TCP/IP,http,RPC、SOA、长连接短连接

  • 2019 年 11 月 22 日
  • 筆記

TCP/IP

  • 建立TCP需要三次握手才能建立(客户端发起SYN,服务端SYN+ACK,客户端ACK),
  • 断开连接则需要四次握手(客户端和服务端都可以发起,FIN-ACK-FIN-ACK)。

为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。

但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

SYN攻击:发送大量的SYN,导致服务端无法识别哪些是有效的

RPC

RPC是指远程调用,两服务器A、B,A要调用B上的一个方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据

  1. 通讯问题:在客户端和服务端建立TCP连接,远程调用的所有交换数据都在这个连接里传输。
  2. 解决寻址问题:IP及端口寻址,方法名
  3. 序列化(Serialize):发生远程调用时,方法的参数需要通过底层的网络协议如TCP传送到服务器,由于网络协议是基于二进制的,内存中的参数值需要序列化成二进制的形式,通过寻址和传输序列化的二进制发送给服务器。
  4. 服务器反序列化:服务器收到请求后需要反序列化,恢复内存中的表达方式,然后找到对应的方法(寻址的一部分),进行本地调用。
  5. 返回值发送给客户端,这个部分也需要序列化和反序列化。

SOA

采用一组服务的方式来构建一个应用,服务(hedwig、jsf、RESTful)独立部署在不同的进程中,不同服务通过一些轻量级交互机制来通信,例如RPC、HTTP等。服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。

RPC 的实现是基于SOA这样的一个架构 C/S模式 远程调用的通讯使用TCP 然后hedwig restful jsf这些就是不同的服务形式

http 协议和 tcp/ip 协议的关系

(1) http 是应用层协议,tcp 协议是传输层协议,ip 协议是网络协议。

(2) ip 协议主要解决网络路由和寻址问题

(3) tcp 协议主要解决在 ip 层协议之上,如何可靠的传输数据,即接收端收到的数据包的大小和顺序,和发送端保持一致。tcp 协议是可靠的面相连接的。

  1. http协议是无状态的,指的是http协议对于事务处理没有记忆功能,客户端向服务端请求完数据之后,服务端不知道客户端是什么状态。
  2. http的长连接和短连接,本质上是tcp层的长连接和短连接: http 1.0 默认使用短连接, http 1.1 默认使用长连接,在使用的http协议,在响应头会加上 Connection:keep-alive
  3. RPC 比 http 请求快的原因:http 使用 http 协议,rpc 使用 tcp 协议,比 http 少了应用层,表示层,会话层,这3层,rpc使用长连接,而长连接比短连接更节省资源,效率更高(每个连接的建立和释放都是需要资源和时间的)。

TCP/IP

是个协议组,可分为三个层次:网络层、传输层和应用层

在网络层有IP 协议、ICMP 协议、ARP 协议、RARP 协议和 BOOTP 协议。

在传输层中有TCP协议与UDP协议。

在应用层有: TCP 包括 FTP、HTTP、TELNET、SMTP 等协议

UDP 包括 DNS、TFTP 等协议

当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次握手,所以说每个连接的建立都是需要资源消耗和时间消耗的。

通信过程:

主机 A 的应用程序要能和主机 B 的应用程序通信,必须通过 Socket 建立连接,而建立 Socket 连接必须需要底层 TCP/IP 协议来建立 TCP 连接。建立 TCP 连接需要底层 IP 协议来寻址网络中的主机。我们知道网络层使用的 IP 协议可以帮助我们根据 IP 地址来找到目标主机,但是一台主机上可能运行着多个应用程序,如何才能与指定的应用程序通信就要通过 TCP 或 UPD 的地址也就是端口号来指定。这样就可以通过一个 Socket 实例唯一代表一个主机上的一个应用程序的通信链路了。

建立通信链路:

当客户端要与服务端通信,客户端首先要创建一个 Socket 实例,操作系统将为这个 Socket 实例分配一个没有被使用的本地端口号,并创建一个包含本地和远程地址和端口号的套接字数据结构,这个数据结构将一直保存在系统中直到这个连接关闭。在创建 Socket 实例的构造函数正确返回之前,将要进行 TCP 的三次握手协议,TCP 握手协议完成后,Socket 实例对象将创建完成,否则将抛出 IOException 错误。

与之对应的服务端将创建一个 ServerSocket 实例,ServerSocket 创建比较简单只要指定的端口号没有被占用,一般实例创建都会成功,同时操作系统也会为 ServerSocket 实例创建一个底层数据结构,这个数据结构中包含指定监听的端口号和包含监听地址的通配符,通常情况下都是“*”即监听所有地址。之后当调用 accept() 方法时,将进入阻塞状态,等待客户端的请求。当一个新的请求到来时,将为这个连接创建一个新的套接字数据结构,该套接字数据的信息包含的地址和端口信息正是请求源地址和端口。这个新创建的数据结构将会关联到 ServerSocket 实例的一个未完成的连接数据结构列表中,注意这时服务端与之对应的 Socket 实例并没有完成创建,而要等到与客户端的三次握手完成后,这个服务端的Socket 实例才会返回,并将这个 Socket 实例对应的数据结构从未完成列表中移到已完成列表中。所以 ServerSocket 所关联的列表中每个数据结构,都代表与一个客户端的建立的TCP 连接。

