TCP/IP协议相关知识

本文详细介绍了TCP/IP协议的基础概念,包括TCP/IP协议族的工作原理、分层结构、TCP和UDP的区别,以及Socket通信机制。此外还介绍了如何利用多线程处理多个客户端连接,以及IOCP模型在高并发场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


     1、TCP/IP协议

TCP/IP协议叫做传输控制/网际协议,它规范了网络上的所有通信设备,尤其是一个主机与另一个主机的数据往来格式和传送方式,是网络中使用的基本通信协议。

TCP/IP是一个协议族,包括上百个功能的协议,其中TCPIP协议是保证数据完整传输的两个基本的重要协议。TCP/IP协议传输数据的过程中,TCP协议负责将数据分成若干个数据包,并给每个数据包加上包头,包头上面有相应的编号,以此保证数据接收时能将数据还原。IP协议给每个包头加上接收端主机地址,这样能够确保数据传输到正确的目的主机地址。所以,IP协议保证数据的传输,TCP协议保证数据传输的质量。

 

     2、TCP/IP协议分层

TCP/IP通信协议采用了四层的层级模型结构,它参考了OSI的七层模型,主要分为应用层、传输层、网络层和链路层。

  • 应用层:负责处理特定的应用程序细节。比如简单邮件传输协议(SMTP),文件传输协议(FTP),网络远程访问协议(Telnet)以及简单网络管理协议(SNMP)。

  • 传输层:提供了节点间的数据传送服务,主要为两台主机上的应用程序提供端到端的通信。其中主要包括两种重要的传输协议,传输控制协议(TCP)和用户数据报协议(UDP)。TCP提供了可靠的数据通信,因此应用层可以不考虑传输的完整性。而UDP并不能保证数据能够到达目的端,任何必须的可靠性由应用层提供。

  • 网路层:负责提供基本的数据封包传送功能,让每一块数据包都能到达目的主机。主要包括网络协议(IP)、Internet互联网控制报文协议(ICMP Internet)以及Internet组管理协议(IGMP Internet)。

  • 链路层:通常包括操作系统中的设备驱动程序和计算机中对应的网路接口卡,主要处理物理接口细节。

 

     3、TCP

传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器端进行数据交换时,必须现在双方建立一个TCP连接,之后才能传输数据。它能够保证数据传输过程中数据是可靠的顺序的以及不会重复。但是,TCP在数据转移时必须创建并保持一个连接,这个会给通信过程增加开销,对比UDP传输速率会较慢。

TCP建立连接需要进行三次握手:

  1. 建立连接时,客户端A向服务器B发送同步序列号SYN包(SYN=j),并且进入SYN_SEND状态,等待服务器确认。

  2. 服务器B接收到SYN包时,将发送确认序号ACKj+1)对客户端的SYN报文段进行确认,同时还会发回服务器的初始序号SYN包(SYN=k)作为应答,即SYN+ACK包,此时服务器进入SYN_RECV状态。

  3. 客户端A收到服务器BSYN+ACK包时,将发送给服务器确认包ACKACK=k+1),发送完成后,客户端和服务器进入ESTABLISHED状态,完成三次握手。

 

客户端状态:

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

前三个状态是客户端三次握手建立连接的状态迁移。建立连接后是四次挥手断开连接的状态迁移。

客户端主动请求关闭连接时,会向服务器端发送FIN报文,此时客户端进入FIN_WAIT_1状态。服务器不会立即关闭socket连接,仍然可以发送数据,此时服务器端会发送ACK确认包给客户端,客户端进入FIN_WAIT_2状态,等待服务器发送FIN报文。在客户端接收到FIN报文并发送ACK确认包时,客户端进入TIME_WAIT状态,在等待2MSL后依然没得到回复时,此时证明服务器已经正常断开连接,此时会断开TCP连接。

 

服务器状态:

CLOSED->LISTEN->SYN_RECV->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

同样,前几个状态是三次握手的状态转移。当服务器接收到关闭连接的FIN报文并发送ACK回答请求时,会进入CLOSE_WAIT状态。当服务器发送数据包完毕时,会发送FIN报文主动请求关闭连接,这时等待客户端的答复,即ACK的接收,进入LAST_ACK状态。当接收到ACK时,就关闭连接,进入CLOSED状态。

 

     4、UDP

UDP是一个非连接的协议,传输数据之前不需要建立源端和终端的连接,它是一个简单的面向数据报的运输层协议。它只是把应用程序传给IP层的数据报发送出去,并不能保证它们能到达目的地。因为UDP没有建立连接,所以不需要维护连接状态,传输速率对比TCP快得多。

 

     5、Socket

