Socke基础

网络协议

OSI七层网络模型 TCP/IP四层模型 对应网络协议
应用层(Application) 应用层 HTTP、TFTP、FTP、NFS、WAIS
表示层(Presentation) Telnet、SNMP、Gopher
会话层(Session) SMTP、DNS
传输层(Transport) 传输层 TCP、UDP
网络层(Network) 网际层 IP、ICMP、ARP、RARP、AKP、UUCP
数据链路层(Data Link) 网络接口层 FDDI、Ethernet、ARPANET、PDN、SLIP、PPP
物理层(Physical) IEEE 802.1~IEEE 802.11

TCP通信过程

TCP三次握手建立连接过程

  1. 客户端先向服务端发送SYN包(Socket状态从CLOSED变为SYN-SEND)。
  2. 服务端收到SYN包后(Socket状态从LISTEN变为SYN-RECV),向客户端发送针对此SYN包的SYN/ACK包,以确认收到这个SYN包。
  3. 客户端收到此SYN/ACK包后(Socket状态从SYN-SEND变为ESTABLISED),再向服务端发送针对此SYN/ACK包的ACK包。
  4. 服务端收到此ACK包后(Socket从SYN-RECV变为ESTABLISED),连接成功。

全双工异步通信

TCP和UDP协议都是全双工的通信协议,通信双方都可以主动向对方发送数据并接受响应。

通信双方在程序设计上要支持数据的“并行”发送和接受。在全双工通信时,为了达到通信效果,我们需要将数据的传输与数据的加工处理分开,分别由不同的线程处理。这种模式被称为全双工异步通信。

连接断开的四次握手过程

  1. 客户端向服务器发送FIN数据包,表示想要断开连接。Socket状态从ESTABLISED变为FIN_WAIT_1。
  2. 服务器收到此FIN数据包后,向客户端发送ACK包,表示断开中(检查是否可以断开连接)。Socket状态ESTABLISED变为CLOSE_WAIT。
  3. 客户端接收到ACK包,Socket状态从FIN_WAIT_1变为FIN_WAIT_2状态,等待服务器发送确认断开的数据包。
  4. 服务器在准备完毕后向客户端发送FIN包,确认可以断开连接。其Socket状态从CLOSE_WAIT变为LAST_ACK,等待客户端确认。
  5. 客户端收到服务其的FIN包后,再向服务器发送ACK包,确认可以断开连接,Socket状态从FIN_WAIT_2变为TIME_WAIT。
  6. 服务器收到客户端ACK包后,断开连接,关闭套接字(CLOSED状态)。
  7. 客户端等待一段时间,才真正关闭连接,让Socket状态从TIME_WAIT变成CLOSED。

第五步的时候,客户端向服务端发送的ACK包有可能因为网络问题导致丢失,从而导致服务端重新发送对应的FIN包。入欧客户端发送ACK包后完全关闭了Socket,那么无论服务端发送多少次FIN包,都收不到客户端的ACK包了,所以客户端要进入TIME_WAIT状态等待一段时间,确认服务器收到ACK包,才进入CLOSED状态。

通信方式

长连接与短连接

每次传输数据之前都要建立新连接,并传输之后关闭连接,这种方式被称为短连接。(HTTP 1.x就是基于TCP短连接的超文本传输协议)

在客户端和服务端之间建立一个长期的连接,并在其上进行多次通信,直到双方不再需要通信,或者其中一方退出时候才断开连接,这种方式被成为长连接。

线程模型

方案1 

客户端的每个线程都各自创建一个Socket可连接来连接服务端。服务端在接收到新的连接请求后,为每一个连接都创建一个线程来读取和处理数据,并返回结果。

注意:1.0.0表示发出去的数据,1.0.1表示处理结果数据

 这种模型结构简单,编码容易,不需要对数据进行封包等处理;缺点是并发能力差,效率低。

方案2

双方建立一个连接,客户端的多个线程通过独占锁的机制轮流使用Socket。具体步骤

  1. 获取锁
  2. 发送数据
  3. 接收数据
  4. 释放锁

 

 注意:L表示独占锁

这一个模式需要对数据进行封包,已确定每个数据的边界。其适用于客户端线程不是很多,但是调用频繁。且每个调用耗时很短的场景。

方案3

双方只建立一个连接,客户端多个线程通过竞争锁来轮流通过Socket发送数据,并在发送玩数据后阻塞自己,等待唤醒。再用一个专门的线程从Socket中读取结果数据,之后唤醒阻塞的线程,将结果数据传递给他们。

 注意:R代表专门的数据读取线程,B表示线程在获取了锁L并完成数据发送后将自己转为阻塞状态。

需要注意的是由于服务端的数据处理是多线程并行的,因此么个请求的处理时长不一,无法按数据输入数据返回结果。

这种模型也需要对数据进行封包,以确定数据边界。由于需要多线程竞争同一个锁,因此,线程数越多性能越差,但是优于前两个方案。

方案4

基于方案3,抗客户端的写锁L换成一个数据队列Q,用一个专门的写线程W从队列Q获取数据并发送,减少了竞争锁。

 方案5

基于方案4,我们再进一步,在服务端也采用发送数据队列和专门的发送线程。

  

原文地址:https://www.cnblogs.com/wangb0402/p/12674065.html