转接上次博客:Linux 12:TCP编程
三次挥手,四次握手
应答确认,超时重传,滑动窗口,流量控制
| 滑动窗口 |
TCP协议是利用滑动窗口实现流量控制的。一般来说,我们总是希望数据传输得更快一些,不会一次只发一个字节。但是如果发送方把数据发得过快,接受方就可能来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。
在TCP的报头中有一个字段叫做接收通告窗口,这个字段由接收端填充,是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。所以发送端就会有一个发送窗口,这个发送窗口的大小是由接收端填充的接收通告窗口的大小决定的,并且窗口的位置会随着发送端数据的发送和接收到接收端对数据的确认而不断的向右滑动,将之称为滑动窗口。


上图中,TIME_WAIT 状态一般情况下是主动关闭的一端才会出现的状态。该状态出现后,会维持一段长为 2MSL(Maximum Segment Life)的时间,才能完全关闭。MSL 是 TCP 报文段在网络中的最大生存时间,标准文档 RFC1122 的建议值是2min。
状态转移图解释



TIME_WAIT 状态存在的原因有两点:
◼ 可靠的终止 TCP 连接。
◼ 保证让迟来的 TCP 报文有足够的时间被识别并被丢弃。
UDP提供的是面向无连接、不可靠的、数据报服务。

慢启动和拥塞避免
所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制是一个全局性的过程,涉及到所有主机,所有路由器,以及与降低网络传输性能有关的所有因素。
对整个网络资源进行合理利用
几种拥塞控制的方法:
◼ 慢启动
◼ 拥塞避免“加法增大”
◼ 快速重传
◼ 快速恢复


udpser.c
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 #include<sys/socket.h>
6 #include<pthread.h>
7 #include<netinet/in.h>
8 #include<arpa/inet.h>
9
10 int main()
11 {
12 int sockfd=socket(AF_INET,SOCK_DGRAM,0);
13 if(sockfd==-1)
14 {
15 exit(1);
16 }
17 struct sockaddr_in saddr,caddr;
18 memset(&saddr,0,sizeof(saddr));
19 saddr.sin_family=AF_INET;
20 saddr.sin_port=htons(6000);
21 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
22
23 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
24 if(res==-1)
25 {
26 printf("bind err\n");
27 exit(1);
28 }
29
30 //接收多个数据端数据
31 while(1)
32 {
33 char buff[128]={0};
34 int len=sizeof(caddr);
35 int num=recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
36 printf("buff(%d,ip=%s)=%s\n",num,inet_ntoa(caddr.sin_addr),buff);
37 sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
38 }
39 }
udpcli.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<unistd.h>
5 #include<arpa/inet.h>
6 #include<netinet/in.h>
7 #include<sys/socket.h>
8
9 int main()
10 {
11 int sockfd=socket(AF_INET,SOCK_DGRAM,0);
12 if(sockfd==-1)
13 {
14 exit(1);
15 }
16
17 struct sockaddr_in saddr;
18 memset(&saddr,0,sizeof(saddr));
19 saddr.sin_family=AF_INET;
20 saddr.sin_port=htons(6000);
21 saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
22
23 while(1)
24 {
25 printf("input\n");
26 char buff[128]={0};
27 fgets(buff,128,stdin);
28
29 if(strncmp(buff,"end",3)==0)
30 {
31 break;
32 }
33 sendto(sockfd,buff,strlen(buff)-1,0,(struct sockaddr*)&saddr,sizeof(saddr));
34 memset(buff,0,128);
35 int len=sizeof(saddr);
36 recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
37 printf("buff=%s\n",buff);
38 }
39 exit(0);
40 }
运行结果

可以和多个客户端同时连接
协议不同,端口号可以同时共用
UDP会独立发送报文,而且服务器端和客户端没有建立连接,udp发送报文每次要填入目的地的客户和端口,不能确保两次目的地相同,所以不能合并两次报文,udp允许丢包,TCP是一对一建立连接,可靠,但是系统开销较大,电话,发邮件等等,udp不可靠,但是传输速度快,开销较小,视频等等,tcp不允许丢包
