TCP通信实现

发布于:2024-09-18 ⋅ 阅读:(41) ⋅ 点赞:(0)

目录

前言

一、实现TCP通信 

二、通信原理 (网路传输的封包与拆包)

三、通信过程中的头

1.MAC帧

2. IP头

 3.TCP头

4.UDP头         

 总结


前言

        TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于流的通信协议。它是互联网协议栈(TCP/IP)中的核心协议之一,主要用于保证在计算机网络中可靠地传输数据。

TCP通信的基本特点

  • 面向连接:在发送数据之前,TCP要求通信双方(客户端和服务器)首先建立一个连接,这个过程被称为“三次握手”。连接建立后,数据才可以传输;数据传输完成后,需要释放连接(通过“四次挥手”关闭连接)。

  • 可靠传输:TCP保证数据包的正确传输。通过序列号和确认号的机制,TCP能够检测丢包、乱序、重复等问题,并通过重传机制进行纠正,从而确保数据的完整性和顺序性。

  • 基于流:TCP传输的数据没有消息边界,而是一个连续的数据流。数据可以按照任意大小进行发送和接收,应用层必须根据协议或约定来解析数据边界。

         本小节我们先来实现TCP通信,然后再来细分TCP通信当中的一些细节问题,关于tcp的三次握手和四次挥手看这篇文章:http://t.csdnimg.cn/WWgfZ

一、实现TCP通信 

服务器代码:

//实现TCP服务器文件
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<netinet/ip.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<fcntl.h>

