找回密码
 立即注册
首页 业界区 安全 网络编程练习题---利用TCP协议完成客户端与服务端点对点 ...

网络编程练习题---利用TCP协议完成客户端与服务端点对点通信

琶轮 昨天 09:36
目录

  • 题目一

    • 解析
    • 代码实现

  • 题目二:

    • 解析
    • 代码实现

      • tcp_client.c
      • tcp_server.c



题目一

设计程序实现解析www.baidu.com的域名,把获取到的百度的IP地址全部输出到终端并验证是否正确。
解析

主机打算响应某个网站的网络请求,但是只知道网站域名是无法通信的,需要对域名进行地址解析,得到网站的公有IP地址,所以Linux系统提供了名称叫做gethostbyname()的函数接口实现该功能,使用规则如下:
1.png

代码实现
  1. /********************************************************************************
  2. *
  3. *        file name:        demo_domain.c
  4. *        author         :  ProgramMonkey_Fly@126.com
  5. *        date         :  2024/06/04
  6. *        function :  
  7. *               设计程序实现解析www.baidu.com的域名,
  8. *               把获取到的百度的IP地址全部输出到终端并验证是否正确。
  9. *         note         :  
  10. *               1.可以通过ping 百度域名,观察返回值的IP地址来验证获取值是否正确
  11. *               2.通过命令行输入不同的域名,来获取不同域名的IP地址
  12. *                 例如:./xxx xxx(有效域名地址)
  13. *   version  :
  14. *
  15. *        CopyRight (c)  2023-2024   ProgramMonkey_Fly@126.com   All Right Reseverd
  16. *
  17. * ******************************************************************************/
  18. /****************************头文件*********************************************/
  19. #include <netdb.h>
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #include <stdlib.h>
  23. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #include
  26. #include <string.h>
  27. int main(int argc, const char *argv[])
  28. {
  29.     //对参数进行错误处理
  30.     if(argc != 2)
  31.     {
  32.         fprintf(stderr, "argc error, errno: %d, %s\n", errno, strerror(errno));
  33.         exit(1);
  34.     }
  35.     //利用gethostbyname函数接口,获取目标域名所包含的信息
  36.     struct hostent *hostent =  gethostbyname(argv[1]);
  37.     //定义一个结构体变量,用于存储IP地址
  38.     struct in_addr ip_hostent;
  39.     //定义一个循环数组下标
  40.     int i = 0;
  41.     //循环将获取得到的hostent结构体中的ip地址转换为点分十进制字符串输出
  42.     while(hostent->h_addr_list[i] != NULL)
  43.     {
  44.         //将获取IP地址进行类型转换,存储在ip_hostent中
  45.         ip_hostent.s_addr = *(uint32_t *)(hostent->h_addr_list[i]);
  46.         //利用函数接口inet_ntoa(),将网络节序类型转换为点分十进制字符串类型并输出
  47.         printf("%s ip :%s\n", argv[1], inet_ntoa(ip_hostent));
  48.         //对数组下标进行偏移
  49.         i++;
  50.     }
  51.     return 0;
  52. }
复制代码
题目二:

利用TCP协议,设计两个程序,一个作为客户端,先发送连接申请给服务端,发送消息给服务端;另一个作为服务端,接受客户端申请,并接受客户端发送的消息。
解析


  • listen函数不具有阻塞特性,因为listen只是相当于把socket的属性更改为被动连接,可以接收其他进程的连接,设置好后便会返回,监听的实质有操作系统完成。
  • 调用listen函数需要设置监听队列的最大容量,该监听队列容量不是指的是服务端能连接客户端的数量。
  • accept函数具有阻塞特性,调用一次accept只能接收一个客户端申请请求,并且会生成返回一个新的、专属于当前连接的客户端的文件描述符,该描述符一定要存储起来,方便服务端后续与客户端点对点通信。
代码实现

