SocketException 现有连接被远程主机强制关闭

2024-03-14

我决定研究一下网络消息传递等,我的第一个调用端口是 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

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

T

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


以上几个问题。

  1. 不要使用ME在 C# 中,它是this. Me是VB。如果使用 C#,上面的代码将无法编译,因为您遗漏了User()您定义为的类ME。我不知道为什么你认为你需要它,因为它似乎包含的是UserIP and UserName。 IP 是Socket,所以如果你需要的话,你应该使用它:
    IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
    And UserName可以成为全局字符串变量 - 不必是类的一部分。
    也许我很挑剔,但我没有看到哪里需要在User()对我来说,试图破译代码,只是把事情搞砸了。
  2. 始终定义您的Socket,连接到它,然后做你的.Send()。您错过了按钮点击中的前两个步骤 - 您只需执行您的操作即可.Send(). UdpClient不是一个Socket,我认为最好这样做Socket并稍后定义您的连接类型。我认为你可能是对的,你正在努力做你的事情.Send()使用UdpClient你定义为你的听众。不要使用同一个对象来发送和收听!通常您会这样做,但每个事件都有 2 个不同的地址和端口。
  3. 不要使用foreach在你的CreateUDPClient()函数来获取你的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 https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx

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

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

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

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

您将创建一个套接字并将其添加到其中。缓冲区是一种告诉Receive() or 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像这样的对象。使用StateObject像 MSDN 上的类一样,并且仅将其用作您的侦听器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SocketException 现有连接被远程主机强制关闭 的相关文章

随机推荐