1 UDP通信过程

UDP客户端/服务器(C/S)结构的通信过程如下:
1547561618816.png

2 完整代码示例

server

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <string.h>
  9. #define ERR_EXIT(m)\
  10. do\
  11. {\
  12. perror(m);\
  13. exit(EXIT_FAILURE);\
  14. }while(0)
  15. int main()
  16. {
  17. int sock;
  18. if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)//类型指定为数据报式,用于TCP
  19. {
  20. ERR_EXIT("socket create failed");
  21. }
  22. sockaddr_in servaddr;
  23. servaddr.sin_family = AF_INET;
  24. servaddr.sin_port = htons(5188);
  25. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  26. //bind the socket
  27. if (bind(sock, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  28. {
  29. ERR_EXIT("bind socket failed");
  30. }
  31. //send and receive data
  32. char recvbuf[1024] = {0};
  33. sockaddr_in remoteAddr;
  34. socklen_t remoteLen = sizeof(remoteAddr);
  35. int ret;
  36. while (1)
  37. {
  38. memset(recvbuf, 0, sizeof(recvbuf));
  39. ret = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (sockaddr*)&remoteAddr, &remoteLen);
  40. if (ret == -1)
  41. {
  42. if (errno == EINTR)
  43. continue;//是系统中断导致,则继续
  44. ERR_EXIT("recvfrom failed");
  45. }
  46. else if (ret > 0)
  47. {
  48. printf("%s\r\n", recvbuf);
  49. sendto(sock, recvbuf, ret, 0, (sockaddr*)&remoteAddr, remoteLen);
  50. }
  51. }
  52. close(sock);
  53. }

client

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <string.h>
  9. #include <arpa/inet.h>
  10. #define ERR_EXIT(m)\
  11. do\
  12. {\
  13. perror(m);\
  14. exit(EXIT_FAILURE);\
  15. }while(0)
  16. int main()
  17. {
  18. int sock;
  19. if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)//类型指定为数据报式,用于TCP
  20. {
  21. ERR_EXIT("socket create failed");
  22. }
  23. sockaddr_in servaddr;
  24. servaddr.sin_family = AF_INET;
  25. servaddr.sin_port = htons(5188);
  26. servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");//指定server地址
  27. //send and receive data
  28. char sendbuf[1024] = {0};
  29. int ret;
  30. while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
  31. {
  32. sendto(sock, sendbuf, strlen(sendbuf), 0, (sockaddr*)&servaddr, sizeof(servaddr));
  33. memset(sendbuf, 0, sizeof(sendbuf));
  34. ret = recvfrom(sock, sendbuf, sizeof(sendbuf), 0, NULL, NULL);//从server接收,不需要指定ip
  35. if (ret == -1)
  36. {
  37. if (errno == EINTR)
  38. continue;//是系统中断导致,则继续
  39. ERR_EXIT("recvfrom failed");
  40. }
  41. else if (ret > 0)
  42. {
  43. printf("%s\r\n", sendbuf);
  44. memset(sendbuf, 0, sizeof(sendbuf));
  45. }
  46. }
  47. close(sock);
  48. }

3 UDP的注意点

  • UDP报文可能会丢失或重复
  • UDP报文可能会乱序
  • UDP缺乏流量控制,缓冲区数据可能被覆盖
  • UDP数据报文可能被截断
  • recvfrom返回0,不代表连接关闭,因为UDP是无连接的
  • ICMP异步错误,本端无法知道对端是否开启,发生数据不会出现错误提示(可以先调用一下UDP connect函数,这样发送数据会返回错误)