TCP连接过程解析

2 篇文章 0 订阅
1 篇文章 0 订阅

本文讲解传统Socket,而java中新的NIO和这里讲的稍微有所区别。以ppt的形式展现。


第一步:建立连接

•       我们做的事情:
Socket socket = new Socket("10.255.209.45", 1111) 

•       操作系统做的事情:
三次握手

 





Socket建立连接时发生了什么

 






第一步:建立连接时的seq

•       建立连接时生成的seq可以是随机的,也可以是动态增长并循环的

•       双方的seq不相关

•       自己发送syn、ack时seq会加1,对方回复ack的时候回带上原来的seq以便区分ack哪个包

•       发送普通数据包,seq增加数据包字节数,接收端据此将数据放入缓冲区不同offset处

•       只ack最大的连续收到的包,例如收到1/2/5,回复ack 2即可

 




对端不存在会怎样?

–    Socket socket = new Socket(“不存在的ip",1111)

–     java.net.ConnectException:Connection timed out




 


对端端口没有应用在监听会怎样?

–    Socket socket = new Socket(“正确的ip",1111)

–     java.net.ConnectException:Connection refused

 






 

•        连接超时时间配置

–     Socket socket = new Socket();

–     InetSocketAddress addr = new InetSocketAddress("10.255.209.45",111);


–     socket.connect(addr);

–     socket.connect(addr, 0); 

–     二者效果等同,都是由OS的参数决定等待多久没连接上就算超时

 

 


 

 



•        从以上俩图可以看出,没有设置连接超时时间时使用SO_TIMEOUT参数 

•        SO_TIMEOUT也可能会为0,此时取决于操作系统的实现,但也不会无限等待,最多2MSL,或路由等网络设备返回目标不可达,或对端返回RST连接重置标志 

•        2MSL在Linux 2.6中固定为60s

 







•        连接超时时间配置

–     Socket socket = new Socket();

–     InetSocketAddress addr = new InetSocketAddress("10.255.209.45",111);

–     socket.connect(addr,  10 * 1000); // 10s 

•        超时时间为0,使用阻塞模式,OS返回连接结果状态

•        超时时间大于0,使用非阻塞模式,OS返回后在jvm中等待超时

 


从下图可看出,连接超时时间大于0的时候,会首先设置连接为非阻塞模式,并等待特定时间,直至连接成功或超时;最后再将连接设置为非阻塞模式。


 


 

连接超时和so_timeout的区别

 







so_timeout干嘛的

•        socket. getInputStream

–     Return new SocketInputStream(this);

•        socket.setOption

–     switch (opt) {

–     case SO_TIMEOUT:

–     timeout = tmp; break;

•        socketInputStream.read

–     return read(b, off, length, impl.getTimeout());

 

•        so_timeout: OS等待直到输入缓冲区有数据

 

 




连接超时、so_timeout二者区别

•        连接超时时间限制三次握手建立连接的总时间(发送sync,收到ack的时间之和),不包括三次握手的第三步。

•        后者限制对方何时必须完成业务层处理,返回结果给发送方。

 




 

为什么先建立连接后传输数据?

•        协商最大包大小:双方缓冲区大小、中间路由设备会影响此值

•        协商滑动窗口大小、对方是否支持特定功能、计算Round trip time等

•        确定一个序号,后续发送数据包时顺序递增,以便进行丢包重传,在接收端重组接收到的乱序的报文

•        确认双向链路均正常(防火墙可能限制)

•        等等

 





为什么需要关闭连接? 

•        释放双方占用的内存、端口号等资源 

•        避免上一个连接的数据包被下一个连接收到

 

 



关闭过程:

 






同时关闭:






 

close_wait怎么解决

•        原因:对端关闭连接后,自己没有关闭连接,导致自己这边的状态为close_wait

•        很少出现

•        查代码去

 



 





主动发起关闭的一方出现FIN_WAIT_2 、TIME_WAIT

•        主动调用close的一方会出现time_wait

–     Socket socket = new Socket();

socket.close(); 

–     Socket socket =serverSocket.accept();

socket.close();

•        主动A调用close的一方进入FIN_WAIT_2状态,对方B也调用close后,A进入TIME_WAIT状态,等待2MSL防止对方没收到最后的ack 

•        2MSL在Linux 2.6中固定为60s

 

 

解决FIN_WAIT_2

•        出现FIN_WAIT_2原因:对方没有调用close 

•        办法:

–     1、检查对方代码;

–     2、修改OS的参数“net.ipv4.tcp_fin_timeout”,Linux默认60秒,超时后强制关闭,转换到CLOSED

 

 


解决TIME_WAIT办法1:暴力关闭

•        SO_LINGER选项:

–     设置为true,并在应用代码中自定义超时时间,达到超时时间或收到对方回复后强制关闭连接,且给对方发送RST信息。设置为0立即强制关闭。默认false,调用close时立即返回,进入FIN_WAIT_1

 




解决TIME_WAIT办法2:调整OS参数

•        用OS参数解决:

–     net.ipv4.ip_local_port_range:增加可用端口范围

•     客户端有效
•     服务器(ServerSocket)端TIME_WAIT不会占用端口

–     net.ipv4.tcp_max_tw_buckets:超过此数的TIME_WAIT端口立即被清除,之后可使用

–    net.ipv4.tcp_tw_recycle:2RTT内回收端口

–    net.ipv4.tcp_tw_reuse:允许重用TIME_WAIT端口

–     sysctl –wnet.netfilter.nf_conntrack_tcp_timeout_time_wait=1

–     net.inet.tcp.msl控制time_wait时长(FreeBSD)

–     Windows可在注册表修改参数

 




解决TIME_WAIT办法3:迂回

•        出现TIME_WAIT原因:防止对方没收到最后的ack 

•        解决办法:

–     1、使用长连接,socket不调用close,所以就不会产生TIME_WAIT,而是一直处于ESTABLISHED

–     2、自己不主动close,让对方close

–     3、将必须使用大量短连接的应用分拆,部署到不同的物理机或虚拟机

 




其他socket选项(在代码中使用的叫做选项)

•        TCP_NODELAY:

–     默认false,如果每次向输入缓冲区写入数据较少,OS会等达到特定大小,或超过一定时间后再发送这些数据;

–     设置为true,则不论写入多少数据都一次发送出去

•        TCP_CORK:暂停TCP_NODELAY的作用最多200ms 

•        TCP_LINGER2:

–     作用同tcp_fin_timeout,由应用设置而不是OS参数 

•        提示:NIO中的SocketChannel也可以和Socket一样设置选项

 




其他socket参数(在OS调整的叫做参数)

•        tcp_abort_on_overflow:OS处理不了就抛弃连接请求,避免被DOS攻击(默认为disabled) 

•        tcp_max_syn_backlog:收到syn回复ack后放入syn队列,表示半连接,超过此值的syn被丢弃;或表示OS已建立连接但应用没有accept的最大连接数(默认值有固定算法) 

•        tcp_syn_retries:发送多少次syn都没有收到ack后认定为无法连接

•        tcp_synack_retries:收到syn后回复ack多少次后再收到syn则丢弃

•        net.core.somaxconn:最大连接数

 



其他资料

•        man手册

–     man sendfile:zero-copy技术

–     man tcp:

•     tcp讲解,找到man手册的SEE ALSO部分,有相关的命令;
•     继续用man命令查看,以此类推,可熟悉tcp相关的大多数知识

–     man udp/man ip/man socket/man route

•        tcp/ip详解,卷一:协议

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值