tcp_client.c
  1. /********************************************************************************
  2. *
  3. *        file name:        tcp_client.c
  4. *        author         :  ProgramMonkey_Fly@126.com
  5. *        date         :  2024/06/05
  6. *        function :  该案例是掌握TCP协议通信方式,该代码文件将实现客户端发送信息给服务端的功能。
  7. *         note         :  
  8. *                                1. 需要注意的是connect是非阻塞特性,所以一定要接收返回值进行判断,
  9. *                                   否则会出现没有连接成功,却进入发送的错误状态。
  10. *                                2. 由于该函数部分参数由命令行传入,所以在执行文件时要加上参数
  11. *                                   例如:./xxx  xxx(端口号) xxx.xxx.xxx.xxx(服务端IP地址--点分十进制)
  12. *   version  :
  13. *
  14. *        CopyRight (c)  2023-2024   ProgramMonkey_Fly@126.com   All Right Reseverd
  15. *
  16. * ******************************************************************************/
  17. /****************************头文件*********************************************/
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <netinet/tcp.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include
  26. #include <unistd.h>
  27. int main(int argc,const char *argv[])
  28. {
  29.         //判断命令行参数
  30.         if(argc != 3)
  31.         {
  32.                 fprintf(stderr, "argc error,errno:%d,%s\n",errno,strerror(errno));
  33.                 exit(1);
  34.         }
  35.         //创建TCP的套接字文件
  36.         int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
  37.         if(tcp_socket == -1)
  38.         {
  39.                 fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
  40.                 exit(2);
  41.         }
  42.         //绑定本地信息--如果只打算实习发送功能,该步骤也可以省略
  43.         struct sockaddr_in  host_addr;
  44.         host_addr.sin_family                 = AF_INET;                                                 //协议族,为固定宏
  45.         host_addr.sin_port                   = htons(atoi(argv[1]));                        //想要接收信息进程的端口号
  46.         host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);                        //本地地址,填写该宏定义代表任意网口都可以接收值
  47.         bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));
  48.         //向目标主机发送消息,需要设置目标端口和目标地址
  49.         char buf[128] = {0};
  50.         struct sockaddr_in  dest_addr;
  51.         socklen_t flag_dest = sizeof(dest_addr);
  52.         dest_addr.sin_family                 = AF_INET;                                                 //协议族,是固定的
  53.         dest_addr.sin_port                   = htons(atoi(argv[1]));                        //服务器运行进程的端口号,必须转换为网络字节序
  54.         dest_addr.sin_addr.s_addr   = inet_addr(argv[2]);                        //要发送对象的IP地址,必须转换为点分十进制字符串形式
  55.         //使用connect函数接口向服务器发起连接申请
  56.         int flag_connect = connect(tcp_socket, (struct sockaddr *)&dest_addr, flag_dest);
  57.         if(flag_connect == -1)
  58.         {
  59.                 fprintf(stderr, "connect socket error,errno:%d,%s\n",errno,strerror(errno));
  60.                 exit(3);
  61.         }
  62.         //循环向服务器发送消息
  63.         while(1)
  64.         {
  65.                 //从键盘获取信息
  66.                 scanf("%s", buf);
  67.                 write(tcp_socket, buf, strlen(buf));
  68.                 bzero(buf, sizeof(buf));
  69.         }
  70.         return 0;
  71. }
复制代码
tcp_server.c
  1. /********************************************************************************
  2. *
  3. *        file name:        tcp_server.c
  4. *        author         :  ProgramMonkey_Fly@126.com
  5. *        date         :  2024/06/17
  6. *        function :  该案例是掌握进行模块化编程思想,以及封装函数接口流程
  7. *         note         :  
  8. *                                1. 需要注意的是listen是非阻塞特性,accept才具有阻塞特性
  9. *                                2. accpet在成功连接客户端后,会重新创建一个新的、专属于连接客户端的
  10. *                                   套接字文件描述符,方便服务端与客户端点对点通信
  11. *                                3. 由于该函数部分参数由命令行传入,所以在执行文件时要加上参数
  12. *                                   例如:./xxx  xxx(端口号)
  13. *   version  :
  14. *
  15. *        CopyRight (c)  2023-2024   ProgramMonkey_Fly@126.com   All Right Reseverd
  16. *
  17. * ******************************************************************************/
  18. /****************************头文件*********************************************/
  19. #include <sys/socket.h>
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #include <netinet/ip.h>
  23. #include
  24. #include <netinet/in.h>
  25. #include <netinet/udp.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/types.h>
  29. #include <unistd.h>
  30. int main(int argc, char const *argv[])
  31. {
  32.         //对命令行传入参数数量进行判断
  33.         if(argc != 2)
  34.         {
  35.                 fprintf(stderr, "argc error,errno:%d,%s\n",errno,strerror(errno));
  36.                 exit(1);
  37.         }
  38.         //1.创建TCP套接字
  39.         int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
  40.         if (tcp_socket == -1)
  41.         {
  42.                 fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
  43.                 exit(2);
  44.         }
  45.         //2.绑定自身的IP地址和端口,由于该处服务器功能是接受信息,所以一定要绑定自身信息
  46.         struct sockaddr_in  host_addr;
  47.         host_addr.sin_family                 = AF_INET;                                                 //协议族,是固定的
  48.         host_addr.sin_port                   = htons(atoi(argv[1]));                        //目标端口,必须转换为网络字节序
  49.         host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);                    //目标地址  INADDR_ANY 这个宏是一个整数,所以需要使用htonl转换为网络字节序
  50.         bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));
  51.         //3.设置监听,且监听队列最大容量设置为5
  52.         listen(tcp_socket,5);
  53.         //4.等待接受客户端的连接请求
  54.         struct sockaddr_in  client;
  55.         socklen_t client_len = sizeof(client);
  56.         //调用accept函数接口后,一定要接收其返回值,因为该返回值为accept创建的新的、专属于连接客户端的套接字文件描述符
  57.         int connect_fd = accept(tcp_socket,(struct sockaddr *)&client,&client_len); //会阻塞
  58.         char buf[128] = {0};
  59.         //5.说明双方建立连接,此时可以接收数据
  60.         while(1)
  61.         {
  62.                 read(connect_fd,buf,sizeof(buf));
  63.                 printf("recv from [%s],data is = %s\n", inet_ntoa(client.sin_addr) ,buf);
  64.                 bzero(buf,sizeof(buf));
  65.         }
  66.         return 0;
  67. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册