【问题标题】:Simple UDP example to send and receive data from same socket从同一个套接字发送和接收数据的简单 UDP 示例
【发布时间】:2013-12-01 01:56:57
【问题描述】:

由于某种原因,我很难从同一个套接字发送和接收数据。无论如何,这是我的客户端代码:

var client = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000); // endpoint where server is listening (testing localy)
client.Connect(ep); 

// send data
client.Send(new byte[] { 1, 2, 3, 4, 5 }, 5);

// then receive data
var receivedData = client.Receive(ref ep);  // Exception: An existing connection was forcibly closed by the remote host

基本上我想创建一个协议,在该协议中我发送一个 udp 数据包,然后我期望得到响应。就像每个请求的 HTTP 协议都有一个响应。 如果服务器位于不同的计算机上,则此代码有效。但是,可能存在服务器和客户端在同一台计算机上的情况。

这里是服务器:

UdpClient udpServer = new UdpClient(UDP_LISTEN_PORT);

while (true)
{
    var groupEP = new IPEndPoint(IPAddress.Any, 11000); // listen on any port
    var data = udpServer.Receive(ref groupEP);
    udpServer.Send(new byte[] { 1 }, 1); // if data is received reply letting the client know that we got his data          
}

编辑

我不能使用 tcp 的原因是因为有时客户端在 NAT(路由器)后面,而且 UDP 打洞比 TCP 更简单。


解决办法:

感谢 markmnl 的回答,这是我的代码:

服务器:

UdpClient udpServer = new UdpClient(11000);

while (true)
{
    var remoteEP = new IPEndPoint(IPAddress.Any, 11000); 
    var data = udpServer.Receive(ref remoteEP); // listen on port 11000
    Console.Write("receive data from " + remoteEP.ToString());
    udpServer.Send(new byte[] { 1 }, 1, remoteEP); // reply back
}

客户端代码:

var client = new UdpClient();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11000); // endpoint where server is listening
client.Connect(ep);

// send data
client.Send(new byte[] { 1, 2, 3, 4, 5 }, 5);

// then receive data
var receivedData = client.Receive(ref ep);

Console.Write("receive data from " + ep.ToString());

Console.Read();

【问题讨论】:

    标签: c# udp


    【解决方案1】:

    (我假设您知道使用 UDP(用户数据报协议)并不能保证交付、检查重复和拥塞控制,并且只会回答您的问题)。

    在你的服务器中这一行:

    var data = udpServer.Receive(ref groupEP);
    

    将 groupEP 从您所拥有的地址重新分配到您收到某些东西的地址。

    这一行:

    udpServer.Send(new byte[] { 1 }, 1); 
    

    由于您没有指定将数据发送给谁,因此无法正常工作。 (它适用于您的客户端,因为您调用了 connect,这意味着 send 将始终发送到您连接的端点,当然我们不希望在服务器上这样做,因为我们可能有很多客户端)。我会:

    UdpClient udpServer = new UdpClient(UDP_LISTEN_PORT);
    
    while (true)
    {
        var remoteEP = new IPEndPoint(IPAddress.Any, 11000);
        var data = udpServer.Receive(ref remoteEP);
        udpServer.Send(new byte[] { 1 }, 1, remoteEP); // if data is received reply letting the client know that we got his data          
    }
    

    此外,如果您在同一台机器上拥有服务器和客户端,则应该将它们放在不同的端口上。

    【讨论】:

    • 你能在最后一句话的基础上扩展一下吗?
    • 如果您尝试将套接字绑定到已在使用的端口,您将获得地址已在使用中的异常。但是我看到您没有在客户端中为您的 UdpClient 指定端口,所以不用担心,您已经在使用不同的端口。
    • 使用Using (var udpServer = new UdpClient(UDP_LISTEN_PORT)) { }
    • @ArteS 如果您打算特别频繁地再次使用UdpClient,我不会使用using - 每次都处理和重新创建会很浪费。所以很遗憾不能使用usings 有用的糖来为您处理,必须自己处理。
    • 呃,这不是 UDP 你知道的,那是 UDP 之上的协议。我碰巧很清楚,我在 UDP 之上编写了协议以实现可靠性..
    【解决方案2】:

    我会尽量保持简短,几个月前我为我尝试构建的游戏完成了this,它执行类似于 TCP 的 UDP“客户端-服务器”连接,您可以发送(消息)(消息+对象)使用这个。我已经用它做了一些测试,它工作得很好,如果需要,请随时修改它。

    【讨论】:

    • 截至 2021 年 1 月 20 日的断开链接
    【解决方案3】:

    这是我定义远程和本地端口的解决方案,然后将接收到的数据写入文件,将其全部放入您选择的具有正确导入的类中

        static UdpClient sendClient = new UdpClient();
        static int localPort = 49999;
        static int remotePort = 49000;
        static IPEndPoint localEP = new IPEndPoint(IPAddress.Any, localPort);
        static IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), remotePort);
        static string logPath = System.AppDomain.CurrentDomain.BaseDirectory + "/recvd.txt";
        static System.IO.StreamWriter fw = new System.IO.StreamWriter(logPath, true);
    
    
        private static void initStuff()
        {
          
            fw.AutoFlush = true;
            sendClient.ExclusiveAddressUse = false;
            sendClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            sendClient.Client.Bind(localEP);
            sendClient.BeginReceive(DataReceived, sendClient);
        }
    
        private static void DataReceived(IAsyncResult ar)
        {
            UdpClient c = (UdpClient)ar.AsyncState;
            IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            Byte[] receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
            fw.WriteLine(DateTime.Now.ToString("HH:mm:ss.ff tt") +  " (" + receivedBytes.Length + " bytes)");
    
            c.BeginReceive(DataReceived, ar.AsyncState);
        }
    
    
        static void Main(string[] args)
        {
            initStuff();
            byte[] emptyByte = {};
            sendClient.Send(emptyByte, emptyByte.Length, remoteEP);
        }
    

    【讨论】:

    • 谢谢,这很好用!它可用于两种方式:作为 UDP 侦听器和 UDP 发送器。
    猜你喜欢
    • 2013-11-19
    • 2023-04-03
    • 2016-01-23
    • 2015-02-21
    • 1970-01-01
    • 2016-02-19
    • 2010-11-13
    • 2012-10-05
    • 1970-01-01
    相关资源
    最近更新 更多