socket

socket

1、什么是Socket

在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据   socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。   我的理解就是Socket就是该模式的一个实现:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。   Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

2、网络中进程如何通信

既然Socket主要是用来解决网络通信的,那么我们就来理解网络中进程是如何通信的。

2.1、本地进程间通信

a、消息传递(管道、消息队列、FIFO)   b、同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)?【不是很明白】   c、共享内存(匿名的和具名的,eg:channel)   d、远程过程调用(RPC)

2.2、网络中进程如何通信

我们要理解网络中进程如何通信,得解决两个问题:   a、我们要如何标识一台主机,即怎样确定我们将要通信的进程是在那一台主机上运行。   b、我们要如何标识唯一进程,本地通过pid标识,网络中应该怎样标识? 解决办法:   a、TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机   b、传输层的“协议+端口”可以唯一标识主机中的应用程序(进程),因此,我们利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互

3、Socket怎么通信

现在,我们知道了网络中进程间如何通信,即利用三元组【ip地址,协议,端口】可以进行网络间通信了,那我们应该怎么实现了,因此,我们socket应运而生,它就是利用三元组解决网络通信的一个中间件工具,就目前而言,几乎所有的应用程序都是采用socket,如UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰)。 Socket通信的数据传输方式,常用的有两种:   a、SOCK_STREAM:表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。   b、SOCK_DGRAM:表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。   例如:QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响

4、TCP/IP协议

4.1概念

TCP/IP【TCP(传输控制协议)和IP(网际协议)】提供点对点的链接机制,将数据应该如何封装、定址、传输、路由以及在目的地如何接收,都加以标准化。它将软件通信过程抽象化为四个抽象层,采取协议堆栈的方式,分别实现出不同通信协议。协议族下的各种协议,依其功能不同,被分别归属到这四个层次结构之中,常被视为是简化的七层OSI模型。

它们之间好比送信的线路和驿站的作用,比如要建议送信驿站,必须得了解送信的各个细节。

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接,客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。 TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)。可以形象的比喻为下面的对话:

[Shake 1] 套接字A:“你好,套接字B,我这里有数据要传送给你,建立连接吧。”
[Shake 2] 套接字B:“好的,我这边已准备就绪。”
[Shake 3] 套接字A:“谢谢你受理我的请求。

三次握手是什么呢,说三次握手之前我们必须先了解一下

4.1.1 TCP数据报结构:

图中tcp数据报的结构中带阴影的几个字段需要重点说明一下:   (1) 序号:Seq(Sequence Number)序号占32位,用来标识从计算机A发送到计算机B的数据包的序号,计算机发送数据时对此进行标记。   (2) 确认号:Ack(Acknowledge Number)确认号占32位,客户端和服务器端都可以发送,Ack = Seq + 1。   (3) 标志位:每个标志位占用1Bit,共有6个,分别为 URG、ACK、PSH、RST、SYN、FIN,具体含义如下:

 

(1)URG:紧急指针(urgent pointer)有效。
(2)ACK:确认序号有效。
(3)PSH:接收方应该尽快将这个报文交给应用层。
(4)RST:重置连接。
(5)SYN:建立一个新连接。
(6)FIN:断开一个连接。
4.1、连接的建立(三次握手):

使用 connect() 建立连接时,客户端和服务器端会相互发送三个数据包,请看下图:

客户端调用 socket() 函数创建套接字后,因为没有建立连接,所以套接字处于CLOSED状态;服务器端调用 listen() 函数后,套接字进入LISTEN状态,开始监听客户端请求 这时客户端发起请求:   1) 当客户端调用 connect() 函数后,TCP协议会组建一个数据包,并设置 SYN 标志位,表示该数据包是用来建立同步连接的。同时生成一个随机数字 1000,填充“序号(Seq)”字段,表示该数据包的序号。完成这些工作,开始向服务器端发送数据包,客户端就进入了SYN-SEND状态。   2) 服务器端收到数据包,检测到已经设置了 SYN 标志位,就知道这是客户端发来的建立连接的“请求包”。服务器端也会组建一个数据包,并设置 SYN 和 ACK 标志位,SYN 表示该数据包用来建立连接,ACK 用来确认收到了刚才客户端发送的数据包   服务器生成一个随机数 2000,填充“序号(Seq)”字段。2000 和客户端数据包没有关系。   服务器将客户端数据包序号(1000)加1,得到1001,并用这个数字填充“确认号(Ack)”字段。   服务器将数据包发出,进入SYN-RECV状态   3) 客户端收到数据包,检测到已经设置了 SYN 和 ACK 标志位,就知道这是服务器发来的“确认包”。客户端会检测“确认号(Ack)”字段,看它的值是否为 1000+1,如果是就说明连接建立成功。   接下来,客户端会继续组建数据包,并设置 ACK 标志位,表示客户端正确接收了服务器发来的“确认包”。同时,将刚才服务器发来的数据包序号(2000)加1,得到 2001,并用这个数字来填充“确认号(Ack)”字段。   客户端将数据包发出,进入ESTABLISED状态,表示连接已经成功建立。   4) 服务器端收到数据包,检测到已经设置了 ACK 标志位,就知道这是客户端发来的“确认包”。服务器会检测“确认号(Ack)”字段,看它的值是否为 2000+1,如果是就说明连接建立成功,服务器进入ESTABLISED状态。   至此,客户端和服务器都进入了ESTABLISED状态,连接建立成功,接下来就可以收发数据了。

