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

本文关键字:连接 程主机 主机 SocketException | 更新日期: 2023-09-27 18:24:19

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

T

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

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

上面的几个问题。

  1. 不要在C#中使用ME,它是thisMe是VB。如果使用C#,上面的代码将不会编译,因为您遗漏了定义为MEUser()类。我不知道你为什么认为你需要它,因为它似乎只包含UserIPUserName。IP是Socket的一部分,所以如果您需要它,就应该使用它:
    IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
    UserName可以成为一个全局字符串变量,而不必是类的一部分
    也许我太挑剔了,但我没有看到在User()对象中需要这样的变量,只是把事情搞砸了,对我来说,试图破译代码
  2. 始终定义您的Socket,连接到它,然后执行.Send()。你错过了点击按钮的前两个步骤——你只需要做.Send()UdpClient不是Socket,我认为最好将其作为Socket,稍后再定义连接类型。我认为你尝试使用你定义为听众的UdpClient来进行.Send()是对的。不要在发送和收听时使用同一个对象!通常情况下,您会这样做,但每个事件都有2个不同的地址和端口
  3. 不要在CreateUDPClient()函数中使用foreach来将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();
}

您可以创建一个套接字并将其添加到其中。Buffer用于告诉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对象。像MSDN上那样使用StateObject类,并将其仅用作侦听器。