UDP套接字编程
UDP客户/服务器的套接字函数
recvfrom()函数: 接收数据,类似标准read();
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *from, size_t *addrlen);
flags参数:传输控制标志
1、0:常规操作,所做的操作与read相同
2、MSG_OOB: 指明要读的是带外数据而不是一般数据
3、MSG_PEEK: 可以查看数据而不读出,在接收数据后不会将这些数据丢弃。
注:由于无连接,客户端可能接收到不同服务器发送的消息,所以要对接收到的消息的from进行检查。
sendto()函数
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, structsockaddr * to, int addrlen);
flags参数:传输控制标志
1、0:常规操作,所做的操作与read相同
2、MSG_DONTROUTE: 告诉内核的目的主机在直接连接的本地网络上,不需要查路由表
3、MSG_OOB: 指明发送的是带外数据
注:发送一个长度为0 的数据报是允许的,长度为0的是一个包含头部(IPV4头部20字节,8字节UDP头部和没有数据的IP数据报,这也意味着对于数据报协议,revcfrom返回0字节也是可行的,由于UDP无连接,所以它并不表示对方已关闭连接,与TCP套接字上的read返回0情况不同)
UDP中对数据报的各项处理
1、 数据报的丢失
数据报丢失,客户端可能一直堵塞在recvfrom,解决办法就是设置超时时间。
2、 验证收到的响应
如果服务器仅在一台具有单个IP地址的主机上运行,客户端只用调用
if(len!=sizeofserver)||memcmp((const void*) &server,(const void *)&peer,len)!=0)即可。
服务器多个IP的话一个解决办法:由客户在DNS中查找服务器主机的名字来验证主机的域名而不是IP地址。另一个解决办法:有UDP服务器给服务器主机上配置的每个IP地址创建一个套接字,并捆绑响应的IP地址到此套接字。即用客户请求的服务器IP地址进行响应。
3、 服务器未运行
客户端sendto将产生port unreachable错误,服务器会以端口不可达的ICMP消息响应,但是ICMP错误报文不会返回给客户进程,这种错误报文称为“异步错误”,但是客户端sendto却返回成功,这是由于UDP输出操作返回成功仅仅表示在接口输出队列上为IP数据报流出空间,而ICMP错误知道很晚才返回,所以称为异步错误。
4、UDP的connect函数
1)UDP的connect没有三次握手过程,完全是本地行为;
2)既然有connect,我们就要区分未连接UDP套接字(默认)和已连接UDP套接字(调用connect);
3)已连接套接字和未连接套接字的区别:
· 不用给输出指定目的IP和端口了,即不使用sendto而是改用wirte或send;
· 不必使用recvfrom,而是使用read、recv或recvmsg;
· UDP套接字引发的异步错误将返回给它们的进程。
4)UDP套接字多次调用connect可能出于以下目的:
· 指定新地址的IP地址和端口号(对于TCP,connect只能调用一次)
· 断开套接字:需要再次调用connect,把地址结构上的地址族成员(sin_family或sin6_family)设置成AF_UNSPEC
5)性能
· 未连接套接字两次sendto执行步骤:连接套接字 -> 输出第一个数据报 -> 断开套接字连接 -> 连接套接字 -> 输出第二个数据报 ->断开套接字连接;
· 已连接套接字两次write的步骤:连接套接字 -> 输出第一个数据报 -> 输出第二个数据报
· 从上面可看出未连接的两次发送数据比已经连接的两次发送数据复杂的多,效率自然低得多。