3

我决定看看网络消息传递等,我的第一个呼叫端口是 UDP。

我遇到的问题是当我尝试发送消息时。我正在尝试在特定端口上访问 IP,但应用程序错误并出现错误

“SocketException 一个现有的连接被远程主机强行关闭”。

这是代码。

    User ME = new User();
    UdpClient MyUDPClient;

    private void Form1_Load(object sender, EventArgs e)
    {
        ME.Username = Environment.UserName;
    }

    private void StartUDP_Click(object sender, EventArgs e)
    {
        CreateUDPClient();
    }

    private void CreateUDPClient()
    {
        IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
        foreach (IPAddress ip in host.AddressList)
        {
            if (ip.AddressFamily == AddressFamily.InterNetwork)
            {
                int Port = int.Parse(txt_Port.Text);
                ME.UserIP = new IPEndPoint(ip, Port);
                break;
            }
        }

        MyUDPClient = new UdpClient(ME.UserIP);
        UDPListening();
    }


    public void UDPListening()
    {
        MyUDPClient.BeginReceive(ReceiveMessage, new object());
    }

    private void ReceiveMessage(IAsyncResult IAR)
    {
        byte[] B = MyUDPClient.EndReceive(IAR, ref ME.UserIP);
        ProcessMSG(Encoding.ASCII.GetString(B));
        UDPListening();
    }

    delegate void MessageDelegate(String MSG);

    public void ProcessMSG(String M)
    {
        if (this.lbl_Messages.InvokeRequired)
        {
            MessageDelegate Del = new MessageDelegate(ProcessMSG);
            this.Invoke(Del, M);
        }
        else
        {
            lbl_Messages.Text = M;
        }
    }



   //Send Data to Another version of this program elsewhere.

    private void btn_SendtoTarget_Click(object sender, EventArgs e)
    {
        IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
        byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");

        MyUDPClient.Send(Message, Message.Length, TargetIP);
    }


}

谢谢您的帮助。

不确定这是否有帮助,但...

应用程序在设置为侦听的机器上运行,位于 192.168.0.25:5555

发送正在尝试发送到机器 192.168.0.50:10001

通过进一步阅读,我认为我的具体问题是创建 UDPclient 对象。它被创建,然后在 ip 192.168.0.25:5555 上监听。当我尝试发送消息时,我尝试使用相同的 UDPClient 但发送到新 IP。我觉得这不是正确的程序,因此它试图关闭以前的程序???我相信有人可以证实这一点。所以这向我建议,要拥有有效的 UDP 网络(UP 和 Down),我需要有一个 UDPclient 接收和第二个 UDP 才能发送(这对于我想要命中的每个目标地址都是动态的)。再一次,这都是猜测工作,如果我有这个,我希望有人可以提供一些指示。

4

1 回答 1

3

上面的几个问题。

  1. 不要ME在 C# 中使用,它是this. Me是VB。如果使用 C#,上面的代码将无法编译,因为您遗漏了User()定义为ME. 我不确定你为什么认为你需要它,因为它似乎只包含UserIPand UserName。IP 是 a 的一部分Socket,因此如果您需要它,您应该使用它:
    IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
    并且UserName可以将其设为全局字符串变量 - 不必是类的一部分。
    也许我很挑剔,但我没有看到User()像这样在对象中需要这些变量中的任何一个,而只是把事情搞砸了,对我来说,试图破译代码。
  2. 总是定义你的Socket,连接到它,然后做你的.Send()。您缺少按钮单击的前两个步骤 - 您只需执行.Send(). UdpClient不是 a Socket,我认为最好将其作为 aSocket并稍后定义您的连接类型。我认为你可能是对的,你试图.Send()使用UdpClient你定义为你的听众来做你的事情。不要为您的发送和收听使用相同的对象!通常你会,但每个事件都有 2 个不同的地址和端口。
  3. 不要foreach在你的CreateUDPClient()函数中使用 a 来让你IPAddress分配给你的IPEndPoint. 你已经知道你的IP了。直接赋值。这是浪费处理时间。

    IPAddress ip = IPAddress.Parse("192.168.0.25");
    IPEndPoint endPoint = new IPEndPoint(ip, port);
    

如果你只有主机名,你会这样做:

    string hostName = "MyComputerName";
    int port = 5555;   // or int.Parse(txt_Port.Text);   ???
    IPHostEntry hostEntry = Dns.GetHostAddresses(hostName);
    IPEndPoint endPoint = new IPEndPoint(hostEntry[0], port);

