通过IP地址,端口号,协议号进行通信识别

TCP/IP通常采用5个信息来识别一个通信。它们是,源IP地址,目标IP地址,协议号,源端口号,目标端口号。

server的生命周期大致如下:

1、创建socket。

2、绑定(bind)地址端口

3、监听网络连接

4、接受连接

5、关闭连接

client的生命周期则稍微简单点:

1、创建socket

2、绑定地址

3、发起连接

4、关闭连接

socket与握手细节

握手的连接发生在客户端connect,服务端的accept返回连接。握手的细节其实是客户端connet和服务端的listen过程,而accept只是返回队列里的连接。下面通过nc和wireshaker抓包来分析tcp三次握手和socket的通信细节。

server进行listen监听

listen&accept函数

通过上述的实验,可见tcp三次握手发生在client的connect调用之后,server端的listen函数调用之后,但是并不是由listen函数完成的,listen()的作用仅仅告诉内核一些信息,即连接队列的大小,三次握手是以后内核完成的。一旦完成了三次握手,内核就把连接放入连接队列之中。

当socket对象调用accpet函数的时候,就从连接队列中将tcp连接取出并返回。如果连接队列中没有连接,那么accept函数调用将会阻塞(如果socket是非阻塞模式,accept此时会返回,并触发一个异常)

TCP保活计时器(keepalive timer)

客户已主动与服务器建立TCP连接,但是后来客户端的主机突然出故障了,显然,服务器以后就不能再收到客户端发来的数据,因此,应当有措施,这时就是这个保活计时器,通常是两个小时,服务器每收到一次客户端的数据,就重置这个计时器,若是这个计时器到了,还没有收到客户的数据,服务器就会发送一个探测报文段,75分钟发送一次 ,若一连发送10个探测报文段后仍然无客户的响应,服务器就认为客户端出了故障,接着关闭这个连接。

关闭连接shutdown

如果无论如何都立即关闭终止连接,shutdown系统调用(相对close函数来说,这个是专门为网络编程设计的)

关闭连接close

三次握手其实在socket编程中的listen函数完成的

我以前以为三次握手是在accept函数中,但是最近在处理我程序高并发的时候发现了,其实三次握手是在listen函数中完成的。(再次证明懂底层才是优化的王道)

心跳机制是TCP在一段时间间隔后发送确认连接端是否还存在,如果存在的话就会回传一个包确定网络有效,如果心跳包有问题,则通知上层应用当前网络有问题了。

这取决于你的server端的超时配置, 每个socket连接都是长连接,它是一个相当占用系统资源的通信管道, 如果这个长连接什么事也没干硬是要占着资源,则server端可以选择关闭这个连接,以省下资源让更多的用户连接进来。

所以,即便客户端的是采用死循环while(true)方式连到服务端,对于特定的客户端和服务端类型来说也需要一定时间间隔的心跳(告诉服务端,我还活着,虽然我没干活也没说话,但别把我关了)

心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。

其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。

为什么需要三次握手?

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

为什么要四次分手?

TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

窗口控制与重发控制

首先,我们先考虑确认应答未能返回的情况。在这种情况下,数据已经到达对端,是不需要在进行重发的。然而,在没有使用窗口控制的时候,没有收到确认应答的数据都会被重发。而使用了窗口控制,某些确认应答即便丢失也无需重发。

流量控制

TCP提供一种机制可以让发送端根据接收端的实际接受能力控制发送的数据量。这就是所谓的流量控制。它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不超过这个限度的数据。该大小限度就被称作窗口大小。

在TCP首部中,专门有一个字端用来通知窗口的大小。接收主机将自己可以接收的缓冲区大小放入这个字端中通知发送端。这个字段的值越大,说明网络的吞吐量越大。

拥塞控制

首先,为了在发送端调节所要发送数据的量,定义了一个叫做“拥塞窗口”,于是慢启动的时候,将这个勇拥塞窗口的大小设置为1个数据段,发送数据,之后每收到一次确认应答,拥塞窗口的值就增加1,在发送数据包时,将拥塞窗口的大小与接收端主机通知的窗口大小做比较,然后它们当中较小那个值,发送比其还要小的数据量。

如果重发采用超时机制,那么拥塞窗口的初始值可以设置为1以后再进行慢启动修正。有了上述的机制,就可以有效地减少通信开始时连续发包导致的网络拥堵,还可以避免网络拥塞情况的发生。

TCP以段为单位发送数据

在建立TCP连接的同时,也可以确定发送数据包的单位,我们也可以称其为“最大消息长度”(MSS)。

MSS是在三次握手的时候,在两端主机之间被计算得出。两端的主机在发出建立连接的请求时,会在TCP首部中写入MSS选项,告诉对方自己的借口能够适应的MSS的大小。然后会在两者之间选择一个较小的值投入使用。

利用窗口控制提高速度

窗口大小就是指无需等待确认应答而可以继续发送数据的最大值。这个机制实现了大量的缓冲区,通过对多个段同时进行确认应答的功能,。