TCP提供的是面向连接的、可靠的、字节流服务。TCP的服务器端和客户端编程流程如下:
connect()方法一般由客户端程序执行,需要指定连接的服务器端的IP地址和端口。该方法执行后,会进行三次握手,建立连接。
三次握手发生在客户端执行connect()的时候,该方法返回成功,则说明三次握手已经建立。
四次挥手发绳子客户端或服务端执行close()关闭连接的时候,示例图如下:
ser.c
1 #include<stdio.h>
2 #include<string.h>
3 #include<unistd.h>
4 #include<stdlib.h>
5 #include<sys/socket.h>
6 #include<arpa/inet.h>
7 #include<netinet/in.h>
8 #include<pthread.h>
9
10 int socket_init();
11 void *fun(void*arg);
12 int main()
13 {
14 int sockfd=socket_init();
15 if(sockfd==-1)
16 {
17 exit(1);
18 }
19 while(1)
20 {
21 struct sockaddr_in caddr;
22 int len=sizeof(caddr);
23 int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
24 if(c<0)
25 {
26 continue;
27 }
28 printf("accept c=%d,ip=%s,port=%d\n",c,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
29 pthread_t id;//创建线程
30 pthread_create(&id,NULL,fun,(void*)c);
31 }
32 }
33 void* fun(void*arg)
34 {
35 int c=(int)arg;
36 while(1)
37 {
38 char buff[18]={0};
39 int n=recv(c,buff,127,0);//接收数据,无数据阻塞
40 if(n==0)
41 {
42 break;
43 }
44 printf("recv(%d)=%s\n",c,buff);
45 send(c,"ok",2,0);
46 }
47 printf("close\n");
48 close(c);
49 }
50
51 int socket_init()
52 {
53 int sockfd=socket(AF_INET,SOCK_STREAM,0);
54 if(sockfd==-1)
55 {
56 printf("socket err\n");
57 return -1;
58 }
59
60 struct sockaddr_in saddr,caddr;//saddr自己使用端口,caddr对方使用端口
61 memset(&saddr,0,sizeof(saddr));
62 saddr.sin_family=AF_INET;
63 saddr.sin_port=htons(6000);
64 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
65
66 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//给套接字设置绑定端口
67 if(res==-1)
68 {
69 printf("bind err\n");
70 return -1;
71 }
72
73 res=listen(sockfd,5);
74 if(res==-1)
75 {
76 printf("listen err\n");
77 return -1;
78 }
79 return sockfd;
80 }
lic.c
1 #include<stdio.h>
2 #include<string.h>
3 #include<unistd.h>
4 #include<stdlib.h>
5 #include<sys/socket.h>
6 #include<arpa/inet.h>
7 #include<netinet/in.h>
8 #include<pthread.h>
9
10 int main()
11 {
12 int sockfd=socket(AF_INET,SOCK_STREAM,0);
13 if(sockfd==-1)
14 {
15 printf("socket err\n");
16 exit(1);
17 }
18
19 struct sockaddr_in saddr;
20 memset(&saddr,0,sizeof(saddr));
21 saddr.sin_family=AF_INET;
22 saddr.sin_port=htons(6000);
23 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
24
25 //三次握手,connect返回成功,则三次握手完成
26 int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
27 if(res==-1)
28 {
29 printf("connect err\n");
30 exit(1);
31 }
32 while(1)
33 {
34 printf("input\n");
35 char buff[128]={0};
36 fgets(buff,128,stdin);
37 if(strncmp(buff,"end",3)==0)
38 {
39 break;
40 }
41 send(sockfd,buff,strlen(buff)-1,0);
42 memset(buff,0,128);
43 recv(sockfd,buff,127,0);
44 printf("buff=%s\n",buff);
45 }
46 close(sockfd);
47 }
运行结果
netstat -natp
从键盘输入的数据先存入缓冲区,等到recv开始执行时候,才开始接收数据
理论上应该输出5个ok,但是由于时间原因,只接收一个,其他4个存入缓冲区,下一次执行recv时候才会输出
tcp代码图解