Socket接口是TCP/IP网络的API,它用于描述IP地址和端口,是一个通信链的句柄。为了实现网络通信过程,必须标识某台主机的一个进程。可以利用IP层的ip地址唯一标识主机,利用协议和端口号唯一标识主机的一个进程。因此,可以利用ip地址+协议+端口号唯一标识网络中的一个进程。这样一来,便可以利用socket进行通信。

常用的Socket类型有两种:流式SocketSOCK_STREAM)和数据报式SocketSOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

 

Socket通信过程是以“打开—读写—关闭”为模式实现的,以TCP为例子,在Server端上,其流程如下:

socket()->bind()->listen()->accept()->recv()->close()

  • Socket():建立socket,可以用于建立TCP或者UDP连接。建立socket会给一个socket数据结构分配内存空间,socket结构体包含5种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。

  • bind():用于建立socket与本机上一个端口之间的关联。在参数的设置中,必须指定本机的地址以及端口等信息,并且需要进行字节序的转换。

  • listen():使socket处于监听状态,并为该socket建立一个输入数据队列,将到达的请求保存在队列中,直到程序处理它们。

  • accept():让服务器接收客户的连接请求。在建立好输入队列时,服务器会调用accept()函数,然后等待客户的连接请求。没有客户请求到来时,服务器会一直停留在accept上,即阻塞,直到接收到用户请求才往下执行。

  • recv()recv()send()函数用于tcp连接的数据传输。

  • close():释放相应的socket

总体流程:首先调用socket函数建立服务器端的socket,然后调用bind函数将本机地址与一个端口号绑定,接着调用listen在相应的socket上进行监听,当accept接收到一个连接服务请求时,将生成新的socket,利用该socket进行数据的交换,最后关闭socket

 

Client端上,其通信流程如下:

socket()->connect()->send()->close()

  • socket():客户端建立socket

  • connect():根据服务器ip地址和端口连接服务器socket

  • send():客户端与服务器传输数据

  • close():关闭客户端socket

总体流程:通过服务器ip地址,创建socket之后调用connect与服务器建立连接,成功之后利用sendrecv函数与服务器进行数据交换,最后关闭socket

 

对于udp,由于没有建立端到端的连接,因此在发送和接收数据时应指明相应的主机地址。sendto()recvfrom()就是用于在无连接的数据报socket方式下进行数据传输。

 

   6、多个Client连接一个Server

可以利用多个accept()实现多client连接,多accept()server建立多个子线程,每个子线程都要一个accept(),这样可以为每个Client建立socket描述符。accept连接成功后,会产生一个新的socket描述符,这样通过循环多线程利用accept产生多socket描述符就可以与多个client进行连接通信。

 

     7、IOCP

传统的C/S模式通常为每个客户端创建一个新的线程,这种实现方式会随着用户量的增大而效率急剧下降。IOCP的引入解决了这种高并发的异步I/O请求,是一种高性能的I/O模型。

IOCP本质就是事先创建好N个线程,让它们先挂起,之后将用户的请求投递到一个消息队列中。然后让这N个线程逐一地从消息队列中取出消息并进行处理。这样一来,不仅减少了线程创建的开销,同时提高了线程的利用率。

处理流程:

首先创建一个完成端口,然后再创建一个或多个工作线程,并指定它们到这个完成端口上去读取数据。然后将远程连接的套接字句柄关联到这个完成端口,工作线程调用getQueuedCompletionStatus在关联到这个完成端口上的所有套接字上等待I/O的完成,最后发出sendrecv,并继续下一次循环阻塞在getQueuedCompletionStatus

  1. 创建一个完成端口

HANDLE completionPort =CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0);

  1. 创建一个线程threadA

  2. threadA循环调用GetQueuedCompletionStatus得到I/O的结果

while(true){

           bRet= GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,(PULONG_PTR)&PerHandleData, (LPOVERLAPPED*)&IpOverlapped, INFINITE);

}

  1. 主线程循环调用accept等待客户端连上

  2. 主线程accept返回新连接建立以后,把这个新的套接字句柄关联到完成端口上,然后发出一个异步的readwrite操作

  3. 主线程继续下一次循环,阻塞在accept等待客户连接

  4. 操作系统完成readwrite操作,并把结果发给完成端口

  5. ThreadA线程里的GetQueuedCompletionStatus马上返回,并从完成端口中取得刚才完成的read/write结果

  6. ThreadA 线程里对这些数据进行处理,然后接着发出 Read/Write,并继续下一次循环阻塞在 GetQueuedCompletionStatus这里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值