我试图创建一个基于数据报套接字(UDP)的迭代服务器。 它调用连接到第一个客户端,它从第一个recvfrom()调用获得(是的,我知道这不是真正的连接)。 服务此客户端后,我断开UDP套接字(调用与AF_UNSPEC的连接) 然后我调用recvfrom()从下一个客户端获取第一个数据包。
现在的问题是,在循环的第二次迭代中recvfrom()的调用返回0.我的客户端从不发送空数据包,所以可能会发生什么。
这就是我正在做的事情(伪代码):
s = socket(PF_INET, SOCK_DGRAM, 0)
bind(s)
for(;;)
{
recvfrom(s, header, &client_address) // get first packet from client
connect(s,client_address) // connect to this client
serve_client(s);
connect(s, AF_UNSPEC); // disconnect, ready to serve next client
}
编辑:我发现我的客户端中的错误意外地发送了一个空数据包。
现在我的问题是如何使客户端等待服务而不是发送请求(服务器连接到另一个客户端,并且还没有服务任何其他客户端)。
答案 0 :(得分:3)
connect()完全没必要。
调用connect 不会阻止您从其他主机接收数据包,也不会阻止您发送它们。只是不要打扰,这不是真的有用。
更正:是的,显然它确实会阻止您接收来自其他主机的数据包。但是在服务器中执行此操作有点愚蠢,因为当您将connect()编辑为一个时,任何其他客户端都将被锁定。你还需要抓住漂浮在周围的“糠”。在DGRAM套接字上可能存在与connect()相关的一些竞争条件 - 如果您调用connect并且来自其他主机的数据包已经在缓冲区中会发生什么?
此外,0是来自recvfrom()的有效返回值,因为空(无数据)数据包有效且可以存在(实际上,人们经常使用它们)。所以你无法检查某件事是否成功。
很有可能,队列中已经有一个零字节数据包。
应该设计您的协议,以尽量减少错误数据报被误解的可能性;因此我建议你不要使用空数据报,而是使用幻数。
UDP应用程序必须能够识别“箔条”数据包并丢弃它们;他们迟早会出现。
答案 1 :(得分:0)
man connect
:
... If the initiating socket is not connection-mode, then connect() shall set the socket’s peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions. If address is a null address for the protocol, the socket’s peer address shall be reset. ...
答案 2 :(得分:-1)
只是纠正,以防任何人像我一样绊倒这个。要断开connect(),需要将sockaddr的sa_family成员设置为AF_UNSPEC来调用。不只是通过AF_UNSPEC。