当前位置:   article > 正文

C语言UDP基础CS模型

C语言UDP基础CS模型

CS模型UDP流程:

服务器: socket->bind->recvfrom->sendto->close

客户端: socket->sendto->recvfrom->close

代码说明:

1 未使用更先进的服务器模型,用基础单线程阻塞(recvfrom)作为演示

2 服务器使用while循环接收客户端消息

3 适用于同一网段的不同主机间通信 

4 使用SO_REUSEADDR选项消除了测试环境下服务器短时间内无限重启的顾虑

5 运行路径:客户端发射一条消息->服务器收到消息后回射给客户端一条消息->客户端打印出消息

   完成一次基础通信

6 先运行服务器 再运行客户端

  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <sys/socket.h>
  4. #include <sys/un.h>
  5. #include <arpa/inet.h>
  6. #include <netinet/in.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. // 服务器地址
  10. #define SERVER_IP "192.168.142.132"
  11. // 服务器端口
  12. #define SERVER_PORT 55550
  13. // 服务器代码
  14. int main()
  15. {
  16. int server_sockfd;
  17. struct sockaddr_in server_sockaddr, client_sockaddr;
  18. memset(&server_sockaddr, 0, sizeof(server_sockaddr));
  19. memset(&client_sockaddr, 0, sizeof(client_sockaddr));
  20. socklen_t client_sockaddr_len = sizeof(client_sockaddr);
  21. ssize_t send_bytes, recv_bytes;
  22. char send_buf[1024] = "server say : give me money.";
  23. char recv_buf[1024] = {0};
  24. // 创建一个 ipv4 udp 的socket
  25. server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  26. if (server_sockfd == -1)
  27. {
  28. perror("socket");
  29. return 1;
  30. }
  31. // 启用socket选项,避免测试环境中Address already in use
  32. // 参数1:已创建的socket 参数2:指定级别 SOL_SOCKET表示适用于套接字本身而非特定协议
  33. // 参数3:表示地址及端口可重用 参数4:非0表示启用SO_REUSEADDR 参数5:int的大小4字节
  34. // 参数4 和 参数5 的设计目的主要是考虑到未来接口的兼容性
  35. int optval = 1;
  36. setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
  37. // ipv4主机网络序转换
  38. inet_pton(AF_INET, SERVER_IP, &server_sockaddr.sin_addr.s_addr);
  39. // 端口主机网络序转换
  40. server_sockaddr.sin_port = htons(SERVER_PORT);
  41. // 指定地址族为ipv4
  42. server_sockaddr.sin_family = AF_INET;
  43. // 绑定
  44. if ((bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr))) == -1)
  45. {
  46. perror("bind");
  47. close(server_sockfd);
  48. return 1;
  49. }
  50. // 此时可以通过ss -tuln 命令观察到55550 端口的状态为UNCONN(未连接)
  51. printf("server start...\n");
  52. while (1)
  53. {
  54. // recvfrom函数返回干了3件事
  55. // 1 接收数据存到recv_buf 2 将客户端的地址信息存到client_sockaddr 3更新client_sockaddr_len的实际长度
  56. recv_bytes = recvfrom(server_sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&client_sockaddr, &client_sockaddr_len);
  57. if (recv_bytes == -1)
  58. {
  59. perror("recvfrom");
  60. continue;
  61. }
  62. printf("%s\n", recv_buf);
  63. memset(recv_buf, 0, sizeof(recv_buf));
  64. // udp是无连接的要向哪发送呢?就是recvfrom返回的客户端地址信息client_sockaddr
  65. send_bytes = sendto(server_sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr *)&client_sockaddr, client_sockaddr_len);
  66. if (send_bytes == -1)
  67. {
  68. perror("sendto");
  69. continue;
  70. }
  71. printf("%s\n", send_buf);
  72. }
  73. // 关闭socket,socket是一个fd所以可以用close关闭
  74. if (close(server_sockfd) == -1)
  75. {
  76. perror("close");
  77. return 1;
  78. }
  79. printf("server close...\n");
  80. return 0;
  81. }
  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <sys/socket.h>
  4. #include <sys/un.h>
  5. #include <arpa/inet.h>
  6. #include <netinet/in.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. // 服务器地址
  10. #define SERVER_IP "192.168.142.132"
  11. // 服务器端口
  12. #define SERVER_PORT 55550
  13. // 客户端
  14. int main()
  15. {
  16. int client_sockfd;
  17. struct sockaddr_in server_sockaddr;
  18. memset(&server_sockaddr, 0, sizeof(server_sockaddr));
  19. socklen_t server_sockaddr_len = sizeof(server_sockaddr);
  20. ssize_t send_bytes, recv_bytes;
  21. char send_buf[1024] = "client say : How can I help you today ?";
  22. char recv_buf[1024] = {0};
  23. // 建立一个ipv4 udp 的套接字用于客户端
  24. client_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  25. if (client_sockfd == -1)
  26. {
  27. perror("socket");
  28. return 1;
  29. }
  30. printf("client start...\n");
  31. // 主机网络序转换ip地址并存入server_sockaddr.sin_addr.s_addr
  32. inet_pton(AF_INET, SERVER_IP, &server_sockaddr.sin_addr.s_addr);
  33. // 主机网络序转换端口并存入server_sockaddr.sin_port
  34. server_sockaddr.sin_port = htons(SERVER_PORT);
  35. // 指定地址族为ipv4
  36. server_sockaddr.sin_family = AF_INET;
  37. // 向服务器发送数据,其中server_sockaddr包含预设的服务器地址信息
  38. send_bytes = sendto(client_sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr *)&server_sockaddr, server_sockaddr_len);
  39. if (send_bytes == -1)
  40. {
  41. perror("sendto");
  42. close(client_sockfd);
  43. return 1;
  44. }
  45. // 打印出来发送内容
  46. printf("%s\n", send_buf);
  47. // 接收服务器处理后的数据,server_sockaddr表示谁给你发的消息,在此案例中与sendto的server_sockaddr内容相同
  48. recv_bytes = recvfrom(client_sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&server_sockaddr, &server_sockaddr_len);
  49. if (recv_bytes == -1)
  50. {
  51. perror("recvfrom");
  52. close(client_sockfd);
  53. return 1;
  54. }
  55. // 打印消息
  56. printf("%s\n", recv_buf);
  57. // 关闭客户端socket
  58. if (close(client_sockfd) == -1)
  59. {
  60. perror("close");
  61. return 1;
  62. }
  63. printf("client close...\n");
  64. return 0;
  65. } // 检查一下客户端

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/335897
推荐阅读
相关标签
  

闽ICP备14008679号