Table of contents
1. Characteristics of TCP protocol
3. Confirmation response mechanism
4. Timeout retransmission mechanism
(1) TCP congestion control method
Second, establish a connection - three-way handshake
3. Disconnect - wave four times
1. Initial TCP
1. Characteristics of TCP protocol
(1) TCP Yes 面向连接的运输层协议
. Before using the TCP protocol, the application must first establish a TCP connection. After the data is transferred, the established TCP connection must be released
(2) Each TCP connection can only have two端点
, and each TCP connection can only be 点对点
one (one-to-one)
(3) TCP provides 可靠交付(
confirmation mechanism, congestion control, flow control, and timeout retransmission)
services. The data transmitted through the TCP connection is error-free, not lost, not repeated, and arrives in order
(4) Provided by TCP 全双工通信
. TCP allows application processes on both sides of the communication to send data at any time. Both ends of the TCP connection are equipped with sending buffer and receiving buffer, which are used to temporarily store the data of two-way communication
(5)
面向字节流
. "Stream" in TCP refers to流入到进程或从进程流出的字节序列
2. TCP header:
3. Confirmation response mechanism
The confirmation response mechanism is one of the cores of TCP reliability
The receiver replies with an acknowledgment message (ACK), indicating that it has been received
For example: You ask your friends to hang out together, the confirmation response mechanism in TCP is as follows. Number the sent request, and respond to the corresponding number when responding, so as to ensure the reliability of data transmission.
4. Timeout retransmission mechanism
Timeout retransmission is also one of the necessary conditions for TCP reliability guarantee
Acknowledgment is an ideal situation, but data may be lost during transmission
Let's use the above example of asking friends to play: A sends a message to B, are you at home? After waiting for a long time, A has not received the message from B. At this time, there are the following situations:
(1) B does not want to reply to A's message
TCP holds a "pessimistic attitude". When a packet loss is retransmitted, TCP feels that the subsequent retransmissions are useless with a high probability, so it takes a longer time interval to save bandwidth.
(2) B did not receive the message from A (packet loss: the sent request was lost)
(3) B replied to the message, but A did not receive it (packet loss: the ACK of the response was lost, retransmission means that the same data was received )
(2)(3) Situation: There are two situations of packet loss, and it is impossible for the sender to determine which situation it is. Therefore, unified processing is performed: when a piece of data is sent, a timer will be automatically started inside TCP. If no ACK is received within a certain period of time, the timer will automatically trigger the action of retransmitting the message——retransmitting after timeout
5. Flow control
Flow control: Let the sender's sending rate not be too fast, and let the receiver have time to receive
Using the sliding window mechanism can easily realize the flow control of the sender on the TCP connection. The essence is that when TCP sends data, it puts the data in the sending buffer and puts the received data in the receiving buffer. What the flow control needs to do is to control the sending of the sending end through the size of the receiving buffer. If the receiving buffer of the other party is full, it cannot continue sending. In order to control the rate of the sending end, the receiving end will carry its own window (rwnd) size when performing ACK confirmation, and will inform the sending end of the size of its own buffer, and perform corresponding flow control.
6. Congestion control
拥塞控制
That is 防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载
. All congestion control needs to do is a premise, that is,网络能够承受现有的网络负荷
(1) TCP congestion control method
There are four algorithms for TCP congestion control, namely 慢开始
(slow-start), 拥塞避免
(congestion avoidance), 快重传
(fast retransmit) and 快恢复
(fast recovery)
slow start
When the host starts to send data, because it does not know the load of the network, if a large number of data bytes are injected into the network immediately, it may cause network congestion. Experience has shown that it is better to probe first, that is
由小到大逐渐增大发送窗口
, that is,由小到大逐渐增大拥塞窗口数值。
When executing the slow start algorithm, each time the sender receives an acknowledgment ACK for a new segment, it adds 1 to the congestion window value, and then starts the next round of transmission. Therefore, the congestion window cwnd grows exponentially with the number of transmission rounds. When the congestion window cwnd grows to the slow start threshold ssthresh, the congestion avoidance algorithm is changed to execute, and the congestion window grows linearly
ssthresh: slow start threshold, generally there will be an initial value
congestion avoidance
Let the congestion window cwnd increase slowly, that is, increase the sender's congestion window cwnd by 1 every time a round-trip time RTT passes, instead of doubling it as in the slow start phase. The congestion window cwnd
按线性规律缓慢增长
grows much more slowly than the congestion window of the slow-start algorithm"Congestion avoidance" is not completely able to avoid congestion, but controls the congestion window to grow linearly,
使网络比较不容易出现拥塞
fast retransmission
Using the fast retransmission algorithm can make the sender
尽早知道发生了个别报文段的丢失
. The fast retransmission algorithm first requires the receiver not to wait for the piggyback acknowledgment when it sends the data, but to send a duplicate acknowledgment of the received segment immediately even if立即发送确认
it is received失序的报文段
fast recovery
The sender knows that only individual segments are currently lost. So instead of starting the slow start,
快恢复
the algorithm is executed. At this time, the sender adjusts the threshold ssthresh = cwnd / 2, sets the congestion window cwnd = ssthresh at the same time, and starts to execute the congestion avoidance algorithm
Second, establish a connection - three-way handshake
There are three steps to establish a TCP connection, namely three-way handshake
Let me give you a simple example first. We can compare it to making a phone call, as follows:
The first time A does not know whether B can hear his own voice, A says to B "Hey, can you hear it?" It is B's reply to A, "I can hear it, how about you", and the third reply from A confirms that both parties can hear the voice, that is, A's reply to B, "I can too", and the call can be guaranteed by the last three times Normal, similar to the three-way handshake when the network establishes a connection.
Is it okay to shake hands twice? ?
No,
the two-way handshake can only ensure that the one-way connection is unobstructed. The TCP protocol is two-way. The third handshake is to let the server know that the client has agreed to the connection request. The two handshakes can only confirm that the network from the client to the server is reachable, but cannot guarantee that the network from the server to the client is reachable. So we must ensure two-way reachability.As shown in the figure above, if there is no third handshake, it is not known whether A’s receiver is normal, resulting in a normal call
TCP three-way handshake:
First handshake:
The TCP client intends to establish a connection and sends a connection request message to the server. The client requests a connection, and the client performs a synchronous sending state (SYN-SEND). In the connection request message, SYN=1 indicates that this is a request connection In the message, the serial number field seq=x (x is an initial value) is used as the initial serial number of the client
Second handshake:
After receiving the client's request, the TCP server will send a confirmation request message to the client if it is connected, and the server enters the synchronous receiving state. In the confirmation message, the synchronization bit SYN and the confirmation bit ACK are set to 1. Indicates that this is a request confirmation message. Set the serial number seq to an initial value y as the initial serial number of the server. Use the confirmation field ack=x+1 as confirmation to the client
The third handshake:
After receiving the confirmation signal from the server, the TCP client will also send a confirmation message to the server, enter the connection established (ESTABLISHED), and send a confirmation message for server confirmation.
Acknowledgment bit ACK=1, indicating that this is an acknowledgment message
The serial number seq=x+1, means x is sent for the first time, and x+1 is sent for the second time
The confirmation number ack=y+1 is the confirmation of the server
After the server receives it, the incoming connection has been established
3. Disconnect - wave four times
There are four steps to disconnect the TCP connection, that is, wave four times
First wave:
The TCP client actively closes the TCP connection, the TCP client sends a connection release (disconnect) message to the server, and enters the termination waiting state 1,
In the disconnection release message:
(1) The termination bit FIN and the confirmation bit ACK should be set to 1, indicating that it is a TCP connection release message, and confirm the previous message at the same time
(2) The serial number seq is set to u (representing a specific value), which is equal to the last byte of the data that has been transmitted before + 1
(3) The confirmation number ack is set to v, which is equal to the last byte sequence number of the previously received data + 1
Second wave:
When the TCP server receives the TCP connection disconnection request message, it will send a confirmation message to the client and enter the shutdown waiting state. After receiving the confirmation, the client will enter the termination waiting state 2
In a disconnect confirmation message:
- Confirmation number ACK=1, which means it is a confirmation message
- The serial number seq=v, which is equal to the last byte sent by the server + 1, matches the confirmation number of the next waved client
Continue to complete the transmission of the data that is not currently transmitted
Third wave:
The TCP server sends a connection release message to the client and enters the final confirmation state
In the server connection release message:
- The termination bit FIN and the confirmation bit ACK are set to 1, indicating that this is a TCP connection release, and at the same time confirm the previous data
- Serial number seq=w, at this time the server is in a half-closed state (disconnection is bidirectional)
- Confirmation number ack=u+1, repeated confirmation of release
Fourth wave:
After receiving the connection release from the server, the TCP client sends a confirmation message and enters the time waiting state
Acknowledgment bit ACK=1, indicating that it is an acknowledgment message
Sequence number seq=u+1 (the last time was u, send it again), indicating that it is a release message
The confirmation number ack=w+1 means it is a confirmation
Why does TCP wait for 2MSL after waving four times?
An MSL indicates the maximum time for a message to survive. Whether it is a message sent by A to B or a message sent by B to A, it can survive up to 1MSL, so wait for 2MSL, that is, the message comes and goes.
Four, socket programming
Client: analogous to making a phone call
analogy |
Function |
function |
have mobile phone |
Create a socket (with a corresponding TCP protocol) |
socket() |
have a mobile number |
Bind socket (with its own network information) |
bind() |
Dial the other party's phone number |
Request a server connection (establish a connection with the server) |
connect() |
make a call |
send and receive data (communicate) |
read()、write()、recv()、send()、 |
hang up the phone |
End communication (close socket) |
close() |
##Client API function
1. Create a socket
#include <sys/types.h>
#include <sys/socket.h>
//Create a socket file, add a corresponding network communication protocol (file) to the process, and the return value is the file descriptor of the creation number (socket descriptor represents a set of protocols---sockets)
int socket(int domain, int type, int protocol);
Parameter 1:
int domain:地址族,选用那种网络层协议地址
AF_INET------IPV4
AF_INET6-----IPV6
Parameter 2:
int type:套接字类型
SOCK_STREAM--------TCP
SOCK_DGRAM---------UDP
SOCK_RAW:原始套接字(没有传输层协议)
Parameter 3:
int protocol:套接字协议
0:套接字默认协议
return value:
int:整数---------文件描述符(套接字文件)
成功:返回套接字描述符 >= 0
失败:返回-1
2. Bind the socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//Bind the local network information to the socket
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
Parameter 1:
int sockfd:绑定本地网络信息到哪个套接字上(绑定到哪一套协议上)
Parameter 2:
const struct sockaddr *addr:结构体地址,这个结构体中存储的本地网络信息(要绑定的网络信息ip、port)
struct sockaddr {//通用结构体,表示一个网络信息内容
sa_family_t sa_family;
char sa_data[14];
}
//IPV4 网络信息结构体
struct sockaddr_in {
sa_family_t sin_family;//地址族 AF_INET
in_port_t sin_port;//端口
struct in_addr sin_addr;//结构体变量--ip地址
};
/* Internet address. */
struct in_addr {
uint32_t s_addr;//ipv4地址
};
Parameter 3:
socklen_t addrlen:整数,结构体大小(确定信息结构体的大小)
return value:
成功:返回0
失败:返回-1
3. Request connection
#include <sys/types.h>
#include <sys/socket.h>
// Request to establish a connection with the server
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
Parameter 1:
int sockfd:客户端的套接字,使用套接字与服务端建立连接
Parameter 2:
const struct sockaddr *addr:服务端的ip、prot信息,客户端要和哪个服务器建立连接
Parameter 3:
socklen_t addrlen:结构体的大小
return value:
成功:返回0
失败:返回-1
Implementation code:
//TCP客户端进行通信(先发再收)
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//1、创建套接字,选择对应的网络通信协议组
int socketfd = socket(AF_INET,SOCK_STREAM,0);//选择TCP协议
if(socketfd < 0)
{
printf("socket create error\n");
return -1;
}
//2、绑定套接字,对套接字添加自己当前进行需要到本地网络信息
struct sockaddr_in clientaddr;//有一个IPV4网络信息结构体
clientaddr.sin_family = AF_INET;//地址族-----IPV4
clientaddr.sin_port = htons(20000);//为当前进程添加的端口号为10000
clientaddr.sin_addr.s_addr = inet_addr("0.0.0.0");
bind(socketfd,(struct sockaddr *)&clientaddr,sizeof(clientaddr));
//与服务器建立连接
struct sockaddr_in serveraddr;//服务端IPV4网络信息结构体
serveraddr.sin_family = AF_INET;//地址族-----IPV4
serveraddr.sin_port = htons(10000);//为当前进程添加的端口号为10000
serveraddr.sin_addr.s_addr = inet_addr("192.168.138.1");
if(connect(socketfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
{
printf("connect error\n");
}else{
printf("connect ok\n");
}
char buf[20];
while(1)
{
memset(buf,0,20);//清空buf
fgets(buf,20,stdin);
write(socketfd,buf,20);//发送
memset(buf,0,20);
read(socketfd,buf,20);//接收
printf("data is %s\n",buf);
}
close(socketfd);
return 0;
}
Server: analogy to answering the phone
analogy |
Function |
function |
have mobile phone |
Create a socket (with a corresponding TCP protocol) |
socket() |
have a mobile number |
Bind socket (with its own network information) |
bind() |
Waiting for a call (Standby) |
Listen to the server socket (check if there is a client connection) |
listen() |
answer the phone |
Receive the connection request from the agreed client |
accept() |
make a call |
send and receive data (communicate) |
read()、write()、recv()、send()、 |
hang up the phone |
End communication (close socket) |
close() |
##Server API function
1. Create a socket
#include <sys/types.h>
#include <sys/socket.h>
//Create a socket file, add a corresponding network communication protocol (file) to the process, and the return value is the file descriptor of the creation number (socket descriptor represents a set of protocols---sockets)
int socket(int domain, int type, int protocol);
Parameter 1:
int domain:地址族,选用那种网络层协议地址
AF_INET------IPV4
AF_INET6------IPV6
Parameter 2:
int type:套接字类型
SOCK_STREAM--------TCP
SOCK_DGRAM---------UDP
SOCK_RAW:原始套接字(没有传输层协议)
Parameter 3:
int protocol:套接字协议
0:套接字默认协议
return value:
int:整数---------文件描述符(套接字文件)
成功:返回套接字描述符 >= 0
失败:返回-1
2. Binding socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//Bind the local network information to the socket
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
Parameter 1:
int sockfd:绑定本地网络信息到哪个套接字上(绑定到哪一套协议上)
Parameter 2:
const struct sockaddr *addr:结构体地址,这个结构体中存储的本地网络信息(要绑定的网络信息ip、port)
struct sockaddr {//通用结构体,表示一个网络信息内容
sa_family_t sa_family;
char sa_data[14];
}
//IPV4 网络信息结构体
struct sockaddr_in {
sa_family_t sin_family;//地址族 AF_INET
in_port_t sin_port;//端口
struct in_addr sin_addr;//结构体变量--ip地址
};
/* Internet address. */
struct in_addr {
uint32_t s_addr;//ipv4地址
};
Parameter 3:
socklen_t addrlen:整数,结构体大小(确定信息结构体的大小)
return value:
成功:返回0
失败:返回-1
3. Monitor
#include <sys/types.h>
#include <sys/socket.h>
Listening and waiting for client connection, if there is a client connection, it will only store the client connection (a listening queue will be created), as long as there is a client to connect, it will be placed in the listening waiting queue - you can always view the server's own information, whether there is a client connection. And then the socket can only be used for listening, not for communicating with the client
int listen(int sockfd, int backlog); automatically listen after calling (check if there is a client connection)
Parameter 1:
int sockfd:要进行监听的套接字,就是之前绑定了服务器ip、port的套接字,
表示要监听哪个套接字是否有客户端连接
Parameter 2:
int backlog:最多同时能够存储多少个客户端连接——等待队列大小
return value:
成功—— 0
失败——-1
4. Agree to the connection request
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//The server agrees to the connection request (take out a client connection request from the waiting queue and establish a connection. If there is no connection request in the listening queue, it will block and wait for the listening queue to have a connection request) - must receive a connection request
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Parameter 1:
int sockfd:监听套接字,从哪个监听中取出连接
Parameter 2:
struct sockaddr *addr:用于存储客户端ip,port,不需要写NULL
Parameter 3:
socklen_t *addrlen:结构体大小
return value:
成功——返回与连接成功的客户端通信的套接字
失败——-1
5. Send or receive data
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
Parameter 1:
int sockfd:套接字
Parameter 2:
const void *buf:要发送或接收的数据
Parameter 3:
size_t len:数据大小
Parameter 4:
int flags:标志,选项
0:阻塞
Implementation code:
//tcp服务端,与客户端进行通信
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
//1、创建套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);//在服务器创建TCP套接字
//2、绑定套接字
struct sockaddr_in serveraddr;
serveraddr.sin_addr.s_addr = inet_addr("192.168.124.80");
serveraddr.sin_port = htons(9999);
serveraddr.sin_family = AF_INET;
bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
//3、监听套接字
listen(sockfd,10);
//4、接受客户端连接
int clientfd = accept(sockfd,NULL,NULL);//返回值就是与客户端通信的套接字
printf("ok\n");
//服务器与客户端如何进行通信
char buf[50];
while(1)
{
printf("recv\n");
sleep(10);
memset(buf,0,50);
int num = recv(clientfd,buf,50,0);//返回值就是接收的大小
if(strcmp(buf,"quit\n") == 0)
break;
printf("size is %d; data is %s",num,buf);
send(clientfd,buf,50,0);
printf("send ok\n");
}
close(clientfd);
close(sockfd);
return 0;
}