首页 文章

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

提问于
浏览
1

我决定看看网络消息等,我的第一个呼叫端口是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网络(UP和Down),我需要有一个UDP客户端接收和第二个UDP能够发送(这是我想要命中的每个目标地址的动态) . 这一切都是猜测工作,如果我有这个,我希望有人可以提供一些指示 .

1 回答

  • 1

    以上几个问题 .

    • 不要在C#中使用 ME ,它是 this . Me 是VB . 如果使用C#,上面的代码将无法编译,因为您省略了您定义为 MEUser() 类 . 我不确定你为什么认为你需要那个,因为它似乎只有 UserIPUserName . IP是 Socket 的一部分,因此如果您需要它,您应该使用它:
      IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
      并且 UserName 可以成为全局字符串变量 - 不必是类的一部分 .
      也许我看到 User() 对象中的任何一个变量都需要这样的东西,并且只是为了解决这些问题,对我来说,试图破译代码 .

    • 始终定义 Socket ,连接到它,然后执行 .Send() . 您错过了按钮点击的前两个步骤 - 您只需执行 .Send() . UdpClient 不是 Socket ,我认为最好将此作为 Socket 并稍后定义您的连接类型 . 我认为你是正确的,你正试图使用你定义为你的听众的 UdpClient 来做你的 . 不要在发送和收听时使用相同的对象!通常你会,但每个事件有2个不同的地址和端口 .

    • 不要在 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();
    }
    

    您将创建一个套接字并将其添加到该套接字 . 缓冲区用于告诉 Receive()EndReceive() 您希望一次从响应中读回的块的大小, sb 将用作响应的占位符 .

    看起来你在这里有很多事情要做:从表格和听众那里进行一次性测试 . 您的 SendtoTarget 按钮执行同步发送, StartUDP_Click() 执行异步接收 .

    您可以将 SendtoTarget_Click() 事件更改为此( never defined your socket, before, and you must connect to it before sending ):

    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 类,并仅将其用作您的侦听器 .

相关问题