int main(int argc, const char *argv[])
{
	
	//1、创建套接字
	int listenfd=socket(AF_INET,SOCK_STREAM,0);
	if(listenfd<0)
	{
		printf("创建失败\n");
		return -1;
	}
	
	//2、绑定套接字
	//填写自己的地址信息,不是必要的
	struct sockaddr_in serveraddr;
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(8888);
	serveraddr.sin_addr.s_addr=inet_addr("192.168.124.29");
	int bind_ret=bind(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	if(bind_ret<0)
	{
		printf("绑定失败\n");
		return -1;
	}
	//3、建立连接connect
	//监听套接字
	int listen_ret=listen(listenfd,10);
	if(listen_ret<0)
	{
		perror("listen failed:");
		return -1;
	}
	
		//建立连接accept
		int serverfd=accept(listenfd,NULL,NULL);
		if(serverfd<0)
		{
			perror("accept failed:");
			return -1;
		}
	while(1)
	{
		//接收数据
		char buf[100];
		int ret=recv(serverfd,buf,100,0);
		//读取数据发送回去
		buf[ret]='\0';
		int send_ret=send(serverfd,buf,strlen(buf),0);
		if(send_ret<0)
		{
			perror("send failed:");
			return -1;
		}
		if(send_ret==0)
			break;
	}
		

	return 0;
}

然后我们使用网络调试器连接服务器:

 网络调试器下载地址:通过网盘分享的文件:scomm.exe
链接: https://pan.baidu.com/s/1OkiZLT_CeoryEZepaOSGqQ 提取码: 8a85

 如果出现绑定失败如下图:

不用紧张,我们下载号网络调试器之后双击运行;

连接完成之后,在调试器中发送你想要发送的内容,服务器接收到以后,会直接发送到客户端,也就是网络调试器中:

这样我们就完成了一个简单的TCP通信的实现过程 

二、通信原理 (网路传输的封包与拆包)

         数据在通信过程中的传输我们可以这样来看:

数据经过多次的封装,然后再发送给服务器,再每一层的封装过程中,都会加入一个协议,这个协议帮助数据完整的传输(也就是在我们发送数据的时候加入了网络层-IP头(协议)、传输层-TCP头(TCP协议),网络接口层-帧头(MAC地址)这个就是封包过程,接收端做拆包过程)。下面我们就以TCP传输作为例子。

        首先,在客户应用当中我们输入了数据,如上图中的流程图一样,在传输层加入了TCP头,在网络层加入了IP头,在网络接口层加入了MAC帧头,我们仔细来看这些头里面有什么数据。

三、通信过程中的头

         上面我们提到了每层中都有协议,那么具体每个协议里面都有什么内容数据呢,本小节我们就来看看里面有什么数据,这里就要用到一个抓包软件wireshark,像自己抓包的小伙伴可以自己下载,

        首先,我们打开wireshark这个软件

        点击WIAN进入抓包

                当我们实现上面TCP服务器的时候,会出现建立连接的过程

1.MAC帧

        看图中左下角,我们打开第二行是内核空间封装的MAC帧头地址

         里面的信息如下:目标MAC地址(Destination)、源MAC地址(Source),type类型,type后面是十六进制的数,如图中是0X0800则表示只接收本机MAC地址的IPV4类型的数据帧

2. IP头

         点击第三行中的数据,这是我们的IP头信息,在下图中可以看到我们使用的IPV4的版本,如下图左下角部分:

IPv4头部的标准长度为20字节,但它可以通过选项字段增加到60字节。以下是IPv4头的每个字段及其作用:

  1. 版本(Version):4位

    • 该字段指示IP协议的版本。对于IPv4,它的值是4;对于IPv6,它的值是6。这个字段帮助网络设备识别和处理不同版本的IP包。
  2. 首部长度(IHL,Internet Header Length):4位

    • 该字段表示IP头的长度,以32位字为单位。最小值是5(即20字节),如果有选项字段,它的值会更大。此字段用于确定IP头部的结束位置。
  3. 服务类型(Type of Service, ToS):8位

    • 该字段用于指示数据包的优先级和服务质量要求,包括延迟、吞吐量和可靠性等。它现在通常被称为“Differentiated Services Code Point (DSCP)”和“Explicit Congestion Notification (ECN)”字段,用于网络流量的优先级和拥塞通知。
  4. 总长度(Total Length):16位

    • 该字段表示整个IP数据包的长度,包括头部和数据部分,以字节为单位。最大值为65,535字节。这个字段用于接收端计算数据包的总长度并进行正确的解析。
  5. 标识(Identification):16位

    • 该字段用于唯一标识每一个IP数据包,用于分片和重组。当一个大的数据包被分片时,每个片段都有相同的标识,以便接收端能够将这些片段重新组装成完整的数据包。
  6. 标志(Flags):3位

    • 该字段用于控制和标识数据包的分片情况:
      • 第一位(保留,Reserved):应为0,未来可能用于扩展。
      • 第二位(Don't Fragment,DF):如果设置为1,表示数据包不允许分片。
      • 第三位(More Fragments,MF):如果设置为1,表示数据包有更多的分片。
  7. 片偏移(Fragment Offset):13位

    • 该字段表示数据包中片段的偏移量,以8字节为单位。它用于数据包的重组,指示每个片段在原始数据包中的位置。
  8. 生存时间(TTL, Time to Live):8位

    • 该字段用于防止数据包在网络中无限循环。每经过一个路由器或跳数,TTL值减1。当TTL值减到0时,数据包被丢弃,并且通常会发送一个“时间超时”(Time Exceeded)消息回源地址。
  9. 协议(Protocol):8位

    • 该字段指示IP数据包中的数据部分使用的传输层协议,如TCP(值为6)、UDP(值为17)等。它帮助接收方识别数据包的负载协议。
  10. 头部校验和(Header Checksum):16位

    • 该字段用于检查IP头的完整性。它包含IP头部的校验和,接收方使用这个值来检测IP头部是否在传输过程中发生了错误。如果校验和不匹配,数据包会被丢弃。
  11. 源IP地址(Source Address):32位

    • 该字段包含数据包发送方的IP地址,用于在网络中标识数据包的来源。
  12. 目的IP地址(Destination Address):32位

    • 该字段包含数据包接收方的IP地址,用于在网络中标识数据包的目标。
  13. 选项(Options):0-40字节(可选)

    • 这个字段是可选的,可以包含不同的网络控制信息,比如时间戳、安全选项等。如果没有使用选项字段,它的长度为0。选项字段的存在可以影响数据包的处理方式,但大多数应用和协议使用默认的头部设置而不添加选项。
  14. 填充(Padding):0-3字节

    • 这个字段用于确保IP头部长度为32位的倍数。它用于对齐,以确保头部的总长度是4字节的整数倍。

 3.TCP头

       TCP头部是TCP协议中的重要部分,它负责确保数据的可靠传输。TCP头部包含了许多控制信息,用于管理连接、数据流和错误检测。

        同样,我们点击第四行,这里面包含了TCP头部的信息,开始部分是我们的源端口号和目的端口号,在左下角部分

TCP头部格式

TCP头部的标准长度为20字节,但可以通过选项字段扩展。以下是TCP头部的每个字段及其作用:

  1. 源端口(Source Port):16位

    • 该字段表示发送方的端口号。端口号用于在主机上区分不同的应用程序或服务。
  2. 目的端口(Destination Port):16位

    • 该字段表示接收方的端口号,指明数据包应送达的具体应用程序或服务。
  3. 序列号(Sequence Number):32位

    • 该字段用于标识发送的数据字节流中的位置。对于每个数据包,序列号帮助接收方按正确顺序重新组装数据。如果连接是新的,它表示第一个字节的序列号;如果是后续的数据包,它表示数据的字节位置。
  4. 确认号(Acknowledgment Number):32位

    • 该字段用于确认已接收到的数据字节的序列号。确认号表示接收方期望接收的下一个字节的序列号。如果确认号为X,则表示接收方已成功接收序列号小于X的数据。
  5. 数据偏移(Data Offset):4位

    • 该字段表示TCP头部的长度,以32位字为单位。它指示数据部分的起始位置,帮助接收方定位数据部分的开始。
  6. 保留(Reserved):3位

    • 该字段保留供将来使用,当前应设置为0。
  7. 控制位(Flags):9位

    • 该字段包含各种控制标志,用于管理TCP连接的状态:
      • URG(Urgent Pointer):如果设置为1,表示数据包包含紧急数据。
      • ACK(Acknowledgment):如果设置为1,表示确认号字段有效。
      • PSH(Push):如果设置为1,表示接收方应立即将数据传递给应用层,而不是缓冲。
      • RST(Reset):如果设置为1,表示强制重置连接。
      • SYN(Synchronize):如果设置为1,表示请求建立连接,用于三次握手过程。
      • FIN(Finish):如果设置为1,表示数据传输结束,请求关闭连接。
  8. 窗口大小(Window Size):16位

    • 该字段用于流量控制,指示接收方当前的接收窗口大小,表示可以接收的最大字节数。它帮助发送方控制发送速率,以避免接收方缓存溢出。
  9. 校验和(Checksum):16位

    • 该字段用于检查TCP头部和数据部分的完整性。接收方计算和比对校验和,以检测在传输过程中是否发生了错误。如果校验和不匹配,数据包会被丢弃。
  10. 紧急指针(Urgent Pointer):16位

    • 该字段在URG标志位为1时有效,指示紧急数据的结束位置。接收方应优先处理这些紧急数据。
  11. 选项(Options):0-40字节(可选)

    • 该字段用于提供附加的控制信息,如最大报文段长度(MSS)、时间戳、窗口缩放等。选项字段可以扩展TCP的功能,但不是所有的数据包都有选项字段。
  12. 填充(Padding):0-3字节

    • 这个字段用于确保TCP头部长度为32位的倍数。它用于对齐,以确保头部的总长度是4字节的整数倍。
  13. 数据(Data):变长

    • 这是TCP头部之后的数据部分,包括实际传输的应用数据。数据部分的长度由数据偏移字段指示。

TCP头部的应用

  • 连接管理:通过SYN和ACK标志,TCP能够管理连接的建立和关闭。SYN用于建立连接,ACK用于确认数据包的接收。

  • 数据传输:序列号和确认号用于跟踪数据的发送和接收,确保数据包按照正确的顺序到达,并进行重传以纠正丢包。

  • 流量控制:通过窗口大小字段,TCP可以动态调整数据的发送速率,防止接收方缓存溢出。

  • 错误检测:校验和字段用于确保数据的完整性,检测和修复传输中的错误。

  • 紧急数据处理:紧急指针字段用于处理优先级数据,确保紧急数据得到及时处理。

  • 选项扩展:选项字段允许在TCP头部添加附加功能,如优化传输性能和支持更多的网络功能。

4.UDP头         

        UDP(User Datagram Protocol,用户数据报协议)是一个简单的、无连接的传输层协议。与TCP不同,UDP不提供连接管理、流量控制和错误恢复机制,它更注重于提供快速的、低开销的数据传输。UDP头部设计简单且直接,用于快速传输数据。如下图:

         

udp的头很简单

UDP头部格式

UDP头部固定为8字节(64位),每个字段的作用如下:

  1. 源端口(Source Port):16位

    • 该字段表示发送方的端口号。端口号用于在主机上标识不同的应用程序或服务。
  2. 目的端口(Destination Port):16位

    • 该字段表示接收方的端口号,指示数据包应送达的具体应用程序或服务。
  3. 长度(Length):16位

    • 该字段表示UDP头部和数据部分的总长度,以字节为单位。最小值是8字节(仅头部),最大值为65,535字节(包括数据)。这个字段用于接收方计算UDP数据包的总长度,确保完整接收。
  4. 校验和(Checksum):16位

    • 该字段用于检查UDP头部和数据部分的完整性。校验和用于检测在传输过程中是否发生了错误。如果校验和不匹配,数据包可能会被丢弃(具体取决于实现和配置)。校验和字段是可选的,但建议使用,以提高数据传输的可靠性。

        从这里也可以看出UDP通信和TCP通信的区别,我们经常说tcp通信可靠也是因为TCP头中包含数据很多,便于数据传输的完整性,后面我会单独出一篇来介绍 

 总结

  •  MAC帧(以太网帧):以太网帧是数据链路层的一个重要组成部分,用于在局域网(LAN)中传输数据。   
  • IPv4头部:包含用于路由和分片的各种信息,如源和目的IP地址、TTL、协议类型等。
  • TCP头部:提供了连接管理、数据流控制和错误检测的功能,适用于需要可靠数据传输的应用。
  • UDP头部:设计简洁,不提供连接管理和流量控制,适用于需要快速传输的应用。