2009-05-26 126 views
3

Iam尝试基于数据报套接字(UDP)创建迭代服务器。 它调用连接到它从第一个recvfrom()调用获得的第一个客户端(是的,我知道这不是真正的连接)。 服务此客户端后,我断开UDP套接字(调用连接AF_UNSPEC) 然后我调用recvfrom()从下一个客户端获取第一个数据包。断开并重新连接已连接的数据报套接字

现在的问题是,在循环的第二个迭代recvfrom()的调用返回0.我的客户端永远不会发送空数据包,所以会发生什么。

这是什么做的IAM(伪):

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 
} 

编辑:我找到的bug在我的客户不小心发送一个空包。 现在我的问题是如何让客户端等待得到服务,而不是发送请求到任何地方(服务器连接到另一个客户端,并且不提供任何其他客户端)。

回答

3

SOCK_DGRAM上的connect()实际上完全没有必要。

调用连接不会阻止您接收来自其他主机的数据包,也不会阻止您发送它们。只是不要打扰,这不是真的有帮助。

更正:是的,显然它确实会阻止您接收来自其他主机的数据包。但是在服务器上这样做有点愚蠢,因为在连接()到一个时,其他客户端将被锁定。此外,你仍然需要捕捉浮动的“糠”。在DGRAM套接字上可能存在一些与connect()相关的竞争条件 - 如果调用connect并且来自其他主机的数据包已经在缓冲区中,会发生什么情况?

另外,0是来自recvfrom()的有效返回值,因为空(无数据)数据包是有效的并且可以存在(事实上,人们经常使用它们)。所以你不能检查是否有某种成功的方式。

在所有可能的情况下,零字节数据包已经在队列中。

您的协议应该设计为最大限度地减少错误数据报被误解的机会;因为这个原因,我建议你不要使用空数据报,而是使用一个幻数。

UDP应用程序必须能够识别“chaff”数据包并丢弃它们;他们迟早会出现。

+0

Connect使用send()或recv()函数设置一个内部过滤器,从中接收和发送地址。 recv():“对于SOCK_DGRAM套接字,从连接调用中指定的目标地址的第一个排队数据报中提取数据”。 – codymanix 2009-05-26 16:30:07

+0

你是对的,我的客户正在发送(由于错误)一个空包。现在我有另一个问题。应该在队列中等待获得服务的客户端发送其第一个请求数据包(从未从服务器接收数据包)。然后它尝试接收响应,并且recv返回-1。我如何让客户等待? – codymanix 2009-05-26 21:15:03

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. 
... 
-1

只是一个在校的情况下任何人碰到这个stumbples像我一样。断开connect()需要使用设置为AF_UNSPEC的sockaddr的sa_family成员来调用。不只是通过AF_UNSPEC。