Socket之IO系统调用详解
上一篇文章里介绍了目前常用的多路复用机制,偏理论的东西看起来不一定很好理解,所以接下来呢将用几个demo来演示IO(未特殊说明都是同步IO)的发展历程:
Blocking IO -->Non-Blocking IO-->IO Multiplexing
特别强调一下,以上都是系统层面,对于java里常说的NIO指的是New IO,不在上述讨论范围内。
先来一波传统IO的编程模型,一个简单的socket代码如下:
如果还未了解过socket编程可以网上先学习下,这边只是为了演示需要,分析这段代码的系统调用过程,继续秀一波,展示这段代码的执行过程,通过如下命令:
strace -ff -o ./villiam-test java SocketIOSystemCallTest
效果如下:
由上图得知,程序已经运行起来。查看当前目录:
villiam-test前缀后的数字是java线程id,可知,已经启动了这些个线程。通过jps查看:
可知上面启动的java进程id是12593.进入该进程的目录查看,cd /proc/12593
分别进入fd目录(文件描述符):
以上便是该进程的所有文件句柄。
进入task目录:
该进程下的所有java线程。(通过此可以统计一个进程内的所有线程数量)
通过grep查看
查看该线程的系统调用 cat villiam-test.12594,查找 "step1"
调用了系统的write函数,1就是标准输出。如果你对unix的socket的编程了解的话,还可以查看 socket,bind,listen等函数,先看socket函数:
接着查看bind及listen函数:
到此为止,我们的程序还一直在监听等待连接进来,再来一波,通过nc命令来连接8090端口:
服务端日志:
可知,客服端连接通过端口49416与之交互,通过netstat -naop 进行查看
多了一个ESTABLISHED的一条记录,本地端口49416与8090端口建立连接。
查看新增的fd及task:
多了一个文件句柄为6,多了一个线程id12749.
接下来我们来验证上面的信息,查看villiam-test.12594 的文件,查找accept关键字:
环环相扣,通过如上的分析,我们得知java的socket的编程是对系统层的封装,最后我们发现系统层调用poll函数进行阻塞,等待IO相应,并且得知,java的thread在系统层调用的是clone函数:
输入:
相应输出:
看到系统调用的recvfrom函数进行阻塞,等待相应。
最后再带大家学习下几个系统函数,通过man命令。
首先学习man bind ,里面有个例子可以学习:
本篇所讲的内容还都是基于传统的IO模型,也就是阻塞的IO。epoll的模型会通过nginx进行讲解,下回分享~