• 基本的UDP套接字编程


    目录

    一、概述

    二、UDP相关套接字函数介绍 

    1. recvfrom函数和sendto函数

    2. UDP服务端

    3. UDP客户端 

    4. UDP通信结果展示


    一、概述

             在使用TCP编写的应用程序和使用UDP编写的应用程序之间存在一些本质的差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议,非常不同于TCP提供的面向连接的可靠字节流。

            以下给出了典型的UDP客户/服务器的函数调用。客户不与服务器建立连接,而是只管使用sendto函数给服务器发生数据报,其中必须指定目的地(即服务器)的地址作为参数。类似的,服务器不接受来自客户端的连接,而是只管调用recvfrom函数,等待来自某个客户的数据到达。recvfrom将接受与所接受的数据报一道返回客户的协议地址,因此服务器可以把响应的发送给正确的客户。

    二、UDP相关套接字函数介绍 

            在学习UDP通信的相关接口时,部分接口与TCP通信相同,在这里就不过多介绍了;可以去看TCP通信这一章:https://blog.csdn.net/sjsjnsjnn/article/details/127011817?spm=1001.2014.3001.5501 

    1. recvfrom函数和sendto函数

    1. // 读取数据
    2. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
    3. struct sockaddr *src_addr, socklen_t *addrlen);
    4. // 发送数据
    5. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
    6. const struct sockaddr *dest_addr, socklen_t addrlen);

    recvfrom参数说明:

    • sockfd:文件描述符。表示从该文件描述符索引的文件当中读取数据。
    • buf:读取数据的存放位置。
    • len:期望读取数据的字节数。
    • flags:读取的方式。一般设置为0,表示阻塞读取。
    • src_addr:对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
    • addrlen:调用时传入期望读取的src_addr结构体的长度,返回时代表实际读取到的src_addr结构体的长度,这是一个输入输出型参数。

    返回值说明:

    • 读取成功返回实际读取到的字节数,读取失败返回-1,同时错误码会被设置。

            recvfrom的最后两个参数类似于accept的最后两个参数:返回时其中套接字地址结构的内容告诉我们是谁发送了数据报;

    ------------------------------------------------------------------------------------------------------------------------

    sendto参数说明:

    • sockfd:对应操作的文件描述符。表示将数据写入该文件描述符索引的文件当中。
    • buf:待写入数据的存放位置。
    • len:期望写入数据的字节数。
    • flags:写入的方式。一般设置为0,表示阻塞写入。
    • dest_addr:它是指向一个含有数据报接受者的协议地址,及对端网络相关的属性信息,包括协议家族、IP地址、端口号等。
    • addrlen:传入dest_addr结构体的长度。

    返回值说明:

    • 写入成功返回实际写入的字节数,写入失败返回-1,同时错误码会被设置。

            sendto的最后两个参数类似于connect的最后两个参数:调用时其中的套接字地址结构被我们填入数据报将发往这个协议地址;

    --------------------------------------------------------------------------------------------------------------------------

     注意:

            如果recvfrom的src_addr参数是一个空指针,那么相应的长度参数addrlen也必须是一个空指针,表示我们并不关心数据发送者的协议地址;

            由于这两个函数提供的第三个参数也是struct sockaddr*类型的,因此我们在传入结构体地址时需要将struct sockaddr_in*类型进行强转;

    2. UDP服务端

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define NUM 1024
    10. void Usage(std::string proc)
    11. {
    12. std::cout << "Usage: " << proc << " port" << std::endl;
    13. }
    14. // ./udp_server port
    15. int main(int argc, char* argv[])
    16. {
    17. if(argc != 2)
    18. {
    19. Usage(argv[0]);
    20. return -1;
    21. }
    22. uint16_t port = atoi(argv[1]);//定义一个16位的端口号
    23. // 1.创建套接字,打开网络文件
    24. int sock = socket(AF_INET, SOCK_DGRAM, 0);
    25. if(sock < 0)
    26. {
    27. std::cerr << "socket create error" << errno << std::endl;
    28. return 1;
    29. }
    30. // 2.给该服务器绑定端口号和ip(特殊处理)
    31. struct sockaddr_in local;
    32. local.sin_family = AF_INET;
    33. local.sin_port = htons(port);
    34. local.sin_addr.s_addr = INADDR_ANY;
    35. if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
    36. {
    37. std::cerr << "bind error" << errno << std::endl;
    38. return 2;
    39. }
    40. // 3.提供服务
    41. bool quit = false;
    42. char buffer [NUM];
    43. while(!quit)
    44. {
    45. struct sockaddr_in peer;//客户端的服务
    46. socklen_t len = sizeof(peer);
    47. ssize_t cnt = recvfrom(sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);//读取客户端发来的消息
    48. if(cnt > 0)
    49. {
    50. buffer[cnt] = 0;
    51. FILE* fp = popen(buffer, "r");
    52. std::string echo_hello;
    53. char line[1024] = {0};
    54. while(fgets(line, sizeof(line), fp) != NULL)
    55. {
    56. echo_hello += line;
    57. }
    58. pclose(fp);
    59. std::cout << "client# " << buffer << std::endl;
    60. //echo_hello += "...";
    61. sendto(sock, echo_hello.c_str(), echo_hello.size(), 0, (struct sockaddr*)&peer, len);//给客户端一个响应
    62. }
    63. else
    64. {
    65. std::cout << "recvfrom false" << std::endl;
    66. }
    67. }
    68. return 0;
    69. }

    代码详解如下:

    3. UDP客户端 

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void Usage(std::string proc)
    10. {
    11. std::cout << "Usage: \n\t" << proc << " server_ip server_port" << std::endl;
    12. }
    13. int main(int agrc, char* argv[])
    14. {
    15. if(agrc != 3)
    16. {
    17. Usage(argv[0]);
    18. return 0;
    19. }
    20. // 1.创建套接字,打开网络文件
    21. int sock = socket(AF_INET, SOCK_DGRAM, 0);
    22. if(sock < 0)
    23. {
    24. std::cerr << "socket error: " << errno << std::endl;
    25. return 1;
    26. }
    27. /*
    28. 客户端需要显示的bind吗?(绑定端口号)
    29. a.首先,客户端必须要有ip和port
    30. b.但是,客户端不需要显示的bind!一旦显示bind,就必须明确client要和哪一个port关联
    31. client指明的端口号,在client端一定会有吗??
    32. 不,有可能被占用,被占用导致client无法使用
    33. server要的是port必须明确,而且不变,但client只要有就行!
    34. 一般是由操作系统自动给你bind()
    35. 就是client正常发送数据的时候,操作系统会自动给你bind,采用的是随机端口的方式!
    36. */
    37. struct sockaddr_in server;
    38. server.sin_family = AF_INET;
    39. server.sin_port = htons(atoi(argv[2]));
    40. server.sin_addr.s_addr = inet_addr(argv[1]);
    41. // 2.使用服务
    42. while(1)
    43. {
    44. std::cout << "MyShell $ ";
    45. char line[1024];
    46. fgets(line, sizeof(line), stdin);
    47. // b.你要发给谁??
    48. sendto(sock, line, strlen(line), 0, (struct sockaddr*)&server, sizeof(server));
    49. struct sockaddr_in tmp;
    50. socklen_t len = sizeof(tmp);
    51. char buffer[1024];
    52. ssize_t cnt = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&tmp, &len);
    53. if(cnt > 0)
    54. {
    55. buffer[cnt] = 0;
    56. std::cout << buffer << std::endl;
    57. }
    58. else
    59. {
    60. std::cout << "recvfrom false" << std::endl;
    61. }
    62. }
    63. return 0;
    64. }

    代码详解如下:

    4. UDP通信结果展示

     

  • 相关阅读:
    建议收藏,PMP应战篇(2)之易混淆知识点
    Linxu 查看磁盘空间命令
    力扣:103. 二叉树的锯齿形层序遍历(Python3)
    MySQL事务还没提交,Canal就能读到消息了?
    麻了,3个offer不知道选哪个?
    Python爬虫之入门保姆级教程
    网络安全(黑客)—2024自学
    一站式在线订货功能详解,B2B电子商务交易平台高效解决企业订单管理痛点
    八大排序算法
    怎么把录音转文字?这些方法值得收藏
  • 原文地址:https://blog.csdn.net/sjsjnsjnn/article/details/127067140