TCP的通信流程和socket套接字完成服务端和客户端通信

发布时间 2023-11-04 11:48:19作者: 潘阳399

一、TCP是一个面向连接的安全的流式传输协议,这个协议是传输层协议。

  面向连接:是一个双向连接,通过三次握手建立连接,通过四次挥手断开连接。

  安全:tcp通信的过程中,会对发送的每一数据包都会进行校验,如果发现数据丢失,会自动重传。

  流式传输:发送端和接受端处理数据的速度,数据的量都可以不一致。

二、服务器端通信流程

    1.创建用于监听的套接字,这个套接字是一个文件描述符

1     int lfd = socket();  

  `  2.将得到的监听的文件描述符和本地 的ip端口进行绑定

1    bind();

    3. 设置监听(成功之后开始监听,监听的是客户端的连接)

1    listen();

    4.等待并接受客户端的连接请求,建立新的连接,会得到一个新的文件描述符(通信用的),没有新连接请求就阻塞

1    int cfd = accept();

    5.通信,读写操作默认都是阻塞的

1 //接受数据
2 read(); //recv();
3 
4 //发送数据
5 write(); //send();

    6.断开连接,关闭套接字

close();

    基于tcp的服务端通信代码

 1 //server.c
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <arpa/inet.h>
 7 
 8 int main()
 9 {
10     //1.建立监听的套接字
11     int lfd = socket(AF_INET, SOCK_STREAM, 0);
12     if (lfd == -1)
13     {
14         perror("socket");
15         exit(0);
16     }
17     
18     //设置端口复用,防止占用服务器后断开后还占用这端口,要等
19     int opt = 1;
20     setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
21     struct sockaddr_in addr;
22     
23     //2.将socket()返回值和本地的ip、端口绑定到一起
24     addr.sin_family = AF_INET;
25     addr.sin_port = htons(10000);
26     addr.sin_addr.s_addr = htonl(INADDR_ANY);
27     //INADDR_ANY代表本机的所有ip,假设有三个网卡就有三个IP地址
28     //这个宏可以代表任意一个IP地址
29     //这个宏一般用于本地的绑定操作。
30     //inet_pton(AF_INET, "192.168.0.23", &addr.sin_addr.s_addr);//绑定具体的ip
31     int ret = bind(lfd, (struct sockaddr*)&addr, sizeof(addr));
32     if (ret == -1)
33     {
34         perror("bind");
35         exit(0);
36     }
37 
38     //3.设置监听
39     ret = listen(lfd, 128);
40     if (ret == -1)
41     {
42         perror("listen");
43         exit(0);
44     }
45 
46     //阻塞等待并接受客户端连接
47     struct sockaddr_in  cliaddr;
48     socklen_t clilen = sizeof(cliaddr);
49     int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &clilen);
50     //int cfd = accept()
51     if (cfd == -1)
52     {
53         perror("accept");
54         exit(0);
55     }
56 
57     //打印客户端的地址信息
58     char ip[24] = { 0 };
59     printf("客户端的IP地址:%s,端口:%d\n",
60         inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip)),
61         ntohs(cliaddr.sin_port));
62 
63     //5.和客户端通信
64     while (1)
65     {
66         //接受数据
67         char buf[1024];
68         memset(buf, sizeof(buf), 0);
69         int len = read(cfd, buf, sizeof(buf));
70         if (len > 0)
71         {
72             printf("客户端说:%s\n", buf);
73 
74             //回复客户端
75             memset(buf, sizeof(buf), 0);
76             sprintf(buf, "你好,客户端,我已经收到了你的问候", sizeof(buf));
77             write(cfd, buf, len);
78         }
79         else if (len == 0)
80         {
81             printf("客户端断开了连接。。。\n");
82             break;
83         }
84         else
85         {
86             perror("read");
87             break;
88         }
89     }
90     close(cfd);
91     close(lfd);
92 
93     return 0;
94 }

 

三、客户端的通信流程

  在单线程的情况下客户端通信的文件描述符只有一个,没有监听的文件描述符

  1,创建一个通信的套接字   

1   int cfd = socket();

  2.连接服务器,需要知道服务器绑定的ip和端口    

1 connect();

  3.与服务端通信

1 //接受数据
2 read(); //recv();
3 
4 //发送数据
5 write();//send()

  4.断开连接,关闭文件描述符

close();

  基于tcp通信的客户端

 1 //客户端,client.c
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <arpa/inet.h>
 7 
 8 int main()
 9 {
10     //1.创建通信的套接字
11     int fd = socket(AF_INET, SOCK_STREAM, 0);
12     if (fd == -1)
13     {
14         perror("socket");
15         exit(0);
16     }
17 
18     //2.连接服务器
19     struct sockaddr_in addr;
20     addr.sin_family = AF_INET;
21     addr.sin_port = htons(10000);
22     //addr.sin_addr.s_addr = 
23     inet_pton(AF_INET, "192.168.0.23", &addr.sin_addr.s_addr);
24     int ret =connect(fd, (struct sockaddr*)&addr, sizeof(addr));
25     if (ret == -1)
26     {
27         perror("connect");
28         exit(0);
29     }
30 
31     //3.和服务端通信
32     int  number = 0;
33     while (1)
34     {
35         //发送数据
36         char buf[1024];
37         sprintf(buf, "您好,服务器。。。%d", number++);
38         write(fd, buf, sizeof(buf));
39 
40         //接受数据
41         memset(buf, 0, sizeof(buf));
42         int len = read(fd, buf, sizeof(buf));
43         if (len > 0)
44         {
45             printf("服务器说:%s\n", buf);
46         }
47         else if (len == 0)
48         {
49             printf("服务器断开了连接。。。\n");
50             break;
51         }
52         else
53         {
54             perror("read");
55             break;
56         }
57         sleep(1); //没隔一秒发送一条数据
58     }
59 }

5.最后,先启动服务端,再启动客户端,效果如下

服务端:

 

 客户端: