在linux执行这一段代码,跟踪他他看信息,查看生命周期
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class IoTest {
public static void main(String args[])throws IOException {
ServerSocket server = new ServerSocket(8090);
System.out.println("step1: new ServerSocket(8090) ");
while (true) {
Socket socket = server.accept();
System.out.println("step2: client\t"+socket.getPort());
new Thread(()->{
try {
InputStream is = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
while (true) {
System.out.println("is: "+reader.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
终端1
/**
*
*
* strace 跟踪
* -ff 克隆 fork进程
* -o 输出
*./ooxx 指定文件
*
*java 监视进程
*./Myproject/io/IoTest 指定class文件
*
*
*
*/
[root@localhost io]# strace -ff -o ./xxoo java IoTest
step1: new ServerSocket(8090)
终端2
[root@localhost io]# javac IoTest.java
[root@localhost io]# ll
总用量 8
-rw-r--r--. 1 root root 1986 6月 15 10:16 IoTest.class
-rw-r--r--. 1 root root 887 6月 15 10:16 IoTest.java
[root@localhost io]# java IoTest
image.png
追踪IoTest的class文件
image.png image.png
追踪到系统调用,然后进去,再第2554行找到了
image.png
image.png
打开第三个终端,追踪线程
image.png
task表示进程里面的所有线程文件
image.png
fd表示文件描述符
任何文件都有io
0:输入
1:输出
2:错误输出
3:运行时的jar包库
4,5是两个socket(ip4和ip6)
image.png
查看网络状态 看到了 进程id6545的java程序 监听者8090端口
image.png
阻塞IO
使用nc作为客户端建立连接之后查看状态
image.png
image.png
这个时候fd多了一个sockte连接
image.png
程序打印
image.png
查看内核状态,追踪系统调用
xxoo.6546
image.png
这段等于
ServerSocket server = new ServerSocket(8090);
image.png
接下来分别是 监听fd5,通过poll阻塞,等到有连接了之后就接收39884端口nc的连接
image.png
是这样的,阻塞在这里(5代表socket状态处于监听)
image.png
image.png
在主线程里面,当新的客户端连接进来,使用clone来创建新的线程出去这个连接(客户端描述符为7 accept返回的结果,clone的返回结果7961,为新的线程的跟踪号)我们来查看一下
image.png image.png
image.png
image.png
客户端向服务端发送消息
服务端接收(write(1)表示打印
image.png
等到有客户端了得到fd6的socket,然后read这个流
image.png
之后再来客户端 ,主线程只负责accept得到文件描述符,之后抛出线程通过子线程去操作 recvfrom的内容,就是如上图所示
image.png
非阻塞IO
select
这是select()多路复用,把所有的文件描述符传入,内核会自动返回可读可写的状态,但是在内核里面会遍历N次文件描述符去检查状态。
image.png
Epoll
内核里面基于事件驱动的被动去自动接收有状态的文件描述符
在内核里面创建一个空间有了新的客户端文件描述符就传进来,比如socket为fd5,
首先创建一个fd8的空间epoll_create fd8
epoll_ctl可以add mod delete,操作指定的文件描述符,所以epoll_ctl(fd8,add,fd5,accept)等待接收
新的客户端
然后等到有事件发生即新的客户端连进来,通过epoll_waite内核就会知道哪个客户端,即监听这个端口,这个方法是一直在轮询执行
然后accept fd5去返回这个客户端,添加到内核里面的fd8空间里,epoll_ctl(fd8,fd6)
image.png
那么是怎么把这些知道客户端的事件呢,把绿色的放到蓝色里面去,这就是靠事件驱动来完成,就是操作系统的中断产生的数据到达,把这些有事件的文件描述符移过去。
image.png
网友评论