Socket编程实践(12)

UDP特点

无连接,面向数据报(基于消息,不会粘包)的数据传输服务;

不可靠(可能会丢包,乱序,重复),但因此一般情况下UDP更加高效;

UDP客户/服务器模型

UDP-API使用

#include <sys/types.h>#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);/**实践: 实现一个基于UDP的echo回声server/client**///server端代码void echoServer(int sockfd);int main(){int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1)err_exit("socket error");struct sockaddr_in servAddr;servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY);servAddr.sin_port = htons(8001);if (bind(sockfd, (const struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)err_exit("bind error");echoServer(sockfd);}void echoServer(int sockfd){char buf[BUFSIZ];ssize_t recvBytes = 0;struct sockaddr_in clientAddr;socklen_t addrLen;while (true){memset(buf, 0, sizeof(buf));addrLen = sizeof(clientAddr);memset(&clientAddr, 0, addrLen);recvBytes = recvfrom(sockfd, buf, sizeof(buf), 0,(struct sockaddr *)&clientAddr, &addrLen);//如果recvBytes=0, 并不代表对端连接关闭, 因为UDP是无连接的if (recvBytes < 0){if (errno == EINTR)continue;elseerr_exit("recvfrom error");}cout << buf ;if (sendto(sockfd, buf, recvBytes, 0,(const struct sockaddr *)&clientAddr, addrLen) == -1)err_exit("sendto error");}}/**client端代码**/void echoClient(int sockfd);int main(){int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == -1)err_exit("socket error");echoClient(sockfd);cout << "Client exiting…" << endl;}void echoClient(int sockfd){struct sockaddr_in servAddr;servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");servAddr.sin_port = htons(8001);char buf[BUFSIZ] = {0};while (fgets(buf, sizeof(buf), stdin) != NULL){if (sendto(sockfd, buf, strlen(buf), 0,(const struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)err_exit("sendto error");memset(buf, 0, sizeof(buf));int recvBytes = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);if (recvBytes == -1){if (errno == EINTR)continue;elseerr_exit("recvfrom error");}cout << buf ;memset(buf, 0, sizeof(buf));}}

实践解析:编译运行server,在两个终端里各开一个client与server交互,可以看到server具有并发服务的能力。用<Ctrl+C>关闭server,然后再运行server,此时client还能和server联系上。和前面TCP程序的运行结果相比较,我们可以体会无连接的含义。udp协议来说,server与client的界限更模糊了,只要知道对等方地址(ip和port)都可以主动发数据。

UDP编程注意事项

1.UDP报文可能会丢失(超时重传)、重复、乱序(维护一个序号)

2.UDP缺乏流量控制:当缓冲区写满以后,由于UDP没有流量控制机制,因此会覆盖缓冲区。

3.UDP协议数据报文截断:如果对端发送的UDP数据报大于本地接收缓冲区,报文可能被截断,后面的部分会丢失(而不是像我们想象的下一次能够接收到)。

4.recvfrom可以返回0,并不代表连接关闭,因为UDP是无连接的,代表发送端没有发送任何数据[sendto可以发送数据0包(只含有UDP+IP首部40B)]。

5.ICMP异步错误

观察现象:使用上例,关闭UDP服务端,启动客户端,从键盘接受数据后,再发送数据。如果recvfrom中flags标志为0,且client端没有调用connect的情况下,UDP客户端阻塞在recvfrom位置(见测试代码3);

说明:

1)UDP发送报文的时,只把数据copy到发送缓冲区。在服务器没有起来的情况下,可以发送成功。

2)所谓ICMP异步错误是指:发送的报文的时候,没有错误,接受报文recvfrom的时候,回收到ICMP应答.

3)异步的错误,无法返回未连接的套接字,因此如果上例我们调用了connect,是可以收到该异步ICMP报文的;

6.UDP调用connect

1)UDP调用connet,并没有三次握手,,只是维护了一个(和对等方的)状态信息,因此我们可以看到即使server没有开启,client端的connect依然还可以正确返回的!(测试代码如测试代码2)

2)一但调用connect,发送可以使用send/write,接收可以使用recv/read函数(见测试代码3)

7.UDP外出接口的确定:

离开之后,我想你不要忘记一件事:不要忘记想念我。

Socket编程实践(12)

相关文章:

你感兴趣的文章:

标签云: