需求描述
在设备搜索相关的协议中,UDP被广泛使用,当不知道对方真实IP地址,并且可能两台机器不在同一个子网下,此时就不能直接使用UDP通讯,换句话说,不在相同子网下的两台机器(例如如子网掩码为255.255.255.0,机器A:192.168.11.11,机器B:192.168.1.101),普通的TCP或UDP发送都无法直接到达对方,此时就需要使用UDP的组播模式。接下来就介绍一下在C#中双向组播的实现。
实现代码
Server端
使用UDP组播,并没有服务端和客户端之分,只是在具体应用中,根据应用具体的逻辑,可以将一端的业务逻辑划分为服务端,另一端为客户端。因此,这里Server端的代码如下:
Socket udpServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
udpServerSocket.ReceiveTimeout = 1000;
udpServerSocket.MulticastLoopback = false; //禁用本地组播回环,否则自己发送的组播消息自己也会收到,形成死循环
udpServerSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, //加入组播
new MulticastOption(IPAddress.Parse("224.0.0.22"), IPAddress.Any));
udpServerSocket.Bind(new IPEndPoint(IPAddress.Any, 18000));
byte[] buf = new byte[1024];
while (true)
{
EndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
int recvCount = udpServerSocket.ReceiveFrom(buf, ref endpoint);
Console.WriteLine("Receive {0} bytes from {1}.", recvCount, endpoint);
Console.WriteLine("Receive message: {0}", Encoding.Default.GetString(buf));
var txEdp = new IPEndPoint(IPAddress.Parse("224.0.0.22"), 18000);
udpServerSocket.SendTo(Encoding.Default.GetBytes("Hi!"), txEdp);
Console.WriteLine("Send \"Hi!\" to {0}.", txEdp);
}
Client端
客户端的代码如下:
Socket UDPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UDPSocket.ReceiveTimeout = 10000;
UDPSocket.ExclusiveAddressUse = false;
UDPSocket.MulticastLoopback = false;
UDPSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UDPSocket.Bind(new IPEndPoint(IPAddress.Any, 18000));
UDPSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("224.0.0.22")));
var txEdp = new IPEndPoint(IPAddress.Parse("224.0.0.22"), 18000);
byte[] buf = new byte[1024];
while (true)
{
UDPSocket.SendTo(Encoding.Default.GetBytes("Hello!"), txEdp);
Console.WriteLine("Send \"Hello!\" to {0}.", txEdp);
EndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
int recvCount = UDPSocket.ReceiveFrom(buf, ref endpoint);
Console.WriteLine("Receive {0} bytes from {1}.", recvCount, endpoint);
Console.WriteLine("Receive message: {0}", Encoding.Default.GetString(buf));
Thread.Sleep(1000);
}
运行结果
运行环境:
机器A:Ubuntu虚拟机,桥接网卡,IP地址为静态指定:192.168.11.11
机器B:Windows的机器,与机器A桥接网卡连接同一交换机,IP机制为动态获取:192.168.1.101
以上两个机器,如果是简单的TCP或UDP是无法通讯的,使用以上示例代码运行结果如下:
- 服务端:
Receive 6 bytes from 192.168.1.101:18061.
Receive message: Hello!
Send "Hi!" to 224.0.0.22:18000.
- 客户端:
Send "Hello!" to 224.0.0.61:18000.
Receive 3 bytes from 192.168.11.11:18000.
Receive message: Hi!
......
从运行结果可以看到,机器A和机器B可以正常实现双向通讯。
评论区