• TCP 和UDP通信流程


    TCP 通信流程

            根据上图可以看到,TCP 服务器和客户端通信分为 TCP 服务端和客户端,需要先建立服务 端然后再建立客户端与之连接进行数据交互。
    服务端编程步骤:
            1.使用 socket 创建流式套接字
            2.使用 bind 绑定将服务器绑定到 IP
            3.listen 监听客户端连接
            4.accept 阻塞等待客户端连接
    客户端编程步骤:
            1.使用 socket 创建流式套接字
            2.connect 连接服务器
                    客户端和服务器连接成功后就可以使用下面读写接口操作套接字进行通信
                    读接口:read,recv,recvfrom
                    写接口:write,send,sendto
    连接断开时,直接使用 close 关闭套接字就行了,也可以使用 shutdown 接口关闭。

    UDP 通信流程

            对于 UDP 通信,其实没有服务端和客户端之分的,反而有点类似于进程间通信一样,只需 要向对于的 IP 端去发送消息即可,上图中服务端的 bind 可有可无,它们之间进行通信的流程就是首先使用 socket 去创建一个数据包套接字用于 UDP 通信,然后就使用 sandto 进行发送消息,用 recvfrom 进行读取消息,不能使用 read 和 write 是因为 UDP 通信需要知道对方的 ip 地址的,而 read 和 write 是不具备该参数的。

    TCP 通信程序简单实例

    客户端程序实例:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. void* read_ser(void *pad)
    11. {
    12. pthread_detach(pthread_self()); //线程分离
    13. int soke_c=*(int*)pad;
    14. while (1)
    15. {
    16. char buf[1024] = {0};
    17. int ret = read(soke_c,buf,1024);
    18. if(ret <= 0)
    19. {
    20. perror("read error");
    21. pthread_exit(NULL);
    22. }
    23. printf("字节长度:%d,收到的信息:%s\n",ret,buf);
    24. }
    25. }
    26. int main(int argc, char const *argv[])
    27. {
    28. if(argc != 3) //打开失败
    29. {
    30. printf("bro,you arg not Yes\n");
    31. return -1;
    32. }
    33. /*连接服务器*/
    34. int sock = socket(AF_INET, SOCK_STREAM, 0); //申请一个 IPV4 的流式套接字
    35. if(sock == -1) //申请套接字失败
    36. {
    37. perror("create socket error");
    38. return -1;
    39. }
    40. struct sockaddr_in Saddr; //保存服务器的地址信息的结构体
    41. memset(&Saddr,0,sizeof(struct sockaddr_in)); //清空结构体
    42. Saddr.sin_family = AF_INET; //协议族,AF_INET 表示使用 IPV4 的协议族
    43. Saddr.sin_port = htons(atoi(argv[2])); //端口号,但是要求的是网络字节序
    44. Saddr.sin_addr.s_addr = inet_addr(argv[1]); //32bit 的一个 IP地址
    45. int r = connect(sock,(struct sockaddr*)&Saddr,sizeof(Saddr)); //连接服务器
    46. if(r == -1) //连接失败
    47. {
    48. perror("connect error");
    49. return -1;
    50. }
    51. printf("连接成功,连接的服务器 ip 是%s,端口号是%s\n",argv[1],argv[2]);
    52. pthread_t tid;
    53. pthread_create(&tid, NULL,read_ser, (void*)&sock); //创建线程去接收服务器消息
    54. while(1)
    55. {
    56. char buf[1024] = {0};
    57. memset(buf,0,sizeof(buf));
    58. scanf("%[^\n]",buf);
    59. printf("%ld\n",strlen(buf));
    60. int ret = write(sock,buf,strlen(buf));
    61. if(ret <= 0)
    62. {
    63. perror("sendto error");
    64. return -1;
    65. }
    66. printf("写了多少个字节:%d\n",ret);
    67. }
    68. close(sock); //关闭套接字
    69. return 0;
    70. }

    服务端程序实例:

    1. #include
    2. #include
    3. #include
    4. #include /* See NOTES */
    5. #include
    6. #include
    7. #include //为了使用 IPV4 地址结构体
    8. #include
    9. #include
    10. #include
    11. #include
    12. //线程函数,处理和一个客户端的通信
    13. void *my_func(void *arg)
    14. {
    15. //线程分离
    16. pthread_detach(pthread_self());
    17. int *cp = (int *)arg;
    18. int ret;
    19. while(1)
    20. {
    21. ret = sendto(*cp,"nishiliangzaima?",20,0,NULL,0); //发送消息
    22. if(ret <= 0)
    23. {
    24. perror("sendto error");
    25. free(cp);
    26. pthread_exit(NULL);
    27. }
    28. char buf[1024] = {0};
    29. ret = read(*cp,buf,1024); //读取消息
    30. if(ret <= 0)
    31. {
    32. perror("recv error");
    33. free(cp);
    34. pthread_exit(NULL);
    35. }
    36. printf("recv size:%d,recv data:%s\n",ret,buf);
    37. }
    38. }
    39. //./main ip port
    40. int main(int argc,char *argv[])
    41. {
    42. if(argc != 3)
    43. {
    44. printf("please input ip + port!\n");
    45. return 0;
    46. }
    47. //1.创建一个套接字
    48. int sockfd = socket(AF_INET, SOCK_STREAM,0);
    49. if(-1 == sockfd)
    50. {
    51. perror("create socket failed");
    52. exit(-1);
    53. }
    54. //2.绑定一个通信 IP 地址(作为服务器本身的 IP)
    55. struct sockaddr_in saddr; //保存服务器的地址(IP+port)
    56. memset(&saddr,0,sizeof(struct sockaddr_in)); //清空结构体
    57. saddr.sin_family = AF_INET;
    58. inet_aton(argv[1], &saddr.sin_addr);
    59. saddr.sin_port = htons(atoi(argv[2]));
    60. int ret = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    61. if(ret == -1)
    62. {
    63. perror("bind error");
    64. exit(-1);
    65. }
    66. printf("bind success\n");
    67. //3.开启对一个套接字的监听
    68. listen(sockfd,250);
    69. //4.等待客户端的连接
    70. while(1)
    71. {
    72. struct sockaddr_in caddr; //保存客户端的地址(IP+port)
    73. socklen_t len = sizeof(caddr);
    74. int *confp = (int *)malloc(sizeof(int));
    75. *confp = accept(sockfd,(struct sockaddr *)&caddr,&len);
    76. if(*confp > 0) //客户端连接成功,返回一个连接套接字专门用来和客户端通信
    77. {
    78. //一个客户端连接成功.开一个进程/线程去处理这个连接
    79. printf("client IP:%s,clientPort:%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
    80. pthread_t tid;
    81. pthread_create(&tid,NULL,my_func,(void *)confp); //创建线程去处理和客户端的会话
    82. }
    83. }
    84. //关闭套接字
    85. shutdown(sockfd,SHUT_RDWR);
    86. close(sockfd);
    87. return 0;
    88. }

    UDP 通信程序简单实例

    A 端:客户端

    1. #include
    2. #include
    3. #include /* See NOTES */
    4. #include
    5. #include
    6. #include //为了使用 IPV4 地址结构体
    7. #include
    8. #include
    9. #include
    10. //./main ip port
    11. int main(int argc,char *argv[])
    12. {
    13. if(argc != 3) //判断输入是否正确
    14. {
    15. printf("please input ip + port!\n");
    16. return 0;
    17. }
    18. //1.创建一个 UDP 套接字
    19. int sockfd = socket(AF_INET,SOCK_DGRAM,0); //创建一个 IPV4 的数据报套接字
    20. if(-1 == sockfd)
    21. {
    22. perror("create socket failed");
    23. exit(-1);
    24. }
    25. //直接发送消息(定义一个接收消息的地址)
    26. struct sockaddr_in addr; //保存接收消息的地址(IP+port)
    27. memset(&addr,0,sizeof(struct sockaddr_in)); //清空结构体
    28. addr.sin_family = AF_INET;
    29. inet_aton(argv[1], &addr.sin_addr);
    30. addr.sin_port = htons(atoi(argv[2]));
    31. while(1)
    32. {
    33. char buf[1024] = {0};
    34. fgets(buf,1024,stdin);
    35. int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&addr,sizeof(addr));//发送数据
    36. if(ret <= 0)
    37. {
    38. perror("sendto error");
    39. }
    40. printf("sendto size:%d\n",ret);
    41. //读取服务器的回复消息
    42. memset(buf,0,1024);
    43. struct sockaddr_in src_addr; //保存消息发送方的地址(IP+port)
    44. memset(&src_addr,0,sizeof(struct sockaddr_in)); //清空结构体
    45. socklen_t src_len = sizeof(src_addr); //保存可用大小
    46. ret = recvfrom(sockfd,buf,1024, 0,(struct sockaddr*)&src_addr,&src_len); //接收消息
    47. if(ret <= 0)
    48. {
    49. perror("recvfrom error");
    50. }
    51. printf("sendIP:%s,sendPort:%d\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port));
    52. printf("recv size:%d,recv data:%s\n",ret,buf);
    53. }
    54. //关闭套接字
    55. shutdown(sockfd,SHUT_RDWR);
    56. close(sockfd);
    57. return 0;
    58. }
    B 端:服务端,当然在 UDP 通信中其实没有服务端客户端之言,不过倒是可以对一端进行服务
    器般的操作。
    1. #include
    2. #include
    3. #include /* See NOTES */
    4. #include
    5. #include
    6. #include //为了使用 IPV4 地址结构体
    7. #include
    8. #include
    9. #include
    10. //./main ip port
    11. int main(int argc,char *argv[])
    12. {
    13. if(argc != 3)
    14. {
    15. printf("please input ip + port!\n");
    16. return 0;
    17. }
    18. //1.创建一个 UDP 套接字
    19. int sockfd = socket(AF_INET, SOCK_DGRAM,0); //创建一个 IPV4 的数据报套接字
    20. if(-1 == sockfd)
    21. {
    22. perror("create socket failed");
    23. exit(-1);
    24. }
    25. //2.绑定(可不绑定)
    26. struct sockaddr_in addr; //本地服务器的地址(IP+port)
    27. memset(&addr,0,sizeof(struct sockaddr_in)); //清空结构体
    28. addr.sin_family = AF_INET;
    29. inet_aton(argv[1], &addr.sin_addr);
    30. //addr.sin_addr.s_addr = INADDR_ANY; //让内核自动选择一个网卡
    31. addr.sin_port = htons(atoi(argv[2]));
    32. int ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr)); //绑定一个 IP 和端口号,可不绑定
    33. if(ret == -1)
    34. {
    35. perror("bind error");
    36. exit(-1);
    37. }
    38. printf("bind success\n");
    39. while(1)
    40. {
    41. char buf[1024] = {0};
    42. //读取别人发送的消息
    43. struct sockaddr_in src_addr; //保存消息发送方的地址(IP+port)
    44. memset(&src_addr,0,sizeof(struct sockaddr_in)); //清空结构体
    45. socklen_t src_len = sizeof(src_addr); //保存可用大小
    46. ret = recvfrom(sockfd,buf,1024, 0,(struct sockaddr*)&src_addr,&src_len); //接收消息
    47. if(ret <= 0)
    48. {
    49. perror("recvfrom error");
    50. }
    51. printf("sendIP:%s,sendPort:%d\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port));
    52. printf("recv size:%d,recv data:%s\n",ret,buf);
    53. ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr *)&src_addr,sizeof(src_addr)); //发送消息
    54. if(ret <= 0)
    55. {
    56. perror("sendto error");
    57. }
    58. }
    59. //关闭套接字
    60. shutdown(sockfd,SHUT_RDWR);
    61. close(sockfd);
    62. return 0;
    63. }

  • 相关阅读:
    java计算
    Cpp知识点系列-结构语句
    第十八章 ObjectScript 应用程序中的数值计算
    Curve 块存储应用实践 -- iSCSI
    本地部署腾讯的tmagic-editor低代码
    事件循环机制-Event-Loop
    【电力负荷预测】模拟退火算法结合狮群算法优化Elman神经网络电力负荷预测【含Matlab源码 1454期】
    我想咨询一下Python,请问在哪儿找资源比较好呀?
    使用 Juju/MAAS 部署 OpenStack
    【lombok原理】无聊的周末一个人手写一个lombok
  • 原文地址:https://blog.csdn.net/jiu_yue_ya/article/details/133681549