网络编程UDP

来源:互联网 发布:阿里云免费半年邀请码 编辑:程序博客网 时间:2024/06/05 19:21
UDP特点:
1. 无连接,不维护端到端的状态。
2. 基于消息的数据传输服务,TCP是基于流的传输服务,因此TCP会出现粘包问题,而UDP不会有这种问题,认为数据包之间是有边界的。
3. 不可靠,数据包可能会丢失,乱序,重复,缺乏流量控制

4. 一般情况下UDP更加高效


UDP注意点:
1. UDP报文可能丢失,重复
2. UDP报文可能会乱序
3. UDP缺乏流量控制
4. UDP协议数报文截断
5. Recvfrom返回0,不代表连接关闭,因为udp是无连接的
6. ICMP异步错误
7. UDP connect

UDP编程时,需要注意,当服务器没有打开时,打开客户端,因为sendto只是把数据发送到内核缓冲区,即使服务器没有打开,这个步骤可以完成,但是会有ICMP错误,但是当试图从缓冲区读数据时就会阻塞。解决方案是在客户端也适用connect函数,这时异步错误会返回给套接字,但是connect并不意味着三次握手建立了连接,并没有给对方传送数据,当使用了connect后,就可以直接用read,和write读取和发送数据。


服务器端:

#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/wait.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<string.h>#include<signal.h>#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)void echo_srv(int sock){char recvbuf[1024];struct sockaddr_in peeraddr;socklen_t peerlen;while (1){peerlen = sizeof(peeraddr);memset(recvbuf, 0, sizeof(recvbuf));int n=recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*)&peeraddr, &peerlen);if (n == -1){if (errno == EINTR)continue;ERR_EXIT("recvfrom");}else if (n > 0){fputs(recvbuf,stdout);sendto(sock, recvbuf, sizeof(recvbuf),0, (struct sockaddr*)&peeraddr, peerlen);}}close(sock);}int main(void){int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0)ERR_EXIT("socket");struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("bind");echo_srv(sock);return 0;}

客户端:
#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<sys/wait.h>#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<string.h>#include<signal.h>#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)int main(void){int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0)ERR_EXIT("socket");struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");        connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr));char sendbuf[1024];char recvbuf[1024];memset(sendbuf, 0, sizeof(sendbuf));memset(recvbuf, 0, sizeof(recvbuf));while (fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL){//sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&servaddr, sizeof(sockaddr));//recvfrom(sock, recvbuf, sizeof(recvbuf), 0, NULL, NULL);        write(sock,sendbuf,strlen(sendbuf));                read(sock,recvbuf,sizeof(recvbuf));        fputs(recvbuf, stdout);memset(sendbuf, 0, sizeof(sendbuf));memset(recvbuf, 0, sizeof(recvbuf));}close(sock);return 0;}