网络IO模型

实际操作演示

这章介绍下TCP网络通讯协议的工作原理。
首先我们使用Java代码编写一个service端和一个client端,让两者建立通讯。
注:使用环境适用于Linux/Unix环境

我们先来看下Service端:
在这里插入图片描述
我们再Service端定义一个9091端口,新建一个ServerSocket并且绑定9091端口。

下面我们将Service 运行起来:
在这里插入图片描述
现在我们已经在shell中将service run起来了,端口号是9091。请注意此时我们的socket只是绑定了端口号,线程是被System.in.read()方法阻塞住了,也就是后续的accept方法无法执行,不能接收client端发送的数据。

下面我们来看下运行service的这个线程情况:
在这里插入图片描述
得知运行service的线程id是9731,下面我们来观察下9731这个线程的情况:
在这里插入图片描述
由此我们可以得知,service在绑定端口号后,OS就已经在内核中创建了FD(6),用来监听请求,尽管此时service还不能接收客户端的连接。

下面我们来启动client端代码:
在这里插入图片描述
代码也很简单,定义一个socket,连接上服务端的9091端口,后面将控制台输入的数据发给service。现在我们将它启动起来:
在这里插入图片描述
现在我们再来看下9091端口的情况:
在这里插入图片描述
已经多出了一个14086的线程,FD(6),注意client的状态是“ESTABLISHED”,说明此时client已经与service建立了连接,完成了三次握手动作,可以进行数据传输了。

既然连接已经建立可以传输了,那我们就在控制台随便输入些信息试试service能否收到吧:
在这里插入图片描述
很显然,由于service端被read()方法阻塞住了,并不能接收到client端的请求,现在我们在service控制台随便输入内容跳过阻塞:
在这里插入图片描述
此时我们惊奇的发现,service在跳过阻塞之后,竟然收到了client之前连续的3次输入。这说明,虽然service访问没有开始接受client的数据,但是一定有一个地方,帮助我们存贮了3次数据,第一次存储了“hello”,第二次存储了“kkk”,第三次存储了“lll”,然后在service可以接收数据之后,一次性给到了我们service,相信大家一定可以猜到,谁帮我们存储了数据呢,一定是OS,OS在连接三次握手之后,就已经在内存中开辟了缓冲区,分配了资源。
另外大家也一定可以注意到打印出来的client port:56490。如果我们再新起一个client,client的端口号是什么样呢?
在这里插入图片描述
所以client的端口号,应该是随机生成的。

通信

基于上面的演示,我们可以给TCP一个简单的描述:
TCP是基于连接可靠传输协议,只要经过三次握手之后,发送了数据,即便service端还没有开始工作,数据一样是可以到达。
这是由于在经历过三次握手之后,OS内核就已经开辟空间进行资源分配了

三次握手

在这里插入图片描述
1.client ------> service : 小姐姐,我想和你处个对象,你那边有没有问题?
2.service ---->client: 小哥哥,我这边没有问题,你那边有没有问题?
3.client ----->service : 小姐姐,我这边没有问题,我准备把礼物给你送过来喽!!
三次握手完成之后,client(小哥哥)这边os分配资源,准备礼物(分配资源,准备发送数据),
service(小姐姐)这边os也分配资源,收拾整理下屋子腾出空间来准备接收小哥哥的礼物(数据)。

连接唯一性

我们还以上面的socket上连接为例,当service连接了两个client之后:
在这里插入图片描述
我们可以看到,在service中分配了一个id为9731的线程,同时拥有3个FD,分别用来做三件事情:
在这里插入图片描述
client1分配FD(6),ip地址:xx1,端口号:yy1
client2分配FD(6),ip地址:xx2,端口号:yy2
service,ip:xx3,端口号yy3。为了监听所有client的连接,分配FD(6),为了接收处理client1请求,分配FD(7),为了接收处理client2请求,分配FD(8)

如此,整个socket请求,连接有两种组合:
xx1-yy1-xx3-yy3,
xx2-yy2-xx3-yy3.

socket是一个四元组数据,包含client的ip和端口号,以及service的ip和端口号。
在service端,每接收到一个client,便会分配一个唯一的FD去标识处理这个请求。

那现在已经搞清楚了连接的唯一性标识,那os又是如何介入的呢?在这里插入图片描述
每一个client在与service三次握手之后,service端的os便会依据socket的四要素,在内核空间创建出一个socket,同时为该socket分配buffer,同时会为该socket分配一个唯一的文件描述符FD,当service后一个处理线程accept()了这个socket之后,后续处理时只要根据FD便可以找到对应的socket以及数据。

client端的逻辑也service也是类似。

BackLog,TimeOut

同一时间,不同client是否可以无限次发起连接请求呢,也即发起三次握手?这样肯定是不行的,因为一旦握手成功,不管后续client是否发送请求过来,service端os都会分配资源,一旦同时又大量的握手成功,service会有风险。可以设置BackLog来限定最大握手数量,超过阈值将会握手失败。
同理为了解决IO读写超时,处理超时等,可以设置timeout属性,防止某些原因造成线程死等待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值