简介

Socket 是一套用来执行符合 TCP/IP 协议标准的网络编程接口。有时一个IP地址和一个端口号也可以叫做插口 (socket) ,这个术语最早出现在 TCP 规范 RFC793 里面。对于网络I/O来说就是用来建立tcp链接的工具,它是一个统称,不同操作系统原理相同,但接口函数却不太一样。上面是广义,狭义上术语翻译过来就叫套接字,是定义一个具备Internet通信的基本单位(例如:我们可以说建立一个套接字)。

但基本思路按照 Unix/Linux 系统的哲学"一切皆文件"来实现的。也就是说它的过程类似本地文件读写操作:

“打开open -> 读写 write/read -> 关闭 close”

通过 Socket 提供的函数在创建一个连接时,会返回一个短整数类型的描述符 (Descriptor) 来表示当前这个套接字。在 Windoes 系统叫做句柄。后面的操作也都将把这个套接字的标识作为参数带入函数中。

基本流程

基本 Socket (既不考虑多线程和有线程池的情况) 流程图如下:

img/socket_flowchart.jpg

上面的关闭操作是大致流程,具体请看一下内容。

TCP 连接

TCP 协议详情

TCP 所处位置和协议格式如下:

img/tcp_message_segment.jpg

几个基本概念

报文段(message segment):在传输层逻辑划分上,每一次传输的包含 TCP 的消息内容,叫做 TCP 报文段。这一段会被继续往下被封装到网络层的 IP 数据包 (Packet) 里面。我们做 TCP 协议分析都是基于报文段来分析的。

报文段划分为两部分:一个是首部,一个是数据

16位源/目的端口号:从这可以看出端口号的上限是 $2^16$ 大小,也就是 65535 个。所以相对此的开放式操作系统(linux, windows and so on)的端口号上限也就是这样的。

32位序列号:表示当前报文段中第一个字节的序列号。TCP 数据流中每个字节都有一个序列号。所以它能够对 $2^{32}$ >=4GB 数据进行编号。

32位确认序列号:发给对方确认的序列号,用来告诉对方本地已经接收上一次的数据,所以回个信。确认号 = 上一次接收的对方序列号 + 1。

4位首部长度:网络上也有说是数据偏移,但是理解上还是首部长度说法好理解。它表示报文段起始到数据偏移大小,也就是首部的长度。之所以只有 4 位,因为协议规定它表示的偏移长度是 32 位,而不是字面上的 1 位。所以它能够表达的最大首部长度是 4x15x32=60 字节。正常的长度是 20 个字节。

保留位:6 位的保留位,既没啥用。

6个标志位

标志位说明
URG紧急位,为 1 时,首部中的紧急指针有效
ACK(Acknowledgment)确认位,为 1 时,首部中的确认号有效
PSH推位,为 1 时,要求把数据尽快交给应用程序
RST复位标志,为 1 时,复位连接,一般在出错或关闭连接时使用
SYN(Synchronization) 同步位,在建立连接时使用,当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文段。对方若同意建立连接,在发回的报文段中使 SYN=1 和 ACK=1
FIN结束位,为1时,表示发送方完成了数据发送

TCP连接的建立

客户端和服务器端 TCP 连接的建立也叫三次握手(three-way handshake),通过三次数据传输完成。

img/TCP_connect.jpg

SYN 会占用一个序列号

TCP 的数据传输

img/TCP_translate.jpg

TCP 连接的关闭

img/TCP_close.jpg

FIN 也会占用一个序列号