一个简单的UDP客户端/服务器程序示例,这个简单的例子执行如下步骤的一个回射服务器:
1) 客户端从标准输入读入一行文本,并写给服务端
2) 服务端从网络输入读入一行文本,并回射给客户端
3) 客户端从网络输入读入这行回射的文件,并显示在标准输出上。
下图描述了这个简单的客户/服务器:
UDP回射服务器程序和UDP回射客户端程序见上篇,略
数据报的丢失
我们的UDP客户/服务器例子是不可靠的。如果一个客户数据报丢失(譬如说,被客户主机与服务器主机之间的某个路由器丢弃),客户端将永远阻塞于dg_cli函数中的recvfrom调用,等待一个永远不会到达的服务器应答。类似的,如果客户数据报到达服务器,但是服务器的应答丢失了,客户端也将永远阻塞于recvfrom调用。防止这样永远阻塞的一般方法是给客户的recvfrom调用设置一个超时。
仅仅给recvfrom调用设置超时并不是完整的解决办法。举例来说,如果确实超时了,我们将无从判定超时的原因是我们的数据报没有到达服务器,还是服务器的应答没有回到客户。如果客户的请求是“从账户A往账户B转一定数目的钱”而不是我们的简单回射服务器例子,那么请求丢失和应带丢失是极不相同的。因此需要给UDP增加可靠性
验证接收的响应
知道客户临时端口号的任何进程都可以给客户发送数据报,而且这些数据报会与正常的服务器应答混杂。可以recvform调用以返回数据报发送者的IP地址和端口号,保留来自服务器的应答,忽略任何其他的数据报。
如下所示:
如果服务器是运行在一个只有单个IP地址的主机上,那么这个新版的客户端能正常工作。然后如果客户端是多宿的,客户端就有可能失败。因为recvfrom返回的IP地址,可能不是我们发送指定的IP地址,服务器可能选择从其他的IP作为外出接口。
一个解决办法是:得到recvfrom返回的IP地址后,客户端通过在DNS中查找服务器主机的名字来验证该主机的域名而不是IP地址。另一个解决办法是:服务端为每个IP地址创建一个套接字,用bind捆绑各自的IP到各自的套接字。这样,就会从对应的IP地址上响应客户端。