• 网络-UDP通信


    1. UDP

    全双工通信、面向无连接、不可靠

    UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

    适用场景

    发送小尺寸数据(如对DNS服务器进行IP地址查询时)

    适合于广播/组播式通信中。

    MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议

    2. UDP通信过程

    服务器:

    1. 创建数据报套接字 socket

    2. 填充网络信息

    3. 绑定 bind

    4. 发送接收消息 sendto/recvfrom

    5. 关闭套接字 close

    客户端:

    1. 创建数据报套接字 socket

    2. 指定网络(服务器)信息

    3. 发送接收消息 sendto/recvfrom

    4. 关闭套接字 close

    3.服务器端

    要求:客户端向服务器发送消息,然后服务器向客户端回发一条一样的消息

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #define N 128 // 宏定义数组大小
    12. // 服务器:
    13. // 1. 创建数据报套接字 socket
    14. // 2. 填充网络信息
    15. // 3. 绑定 bind
    16. // 4. 发送接收消息 sendto/recvfrom
    17. // 5. 关闭套接字 close
    18. int main(int argc, char const *argv[])
    19. {
    20. // 1. 创建数据报套接字 socket
    21. int serverfd = socket(AF_INET, SOCK_DGRAM, 0);
    22. if (serverfd < 0)
    23. {
    24. perror("serverfd socket err");
    25. return -1;
    26. }
    27. printf("socket scuess\n");
    28. // 2. 填充网络信息
    29. struct sockaddr_in myaddr; // 服务器结构体变量
    30. myaddr.sin_family = AF_INET; // IPV4协议
    31. // 结构体成员变量是sin_addr ,sin_addr是struct in_addr 结构体类型的,成员变量为 s_addr,
    32. // 网络ip地址需要转成机器识别的类型;
    33. myaddr.sin_addr.s_addr = INADDR_ANY;
    34. // 端口
    35. myaddr.sin_port = htons(atoi(argv[1]));
    36. // 3. 绑定 bind
    37. // 绑定自己的地址
    38. // 需要强转成通用结构体类型的地址
    39. socklen_t addrlen = sizeof(myaddr);
    40. if (bind(serverfd, (struct sockaddr *)&myaddr, addrlen) < 0)
    41. {
    42. perror("bind err");
    43. return -1;
    44. }
    45. printf("bind scuess\n");
    46. // 4. 发送接收消息 sendto/recvfrom
    47. ssize_t len = -1; // 接收recv返回值
    48. char buf[N] = "";
    49. struct sockaddr_in cliaddr; // 存放客户端结构体变量
    50. while (1)
    51. {
    52. // 接收来自客户端的消息
    53. // 清空数组
    54. memset(buf, 0, N);
    55. // recvfrom最后两个参数为发送端的网络地址信息
    56. len = recvfrom(serverfd, buf, N, 0,
    57. (struct sockaddr *)&cliaddr, &addrlen);
    58. if (len < 0)
    59. {
    60. perror("recv err");
    61. break;
    62. }
    63. // 接收到quit时退出
    64. if (buf[strlen(buf) - 1] == '\n')
    65. {
    66. buf[strlen(buf) - 1] = '\0';
    67. }
    68. if (strcmp(buf, "quit") == 0)
    69. {
    70. break;
    71. }
    72. // 服务器获取的ip地址与端口号都是网络字节序,输出的的时候需要转成主机字节序
    73. printf("ip = %s, port = %d\n", inet_ntoa(cliaddr.sin_addr),
    74. ntohs(cliaddr.sin_port));
    75. printf("recv data = %s\n", buf);
    76. // 向客户端回发消息
    77. // sendto最后两个参数为接收端的网络地址信息
    78. len = sendto(serverfd, buf, len, 0,
    79. (struct sockaddr *)&cliaddr, sizeof(cliaddr));
    80. if (len < 0)
    81. {
    82. printf("send error\n");
    83. return -1;
    84. }
    85. }
    86. close(serverfd);
    87. return 0;
    88. }

    4. 客户端

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #define N 128 // 宏定义数组大小
    12. // 客户端:
    13. // 1. 创建数据报套接字 socket
    14. // 2. 指定网络(服务器)信息
    15. // 3. 发送接收消息 sendto/recvfrom
    16. // 4. 关闭套接字 close
    17. int main(int argc, char const *argv[])
    18. {
    19. // 1. 创建数据报套接字 socket
    20. int clientfd = socket(AF_INET, SOCK_DGRAM, 0);
    21. if (clientfd < 0)
    22. {
    23. perror("serverfd socket err");
    24. return -1;
    25. }
    26. // 2. 指定网络(服务器)信息
    27. struct sockaddr_in server_addr; // 服务器结构体变量
    28. server_addr.sin_family = AF_INET; // IPV4协议
    29. // 结构体成员变量是sin_addr ,sin_addr是struct in_addr 结构体类型的,成员变量为 s_addr,
    30. // 网络ip地址需要转成机器识别的类型;
    31. server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    32. // 端口
    33. server_addr.sin_port = htons(atoi(argv[2]));
    34. // 结构体大小
    35. socklen_t addrlen = sizeof(server_addr);
    36. // 3. 发送接收消息 sendto/recvfrom
    37. ssize_t len = -1; // 接收send返回值
    38. char buf[N] = "";
    39. char buff[N] = "";
    40. while (1)
    41. {
    42. // 向服务器端发送消息
    43. // 清空数组
    44. memset(buf, 0, N);
    45. // 从终端读取内容
    46. len = read(1, buf, N);
    47. if (buf[strlen(buf) - 1] == '\n')
    48. {
    49. buf[strlen(buf) - 1] = '\0';
    50. }
    51. // sendto最后两个参数为接收端的网络地址信息
    52. len = sendto(clientfd, buf, len, 0,
    53. (struct sockaddr *)&server_addr, addrlen);
    54. if (len < 0)
    55. {
    56. printf("send error\n");
    57. return -1;
    58. }
    59. if (strcmp(buf, "quit") == 0)
    60. {
    61. break;
    62. }
    63. // 接收服务器端回发的消息
    64. // 清空数组
    65. memset(buf, 0, N);
    66. // recvfrom最后两个参数为发送端的网络地址信息
    67. len = recvfrom(clientfd, buf, N, 0,
    68. (struct sockaddr *)&server_addr, &addrlen);
    69. if (len < 0)
    70. {
    71. perror("recv err");
    72. break;
    73. }
    74. // 格式化输出
    75. printf("recv:%s!!!!\n", buf);
    76. fprintf(stdout, "recv:%s!!!!", buf);
    77. sprintf(buff, "recv:%s!!!!", buf);
    78. printf("%s\n", buff);
    79. }
    80. close(clientfd);
    81. return 0;
    82. }

    5. 运行结果

    服务器端

    客户端

  • 相关阅读:
    用支持向量机进行光学符号识别
    在腾讯云安装docker及zookeeper和dubbo
    Android 基础知识3-4 Activity的声明周期
    语雀服务器P0事故的一些启发
    2流高手速成记(之二):SpringBoot之基础Web开发
    Gradle系列——常用指令,修改gradle源,Wrapper包装器(源于文档7.5版本,SpringBoot使用)day1-2
    几种经典的卷积神经网络
    pytorch DistributedDataParallel 分布式训练踩坑记录
    Docker安装Zookeeper、RocketMQ
    运动装备经营小程序商城效果如何
  • 原文地址:https://blog.csdn.net/weixin_67273669/article/details/140332477