TCP介绍及TCP网络编程

来源:互联网 发布:js代码断点调试 编辑:程序博客网 时间:2024/05/19 04:54

一、TCP头部结构:
这里写图片描述
①16位端口号及16位目的端口号:告知主机该报文段来自哪里(源端口)要传给那个上层协议或应用程序(目的端口)。
②32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号。A发送给B的第一个报文段中,序号值被系统初始化为某个随机值ISN,后续在该方向上的TCP报文段的序号值被设置为ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。
③32位确认号:另一方对TCP报文段的响应,其值是收到的TCP报文段的序号值加1。
④4位头部长度:标识该TCP头部有多少个32位(4字节,即有多少行)。4位最大能表示15,所以TCP头部最长是60字节。
⑤6位标志:
5.1 URG标志:紧急指针是否有效。
5.2 ACK标志:确认号是否有效。确认报文段。
5.3 PSH标志:提示接收端应用程序应该立即从TCP接受缓冲区中读走数据,为接受后续数据腾出空间。TCP缓冲区 在网卡上,有大小限制,如果应用程序一直不读取就会一直在缓冲区,影响后续数据。
5.4 RST标志:表示要求对方重新建立连接。复位报文段。
5.5 SYN标志:请求建立连接。同步报文段。
5.6 FIN标志:通知对方本段要关闭连接。结束报文段。
⑥16位窗口大小:TCP流量控制。接收通告窗口告诉对方本端的TCP缓冲区还能接收多大字节的数据,避免发过来接收不了而造成的数据丢失。
⑦16位校验和:检验TCP报文段在传输过程中是否损坏。
⑧16位紧急指针:紧急数据先处理。

二、TCP三次握手以及四次挥手(本文都以客户端先发送请求为例)
这里写图片描述
三次握手建立连接:
①请求连接方(客户端)发送SYN请求连接;
②服务器返回SYN/ACK确认收到发送端请求;
③客户端回馈给服务器ACK,表示确认收到服务器发送的确认。

注:1、如果服务器没有收到客户端发送的ACK,则启动超时重传机制,这确保了TCP连接的准确性。2、TCP的握手至少有三次,不可再少。

四次挥手断开连接:
①请求方(客户端)数据已经发送完毕,向服务器发送FIN请求断开连接;
②服务器向客户端发送ACK,对客户端发送的FIN进行确认,并不需要即使断开;
③服务器将接收到的数据处理完毕后发送FIN,断开连接;
④客户端发送确认消息ACK。

注:1、应答方(服务器)给在请求方(客户端)发送第一个ACK之后,可能还需要一段时间来处理请求方发送的数据。2、如果在应答方(服务器)给请求方(客户端)发送第一个ACK后,服务器可能已经处理完了所有的数据,此时四次挥手可以缩短为三次。3、TIME_WAIT状态:出现在主动发起断开链接请求的一端。意义:    3.1、 保证可靠的终止TCP链接    3.2、 保证迟来的数据报能被识别并丢弃

三、总状态转移图
这里写图片描述这里写图片描述

四、TCP编程
服务器:
1、创建socket
2、bind(命名IP地址和端口号)
3、listen(创建监听队列)
4、accept(拿到已经完成连接的)
5、recv/send(收发数据)
6、close(关闭)

客户端:
1、socket
2、connect
3、recv/send
4、close

①创建套接字函数:int socket(int domain, int type, int protocol)domain:协议簇 IPv4(AF_INET)或 IPv6(AF_INET6) type:选择协议 TCP:SOCK_STREAM     UDP:SOCK_DGRAM   protocol:0  ②命名IP地址和端口号:int bind(int sockfd,const struct sockaddr*addr,int addrlen)sockfd:文件描述符 addr:指定IP地址和端口号   struct sockaddr_in{      sa_family_t sin_family;   //地址簇:AF_INET    u_int16_t sin_port;       //端口号(网络字节序:大端模式 PC机:小端模式)    struct in_addr sin_addr; //IPv4地址结构体};  struct sin_addr{         u_int32_t s_addr;        //IPv4地址用网络字节序表示};  addrlen:该socket地址的长度③创建一个监听队列:int listen(int sockfd, int size) size:队列大小,默认值5 。④int accept(int sockfd,struct sockaddr *addr ,int *addrlen)addr:要连接的服务器的ip地址及端口号(netstat -atp 显示本机上所有的tcp服务程序以及其占用的端口号)⑤recv(c,buff,127,0)

代码实现
ser.c

 void main() {     int sockfd = socket(AF_INET,SOCK_STREAM,0);     assert(sockfd != -1);     struct sockaddr_in ser,cli;     ser.sin_family = AF_INET;     ser.sin_port = htons(6000);     ser.sin_addr.s_addr = inet_addr("127.0.0.1");      int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));      assert(res != -1);      listen(sockfd,5);      while(1)      {          int len = sizeof(cli);          int c = accept(sockfd,(struct sockaddr*)&cli,&len);          assert(c != -1);          char buff[128] = {0};          recv(c,buff,127,0);          printf("recv::%s\n",buff);          send(c,"I Know",strlen("I Know"),0);          close(c);      }      close(sockfd);  }

cli.c

//客户端cli.cvoid main() {     int sockfd = socket(AF_INET,SOCK_STREAN,0);      assert(sockfd != -1);      struct sockaddr_in ser,cli;      ser.sin_family = AF_INET;     ser.sin_port = htons(6000);      ser.sin_addr.s_addr = inet_addr("127.0.0.1");      int res = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));      assert(res != -1);      send(sockfd,"Hello World",strlen("Hello World"),0);      char buff[128] = {0};      recv(sockfd,buff,127,0);      printf("recv::%s\n",buff);      close(sockfd);  }
原创粉丝点击