TCP/IP的TCP socket通信过程

本文链接:https://blog.csdn.net/upupday19/article/details/78916142

传统的TCP/IP通信过程依赖于socket,位于应用层和传输层之间,使得应用程序可以进行通信。相当于港口城市的码头,使得城市之间可以进行货物流通。服务器和客户端各有不同的通信流程。

一、服务器

    1、建立连接阶段

  • 调用socket(),分配文件描述符,即监听套接字
  • 调用bind(),将套接字与本地IP地址和端口绑定
  • 调用listen(),监听特定端口,socket()创建的套接字是主动的,调用listen使得该文件描述符为监听套接字,变主动为被动
  • 调用accept(),阻塞等待客户端连接

    2、数据交互阶段

  • 调用read(),阻塞等待客户端发送的请求,收到请求后从read()返回,处理客户端请求
  • 调用write(),将处理结果发送给客户端,然后继续调用read()等待客户端请求

    3、关闭连接

  • 当read()返回0的时候,说明客户端发来了FIN数据包,即关闭连接,也会调用close()关闭连接套接字和监听套接字

二、客户端

    1、建立连接阶段

  • 调用socket(),分配文件描述符
  • 调用connect(),向服务器发送建立连接请求

    2、数据交互阶段

  • 调用write(),将请求发送给服务器
  • 调用read(),阻塞等待服务器应答

    3、关闭连接

  • 当没有数据发送的时候,调用close()关闭连接套接字,即关闭连接,向服务器发送FIN数据报

三、TCP通信过程


四、C语言代码

服务器端


   
   
  1. /* File name: server.c*/
  2. //服务器端
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<errno.h>
  7. #include<unistd.h>
  8. #include<sys/types.h>
  9. #include<sys/socket.h>
  10. #include<netinet/in.h>
  11. #define MAXLINE 4096
  12. #define PORT 8000
  13. int main( void){
  14. //定义服务器监听套接字和连接套接字
  15. int listen_fd = -1, connect_fd = -1; //初始化为-1
  16. struct sockaddr_in servaddr; //定义服务器对应的套接字地址
  17. //服务器接收和发送缓冲区
  18. char sendbuf[MAXLINE], recbuf[MAXLINE];
  19. //初始化套接字地址结构体
  20. memset(&servaddr, 0, sizeof(servaddr));
  21. servaddr.sin_family = AF_INET; //IPv4
  22. servaddr.sin_port = htons(PORT); //设置监听端口
  23. servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //表示接收任意IP的连接请求
  24. //创建套接字
  25. if((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
  26. //如果创建套接字失败,返回错误信息
  27. //strerror(int errnum)获取错误的描述字符串
  28. printf( "create socket error: %s(error: %d)\n", strerror(errno), errno);
  29. exit( 0);
  30. }
  31. //绑定套接字和本地IP地址和端口
  32. if(bind(listen_fd, ( struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
  33. //绑定出现错误
  34. printf( "bind socket error: %s(error: %d)\n", strerror(errno), errno);
  35. exit( 0);
  36. }
  37. //使得listen_fd变成监听描述符
  38. if(listen(listen_fd, 10) == -1){
  39. printf( "listen socket error: %s(error: %d)\n", strerror(errno), errno);
  40. exit( 0);
  41. }
  42. //accept阻塞等待客户端请求
  43. printf( "等待客户端发起连接\n");
  44. while( 1){
  45. if((connect_fd = accept(listen_fd, ( struct sockaddr*) NULL, NULL)) == -1){
  46. printf( "accept socket error: %s(error: %d)\n", strerror(errno), errno);
  47. continue;
  48. }
  49. //可以一直保持连接
  50. while( 1){
  51. //读取客户端发来的信息
  52. ssize_t len = read(connect_fd, recbuf, sizeof(recbuf));
  53. if(len < 0){
  54. if(errno == EINTR){
  55. continue;
  56. }
  57. exit( 0);
  58. }
  59. printf( "接收客户端的请求:%s\n", recbuf);
  60. //向客户端发送信息
  61. printf( "回复客户端信息:");
  62. fgets(sendbuf, sizeof(sendbuf), stdin);
  63. write(connect_fd, sendbuf, sizeof(sendbuf));
  64. }
  65. //关闭连接套接字
  66. close(connect_fd);
  67. }
  68. //关闭监听套接字
  69. close(listen_fd);
  70. }
客户端

   
   
  1. /* File name: client.c */
  2. //客户端
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<errno.h>
  7. #include<unistd.h>
  8. #include<sys/types.h>
  9. #include<sys/socket.h>
  10. #include<arpa/inet.h>
  11. #define MAXLINE 4096
  12. #define PORT 8000
  13. int main( void){
  14. //定义客户端套接字
  15. int sockfd = -1;
  16. //定义想连接的服务器的套接字地址
  17. struct sockaddr_in servaddr;
  18. //发送和接收数据的缓冲区
  19. char sendbuf[MAXLINE], recbuf[MAXLINE];
  20. //初始化服务器套接字地址
  21. memset(&servaddr, 0, sizeof(servaddr));
  22. servaddr.sin_family = AF_INET; //IPv4
  23. servaddr.sin_port = htons(PORT); //想连接的服务器的端口
  24. servaddr.sin_addr.s_addr = inet_addr( "127.0.0.1"); //服务器的IP地址
  25. //创建套接字
  26. if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
  27. printf( "create socket error: %s(error: %d)\n", strerror(errno), errno);
  28. exit( 0);
  29. }
  30. //向服务器发送连接请求
  31. if(connect(sockfd, ( struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
  32. //连接失败
  33. printf( "connect socket error: %s(error: %d)\n", strerror(errno), errno);
  34. exit( 0);
  35. }
  36. while( 1){
  37. //向服务器发送信息
  38. printf( "向服务器发送信息:");
  39. fgets(sendbuf, sizeof(sendbuf), stdin);
  40. write(sockfd, sendbuf, sizeof(sendbuf));
  41. //从服务器接收信息
  42. ssize_t len = read(sockfd, recbuf, sizeof(recbuf));
  43. if(len < 0){
  44. if(errno == EINTR){
  45. continue;
  46. }
  47. exit( 0);
  48. }
  49. printf( "服务器回应:%s\n", recbuf);
  50. }
  51. //关闭套接字
  52. close(sockfd);
  53. }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值