不要使用Dns.GetHostEntry()-- 如果该名称没有反向查找 (PTR) 记录,它将失败。使用Dns.GetHostAddresses(). 而且我不知道为什么你认为你需要循环,除非你有与你提供的相同主机名的 IPv6 地址。如果没有,请使用[0]- 如果不使用 IPv6,它应该是您将使用的第一个也是唯一一个返回的 IP。但同样,由于您已经拥有 IP,只需将其插入 - 无需进行查找。它也可以帮助您消除Dns.GetHostName()- 只需使用192.168.0.25

供您参考,MSDN 在这里有一个同步套接字发送/接收的过程: https ://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx

和异步套接字在这里发送/接收:http:
//msdn.microsoft.com/en-us/library/bew39x2a (v=vs.110).aspx

由于我鄙视仅链接的答案,并且您似乎分别使用Send()和将这两种方法混合EndReceive()到上面的链接中,因此我将努力简洁地描述其内容并帮助修复您的代码:

基本上他们说使用一个StateObject类,而不是MyUDPClient你拥有的全局变量:

public class StateObject
{
    public byte[] buffer = new byte[1024];
    public Socket workSocket; 
    public StringBuilder sb = new StringBuilder();
}

您将创建一个套接字并将其添加到其中。缓冲区作为一种方式来告诉您想要一次从响应中读回的块的大小,Receive()并将用作响应的占位符。EndReceive()sb

看起来你在这里做了很多事情:SendtoTarget_Click从表单和你的听众做一个一次性的测试。您的SendtoTarget按钮执行同步发送,您StartUDP_Click()执行异步接收。

您可以将您的SendtoTarget_Click()事件更改为这个(之前从未定义过您的套接字,并且您必须在发送之前连接到它):

private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
    IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
    byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");

    // Create a UDP socket.  
    Socket sender = new Socket(AddressFamily.InterNetwork,  
        SocketType.Stream, ProtocolType.Udp);  

    try 
    {            
        // Connect to the remote endpoint.
        sender.Connect(TargetIP);  

        // Send message -- already contains the endpoint so no need to 
        // specify again
        sender.Send(Message, 0, Message.Length, SocketFlags.None);

        sender.Close();
    }
    catch (Exception)
    {
       // do something here...
    }
}

对于您的听众,您可以这样做:

private void CreateUDPClient()
{
    IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse("192.168.0.25"), 5555);

    // Create a UDP socket.  
    Socket receiver = new Socket(AddressFamily.InterNetwork,  
            SocketType.Stream, ProtocolType.Udp);  

    try {  

        // Create the state object.  
        StateObject state = new StateObject();  
        state.workSocket = receiver;  

        // Begin receiving the data from the remote device.  
        receiver.BeginReceive(state.buffer, 0, 256, 0,  
            new AsyncCallback(ReceiveMessage), state);  

    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}

和你的函数调用ReceiveMessage(),这样做:

private void ReceiveMessage(IAsyncResult IAR)
{
    string response = String.Empty;
    try {  

        // Retrieve the state object and the client socket   
        // from the asynchronous state object.  
        StateObject state = (StateObject) IAR.AsyncState;  
        Socket client = state.workSocket;  

        // Read data from the remote device.  
        int bytesRead = client.EndReceive(IAR);  

        if (bytesRead > 0) {  
            // There might be more data, so store the data received so far.  
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));  

            // Get the rest of the data.  
            client.BeginReceive(state.buffer, 0, 256, 0,  
                new AsyncCallback(ReceiveCallback), state);  
        } else {  
            // All the data has arrived; put it in response.  
            if (state.sb.Length > 1) {  
                response = state.sb.ToString();  
            }  
            // Signal that all bytes have been received.  
            client.Close();  
        }  
        ProcessMSG(response);
        CreateUDPClient();  // personally, I would re-create than calling BeginReceive directly

    } catch (Exception e) {  
        Console.WriteLine(e.ToString());  
    }  
}

我已尽我所能以一种可行的方式将您的代码与 MSDN 集成。您可能能够再次将该套接字分配给StateObject并调用BeginReceive()它 - 不确定。但是不要UdpClient像那样重复使用对象。使用StateObjectMSDN 上的类并仅将其用作您的听众。

于 2017-05-10T16:08:54.967 回答