写了一个UDP服务器,其主要设计思路是为每个客户端单独创建一个套接字,以方便操作和并发。
但是多个套接字端口复用后数据的接收都被第一个套接字收到了,而我想要不同的客户端数据限定于指定的套接字。或者大家有没有其它更好的并发方案。
——
以下是详情的说明:
因为这些套接字都使用同一个端口,所以我开启了端口复用。
_localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.109"), 50001);
_serverSocket = new Socket(_localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);//端口复用
_serverSocket.Bind(_localEndPoint);
客户端知道服务器的ip和端口,主动向其SendTo发送数据,服务器通过ReceiveFrom接收任意客户端发来的数据得到它的EndPoint,然后为其创建单独的套接字。
这套过程类似TCP的Accept,其目的就是为了给每一个客户端创建一个套接字进行独立的收发数据。
private void ProcessReceiveFrom(SocketAsyncEventArgs e)
{
//进行一些判断
......
var socket = new Socket(_localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);//端口复用
socket.Bind(_localEndPoint);
socket.Connect(e.RemoteEndPoint);
//后续会使用如下异步方法进行操作
//socket.ReceiveAsync(receiveEventArgs);
}
通过Connect指定后的套接字就能使用Sned或Receive方法进行操作,我的目的是希望它们能并发,一切看似很美好,实际运行结果:
服务器发送数据,客户端接收成功
客户端发送数据,服务器没能达到预想结果
——
这里服务器没有通过Receive接收到数据,而是在ReceiveFrom接收到数据,这使得我单独创建套接字显得毫无意义,于是我在调试时手动_serverSocket.Close()关闭了用于ReceiveFrom的套接字,Receive变成能正常接收数据了,也就是端口复用后数据的接收没能限定到我想指定的套接字上。
于是我把_serverSocket和客户端socket绑定的端口分开,一个50001,另一个50002来进行区分,在只有一个客户端的情况正常,但客户端一个以上时只有第一个客户端能接收数据,我把这个能接收数据的客户端Close掉后,第二个客户端就能接收数据了,也就是我的这个端口重用设计在底层并不支持(我也不能说每有一个客户端就新用一个端口),我在TCP能这样做,UDP有没有什么其它解决办法。
您好!
在使用UDP协议时,每个客户端可以使用独立的端口与服务器通信。这样您就可以在服务器端创建多个套接字来收发数据,并通过每个客户端的端口区分不同的客户端。
您可以在创建套接字时指定不同的端口,例如:
_serverSocket1 = new Socket(_localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_serverSocket1.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_serverSocket1.Bind(new IPEndPoint(_localEndPoint.Address, 50001));
_serverSocket2 = new Socket(_localEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
_serverSocket2.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_serverSocket2.Bind(new IPEndPoint(_localEndPoint.Address, 50002));
然后在处理数据时,可以使用客户端端口来区分不同的客户端,例如:
private void ProcessReceiveFrom(SocketAsyncEventArgs e)
{
//进行一些判断
......
var clientPort = ((IPEndPoint)e.RemoteEndPoint).Port;
if (clientPort == 50001)
{
_serverSocket1.SendTo(..., e.RemoteEndPoint);
}
else if (clientPort == 50002)
{
_serverSocket2.SendTo(..., e.RemoteEndPoint);
}
}
希望这些信息能帮到您!如果您还有其他问题,欢迎随时继续提问。
你这代码中,所有套接字都使用了同一个端口,并且已经启用了端口复用。意味着所有套接字都将接收到来自这个端口的数据。
为了解决这个问题,可以使用不同的端口为每个套接字分配不同的端口。例如,可以使用端口号范围 50001-50100,为每个套接字分配一个唯一的端口。这样,每个套接字就只会接收其端口号的数据。
还可以使用 TCP 套接字来提供服务器的并发性。TCP 套接字为每个连接分配独立的端口,因此可以为每个连接创建一个独立的套接字,从而实现并发。这可以通过使用 TcpListener 和 TcpClient 类实现。
此外还可以使用多线程或异步编程模型来支持服务器的并发。这样就可以使用单个套接字来接收所有客户端的数据,并使用多个线程或异步任务来处理这些数据。