TCP短连接

TCP短连接,client向server发起连接请求,server接到请求,然后双方建立连接。client向server 发送消息,server回应client,然后一次读写就完成了,这时候双方任何一个都可以发起close操作,不过一般都是client先发起 close操作。因为一般的server不会回复完client后立即关闭连接的,当然不排除有特殊的情况。从上面的描述看,短连接一般只会在client/server间传递一次读写操作。短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。

TCP长连接

长连接,client向server发起连接,server接受client连接,双方建立连接。Client与server完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

TCP保活功能,保活功能主要为服务器应用提供,服务器应用希望知道客户主机是否崩溃,从而可以代表客户使用资源。如果客户已经消失,使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,则服务器将应远等待客户端的数据,保活功能就是试图在服务器端检测到这种半开放的连接。如果一个给定的连接在两小时内没有任何的动作,则服务器就向客户发一个探测报文段。客户主机必须处于以下4个状态之一:

  1. 客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方是正常的,服务器在两小时后将保活定时器复位。
  2. 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务端将不能收到对探测的响应,并在75秒后超时。服务器总共发送10个这样的探测 ,每个间隔75秒。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
  3. 客户主机崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。
  4. 客户机正常运行,但是服务器不可达,这种情况与2类似,TCP能发现的就是没有收到探查的响应。

从上面可以看出,TCP保活功能主要为探测长连接的存活状况,不过这里存在一个问题,存活功能的探测周期太长,还有就是它只是探测TCP连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。

在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。

长连接和短连接的产生在于client和server采取的关闭策略,具体的应用场景采用具体的策略,没有十全十美的选择,只有合适的选择。

HTTP长连接与短连接

长连接:client方与server方先建立连接,连接建立后不断开,然后再进行报文发送和接收。

这种方式下由于通讯连接一直存在。此种方式常用于P2P通信。

短连接:Client方与server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。

此方式常用于一点对多点通讯。C/S通信。

长连接和短连接异同

长连接:长连接多用于操作频繁,点对点的通讯,而且连接数不能太多的情况。

每个TCP连接的建立都需要三次握手,每个TCP连接的断开要四次握手。

如果每次操作都要建立连接然后再操作的话处理速度会降低,所以每次操作后,下次操作时直接发送数据就可以了,不用再建立TCP连接。例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,频繁的socket创建也是对资源的浪费。

短连接:web网站的http服务一般都用短连接。因为长连接对于服务器来说要耗费一定的资源。像web网站这么频繁的成千上万甚至上亿客户端的连接用短连接更省一些资源。试想如果都用长连接,而且同时用成千上万的用户,每个用户都占有一个连接的话,可想而知服务器的压力有多大。所以并发量大,但是每个用户又不需频繁操作的情况下需要短连接

发送接收方式

  • 异步:报文发送和接收是分开的,相互独立,互不影响的。这种方式又分两种情况: 异步双工:接收和发送在同一个程序中,有两个不同的子进程分别负责发送和接送。 异步单工:接送和发送使用两个不同的程序来完成。
  • 同步:报文发送和接收是同步进行,即报文发送后等待接送返回报文。同步方式一般需要考虑超时问题,试想我们发送报文以后也不能无限等待啊,所以我们要设定一个等待时候。超过等待时间发送方不再等待读返回报文。直接通知超时返回。

阻塞与非阻塞方式

  • 非阻塞方式:读函数不停的进行读动作,如果没有报文接收到,等待一段时间后超时返回,这种情况一般需要指定超时时间。
  • 阻塞方式:如果没有接收到报文,则读函数一直处于等待状态,知道报文到达。

及时通信与游戏的长短连接

实际场合究竟需要使用短连接还是长连接,主要看实时性要求、数据流向和并发量这三个问题。

长连接优点:节约TCP握手时间,可以保证高实时性,数据流向可以采用服务器端的主动推模式。

长连接缺点:并发量不宜太高,持续占用服务端口(相对消耗资源)。

长连接、长轮询一般应用与WebIM、ChatRoom和一些需要及时交互的网站应用中。其真实案例有:WebQQ、Hi网页版、Facebook IM等。

1.现在游戏中的玩家与玩家之间的聊天无法实现实时性,而且系统有邮件或信息时也不能及时的通知玩家

—— 如果涉及到聊天的话,一般来说还是用长连接会更合适,否则大量时间浪费到握手上了;

—— 但是手机的网络长连接网络质量可能会比较撮,你需要严重考虑容错和重链机制。

2.客户端每隔几秒就会发送一个请求,这样服务器的压力岂不是很大?

—— 压力会比较大,关键是聊天往往对时间的要求很高,如果是团战的话,1秒内没看到信息,可能就会觉得完全受不了了;当然也看你聊天的场景如何,是群聊还是单聊,以后会不会发展为语音啥的;

NIO没有任何问题,大规模长连接处理的主流都是用NIO;而且也不是Java发明的,本身就是借助了操作系统的网络管理能力。

http keep-alive与tcp keep-alive,不是同一回事,意图不一样。http keep-alive是为了让tcp活得更久一点,以便在同一个连接上传送多个http,提高socket的效率。而tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制