4.2、TCP四次握手断开连接

建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧。 断开连接需要四次握手,可以形象的比喻为下面的对话:

 

[Shake 1] 套接字A:“任务处理完毕,我希望断开连接。”
[Shake 2] 套接字B:“哦,是吗?请稍等,我准备一下。”
等待片刻后……
[Shake 3] 套接字B:“我准备好了,可以断开连接了。”
[Shake 4] 套接字A:“好的,谢谢合作。”

下图演示了客户端主动断开连接的场景:

建立连接后,客户端和服务器都处于ESTABLISED状态。这时,客户端发起断开连接的请求:

  1. 客户端调用 close() 函数后,向服务器发送 FIN 数据包,进入FIN_WAIT_1状态。FIN 是 Finish 的缩写,表示完成任务需要断开连接。

  2. 服务器收到数据包后,检测到设置了 FIN 标志位,知道要断开连接,于是向客户端发送“确认包”,进入CLOSE_WAIT状态。 注意:服务器收到请求后并不是立即断开连接,而是先向客户端发送“确认包”,告诉它我知道了,我需要准备一下才能断开连接。

  3. 客户端收到“确认包”后进入FIN_WAIT_2状态,等待服务器准备完毕后再次发送数据包。

  4. 等待片刻后,服务器准备完毕,可以断开连接,于是再主动向客户端发送 FIN 包,告诉它我准备好了,断开连接吧。然后进入LAST_ACK状态。

  5. 客户端收到服务器的 FIN 包后,再向服务器发送 ACK 包,告诉它你断开连接吧。然后进入TIME_WAIT状态。

  6. 服务器收到客户端的 ACK 包后,就断开连接,关闭套接字,进入CLOSED状态。

4.3、关于 TIME_WAIT 状态的说明

客户端最后一次发送 ACK包后进入 TIME_WAIT 状态,而不是直接进入 CLOSED 状态关闭连接,这是为什么呢?

TCP 是面向连接的传输方式,必须保证数据能够正确到达目标机器,不能丢失或出错,而网络是不稳定的,随时可能会毁坏数据,所以机器A每次向机器B发送数据包后,都要求机器B”确认“,回传ACK包,告诉机器A我收到了,这样机器A才能知道数据传送成功了。如果机器B没有回传ACK包,机器A会重新发送,直到机器B回传ACK包。

客户端最后一次向服务器回传ACK包时,有可能会因为网络问题导致服务器收不到,服务器会再次发送 FIN 包,如果这时客户端完全关闭了连接,那么服务器无论如何也收不到ACK包了,所以客户端需要等待片刻、确认对方收到ACK包后才能进入CLOSED状态。那么,要等待多久呢?

数据包在网络中是有生存时间的,超过这个时间还未到达目标主机就会被丢弃,并通知源主机。这称为报文最大生存时间(MSL,Maximum Segment Lifetime)。TIME_WAIT 要等待 2MSL 才会进入 CLOSED 状态。ACK 包到达服务器需要 MSL 时间,服务器重传 FIN 包也需要 MSL 时间,2MSL 是数据包往返的最大时间,如果 2MSL 后还未收到服务器重传的 FIN 包,就说明服务器已经收到了 ACK 包

 

 

 

我的理解:tcp的三次招手是说的连接时的操作,在A连接B的时候会发送一个数据报里面包含发送包的序号seq这个序号是随机生成的,还有一个字节的标志位这个标志位的值是SYN代表我想同你建立连接,然后如果B接收到了这个报的话并且建立连接成功的话,也会发送一个seq序号不过这次会带上一个ack成功连接的话会在A发送过来的seq上加一,然后A如果接受到了数据报的话就会发送过去一个ack同样也是B发送过来的seq加一来确定已经接收到。

posted on 2021-04-06 10:08  Rukewa  阅读(1815)  评论(0)    收藏  举报

导航