说到IO模型,先来了解几个专用术语:
我们平时说的阻塞或非阻塞是指应用程序在发起 I/O 操作时,是立即返回还是等待。而同步和异步,是指应用程序在与内核通信时,数据从内核空间到应用空间的拷贝,是由内核主动发起还是由应用程序来触发。
有异步阻塞模型吗?
没有,都异步了,还要阻塞?有病吧!
观察IO模型过程中用到的指令:
strace -ff -o out cmd
-ff 捕捉所有线程
-o 捕捉到的每个线程的输出文件以什么开头
cmd 捕捉的命令,比如 java -jar
服务端code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketBIOServer4JDK1_4 {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(9090, 20);
System.out.println("step1: new ServerSocket(9090) ");
for (; ; ) {
Socket client = server.accept(); //阻塞1
System.out.println("step2:client\t" + client.getPort());
new MyThread(client).start();
}
}
private static class MyThread extends Thread {
private Socket client;
public MyThread(Socket client) {
this.client = client;
}
public void run() {
InputStream in = null;
try {
in = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
String dataline = reader.readLine(); //阻塞2
if (null != dataline) {
System.out.println(dataline);
} else {
client.close();
break;
}
}
System.out.println("客户端断开");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
启动服务端代码
使用jdk1.4编译
/usr/lib/jdk.1.4.2/bin/javac SocketBIOServer4JDK1_4.java
strace -ff -o out /usr/lib/jdk.1.4.2/bin/javac SocketBIOServer4JDK1_4
此时服务端只是起了一个9090端口的LISTEN
[root@optimize-node01 netio]# netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 6729/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 6859/master
tcp 0 0 10.0.0.5:22 10.0.0.1:6628 ESTABLISHED 8258/sshd: root@pts
tcp 0 0 10.0.0.5:22 10.0.0.1:2569 ESTABLISHED 7471/sshd: root@pts
tcp 0 52 10.0.0.5:22 10.0.0.1:6627 ESTABLISHED 8238/sshd: root@pts
tcp6 0 0 :::22 :::* LISTEN 6729/sshd
tcp6 0 0 ::1:25 :::* LISTEN 6859/master
tcp6 0 0 :::9090 :::* LISTEN 8542/java
使用lsof -p pid查看8542进程的文件描述符
[root@optimize-node01 netio]# lsof -p 8542
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 8542 root cwd DIR 253,0 145 51428137 /opt/io/netio
java 8542 root rtd DIR 253,0 256 64 /
java 8542 root txt REG 253,0 64940 401302 /usr/lib/jdk.1.4.2/bin/java
java 8542 root mem REG 253,0 769342 17325867 /usr/lib/jdk.1.4.2/jre/lib/ext/localedata.jar
java 8542 root mem REG 253,0 67964 51665590 /usr/lib/jdk.1.4.2/jre/lib/i386/libnet.so
java 8542 root mem REG 253,0 54665 17325869 /usr/lib/jdk.1.4.2/jre/lib/ext/activation.jar
java 8542 root mem REG 253,0 106176928 51704868 /usr/lib/locale/locale-archive
java 8542 root mem REG 253,0 53248 17325868 /usr/lib/jdk.1.4.2/jre/lib/ext/ldapsec.jar
java 8542 root mem REG 253,0 153117 17325866 /usr/lib/jdk.1.4.2/jre/lib/ext/mailapi.jar
java 8542 root mem REG 253,0 280984 17325861 /usr/lib/jdk.1.4.2/jre/lib/ext/mail.jar
java 8542 root mem REG 253,0 111430 17325863 /usr/lib/jdk.1.4.2/jre/lib/ext/sunjce_provider.jar
java 8542 root mem REG 253,0 8674 17325865 /usr/lib/jdk.1.4.2/jre/lib/ext/jta.jar
java 8542 root mem REG 253,0 5896381 51665554 /usr/lib/jdk.1.4.2/jre/lib/charsets.jar
java 8542 root mem REG 253,0 69571 51665597 /usr/lib/jdk.1.4.2/jre/lib/jce.jar
java 8542 root mem REG 253,0 901949 51665532 /usr/lib/jdk.1.4.2/jre/lib/jsse.jar
java 8542 root mem REG 253,0 89343 51665529 /usr/lib/jdk.1.4.2/jre/lib/sunrsasign.jar
java 8542 root mem REG 253,0 26910912 51665536 /usr/lib/jdk.1.4.2/jre/lib/rt.jar
java 8542 root mem REG 253,0 90040 51665579 /usr/lib/jdk.1.4.2/jre/lib/i386/libzip.so
java 8542 root mem REG 253,0 142076 51665589 /usr/lib/jdk.1.4.2/jre/lib/i386/libjava.so
java 8542 root mem REG 253,0 70980 51665581 /usr/lib/jdk.1.4.2/jre/lib/i386/libverify.so
java 8542 root mem REG 253,0 54464 17096577 /usr/lib/libnss_files-2.17.so
java 8542 root mem REG 253,0 11902 17325864 /usr/lib/jdk.1.4.2/jre/lib/ext/smtp.jar
java 8542 root mem REG 253,0 8896 17325862 /usr/lib/jdk.1.4.2/jre/lib/ext/dnsns.jar
java 8542 root mem REG 253,0 16384 17289127 /tmp/hsperfdata_root/8542
java 8542 root mem REG 253,0 304600 17325561 /usr/lib/libm-2.17.so
java 8542 root mem REG 253,0 112580 17325563 /usr/lib/libnsl-2.17.so
java 8542 root mem REG 253,0 5224816 903979 /usr/lib/jdk.1.4.2/jre/lib/i386/client/libjvm.so
java 8542 root mem REG 253,0 2107596 16829797 /usr/lib/libc-2.17.so
java 8542 root mem REG 253,0 17716 17325559 /usr/lib/libdl-2.17.so
java 8542 root mem REG 253,0 133736 17380605 /usr/lib/libpthread-2.17.so
java 8542 root mem REG 253,0 33188 33684676 /usr/lib/jdk.1.4.2/jre/lib/i386/native_threads/libhpi.so
java 8542 root mem REG 253,0 158768 17325529 /usr/lib/ld-2.17.so
java 8542 root 0u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 1u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 2u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 3u IPv6 89489 0t0 TCP *:websm (LISTEN)
java 8542 root 4u sock 0,7 0t0 89487 protocol: TCPv6
3号文件描述符启动了LISTEN监听,肯定是对应9090端口的监听(稍后在后面的out输出文件里会看到)
回到我们启动程序的目录查看,已经多了很多out输出文件,out.后面的数字就代表线程id,可见我们启动这一个java进程的同时也启动了很多java线程(GC线程,main线程…)
此时这个LISTEN在操作系统层面对应了三个系统调用socket,bind,listen
可通过以下三个命令进行查看,需要安装yum install -y man
man 2 socket
man 2 bind
man 2 listen
如果想在追踪的系统调用中看到的话,需要低版本的java,
windows版本
linux版本
linux版本扔到服务器直接解压使用即可
[root@optimize-node01 netio]# ll
total 17104
drwxr-xr-x 3 root root 19 Jul 2 20:47 org
-rw-r--r-- 1 root root 175691 Jul 6 08:48 out.8542
-rw-r--r-- 1 root root 371013 Jul 6 09:09 out.8543
-rw-r--r-- 1 root root 1295 Jul 6 08:48 out.8544
-rw-r--r-- 1 root root 1488 Jul 6 08:48 out.8545
-rw-r--r-- 1 root root 1313 Jul 6 08:48 out.8546
-rw-r--r-- 1 root root 1546 Jul 6 08:48 out.8547
-rw-r--r-- 1 root root 20243 Jul 6 08:48 out.8548
-rw-r--r-- 1 root root 8761142 Jul 6 09:09 out.8549
out.8542对应我们的main线程
其他对应的是工作线程
我们只需关注8542对应的主线程输出即可
我们在主线程里输出了 step1: new ServerSocket(9090)
同样,在out.8542里如果找到这个输出,就证明8542就是主线程id
通过查看文件,找到write(1, "step1: new ServerSocket(9090) ", 30) = 30,你的文件里跟我的不会完全一致
我们继续观察我们的程序和内核有哪些系统调用
可在文件中找到以下内容
回到我们的程序:Socket client = server.accept(); 这里的accept()就会调用内核的accept进行阻塞
这里accept的第一个参数是3,这个3是文件描述符,这里也跟我们上面使用lsof命令看到的文件描述符对应上了
accept(3, {sa_family=AF_INET6, sin6_port=htons(34450), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope _id=0}, [28]) = 5
我们继续跟踪上面的文件描述符3,既然accept接收这个参数,这个参数肯定是out.8542文件中上面的步骤生成的,通过查找,可以找到以下几行
socket(AF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET6, sin6_port=htons(9090), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=htonl(0)}, 24) = 0
listen(3, 20)
可以看到bind和listen都会使用到3这个文件描述符,3是被socket这个系统调用生成的
ServerSocket server = new ServerSocket(9090);
我们在程序里是使用上述代码来监听9090端口的,可见,在BIO时代,JVM会为我们调用socket,bind,listen三个系统调用来完成上述代码的监听,也就是说通过socket创建一个文件描述符(linux里一切皆文件),调用bind将文件描述符3和端口9090绑定,调用listen对文件描述符3进行监听
可以说:任何的程序只要做服务端,这三个系统调用是必须的,无论是在什么IO模型下,这个三个系统调用完成之后,可以通过accept系统调用去接收客户端的连接
此时,我们的服务端程序还阻塞在accept处,还没有client连接进来
我们此时监控out.8542文件的输出
[root@optimize-node01 netio]# strace -ff -o out /usr/lib/jdk.1.4.2/bin/java org/itliu/sysio/bio/SocketBIOServer4JDK1_4
step1: new ServerSocket(9090)
[root@optimize-node01 netio]# tail -f out.8542
listen(3, 20) = 0
write(1, "step1: new ServerSocket(9090) ", 30) = 30
write(1, "\n", 1) = 1
gettimeofday({tv_sec=1594039721, tv_usec=148811}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148843}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148871}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148995}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149050}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149185}, NULL) = 0
accept(3,
模拟client的连接,在另一台机器操作,输出会更明显
[root@optimize-node02 ~]# nc 10.0.0.5 9090
此时server的输出,接收到了client 48734的连接
[root@optimize-node01 netio]# strace -ff -o out /usr/lib/jdk.1.4.2/bin/java org/itliu/sysio/bio/SocketBIOServer4JDK1_4
step1: new ServerSocket(9090)
step2:client 48734
同时,我们的另一个监听out.8542的窗口也同步发生变化
[root@optimize-node01 netio]# tail -f out.8542
listen(3, 20) = 0
write(1, "step1: new ServerSocket(9090) ", 30) = 30
write(1, "\n", 1) = 1
gettimeofday({tv_sec=1594039721, tv_usec=148811}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148843}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148871}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148995}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149050}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149185}, NULL) = 0
accept(3, {sa_family=AF_INET6, sin6_port=htons(48734), inet_pton(AF_INET6, "::ffff:10.0.0.6", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, [28]) = 5
gettimeofday({tv_sec=1594042173, tv_usec=263776}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=264111}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=264331}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=273727}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=273836}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=274055}, NULL) = 0
write(1, "step2:client\t48734", 18) = 18
write(1, "\n", 1) = 1
gettimeofday({tv_sec=1594042173, tv_usec=274384}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=274419}, NULL) = 0
stat64("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
open("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", O_RDONLY|O_LARGEFILE) = 6
fstat64(6, {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
stat64("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
read(6, "\312\376\272\276\0\0\0.\0A\n\0\20\0\33\t\0\17\0\34\n\0\35\0\36\7\0\37\7\0 \n"..., 1062) = 1062
close(6) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275336}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275478}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275562}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275623}, NULL) = 0
mmap2(NULL, 528384, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xe9dc3000
mprotect(0xe9dc3000, 4096, PROT_NONE) = 0
clone(child_stack=0xe9e43424, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xe9e43ba8, tls={entry_number=12, base_addr=0xe9e43b40, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}, child_tidptr=0xe9e43ba8) = 8619
futex(0x838e57c, FUTEX_WAIT_PRIVATE, 1, NULL) = 0
futex(0x838e42c, FUTEX_WAKE_PRIVATE, 1) = 0
sched_setscheduler(8619, SCHED_OTHER, [5]) = -1 EINVAL (Invalid argument)
futex(0x838e5dc, FUTEX_CMP_REQUEUE_PRIVATE, 1, 2147483647, 0x838e3fc, 2) = 1
accept(3,
对比我们上面tail -f 时的输出,多了很多次系统调用
我们观察上面的输出,有两个accept,第一个accept就是我们第一次使用tail -f 命令输出时阻塞接收client的时候,可以看到这个accept接收了一个端口号为48734,地址为10.0.0.6的连接,与我们服务端的输出对应,而第二个accept同样阻塞再次等待新的连接;并且10.0.0.6:48734这个连接对应的描述符为5
继续使用lsof -p 查看进程的文件描述符
[root@optimize-node01 netio]# lsof -p 8542
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 8542 root cwd DIR 253,0 161 51428137 /opt/io/netio
java 8542 root rtd DIR 253,0 256 64 /
java 8542 root txt REG 253,0 64940 401302 /usr/lib/jdk.1.4.2/bin/java
java 8542 root mem REG 253,0 769342 17325867 /usr/lib/jdk.1.4.2/jre/lib/ext/localedata.jar
java 8542 root mem REG 253,0 67964 51665590 /usr/lib/jdk.1.4.2/jre/lib/i386/libnet.so
java 8542 root mem REG 253,0 54665 17325869 /usr/lib/jdk.1.4.2/jre/lib/ext/activation.jar
java 8542 root mem REG 253,0 106176928 51704868 /usr/lib/locale/locale-archive
java 8542 root mem REG 253,0 53248 17325868 /usr/lib/jdk.1.4.2/jre/lib/ext/ldapsec.jar
java 8542 root mem REG 253,0 153117 17325866 /usr/lib/jdk.1.4.2/jre/lib/ext/mailapi.jar
java 8542 root mem REG 253,0 280984 17325861 /usr/lib/jdk.1.4.2/jre/lib/ext/mail.jar
java 8542 root mem REG 253,0 111430 17325863 /usr/lib/jdk.1.4.2/jre/lib/ext/sunjce_provider.jar
java 8542 root mem REG 253,0 8674 17325865 /usr/lib/jdk.1.4.2/jre/lib/ext/jta.jar
java 8542 root mem REG 253,0 5896381 51665554 /usr/lib/jdk.1.4.2/jre/lib/charsets.jar
java 8542 root mem REG 253,0 69571 51665597 /usr/lib/jdk.1.4.2/jre/lib/jce.jar
java 8542 root mem REG 253,0 901949 51665532 /usr/lib/jdk.1.4.2/jre/lib/jsse.jar
java 8542 root mem REG 253,0 89343 51665529 /usr/lib/jdk.1.4.2/jre/lib/sunrsasign.jar
java 8542 root mem REG 253,0 26910912 51665536 /usr/lib/jdk.1.4.2/jre/lib/rt.jar
java 8542 root mem REG 253,0 90040 51665579 /usr/lib/jdk.1.4.2/jre/lib/i386/libzip.so
java 8542 root mem REG 253,0 142076 51665589 /usr/lib/jdk.1.4.2/jre/lib/i386/libjava.so
java 8542 root mem REG 253,0 70980 51665581 /usr/lib/jdk.1.4.2/jre/lib/i386/libverify.so
java 8542 root mem REG 253,0 54464 17096577 /usr/lib/libnss_files-2.17.so
java 8542 root mem REG 253,0 11902 17325864 /usr/lib/jdk.1.4.2/jre/lib/ext/smtp.jar
java 8542 root mem REG 253,0 8896 17325862 /usr/lib/jdk.1.4.2/jre/lib/ext/dnsns.jar
java 8542 root mem REG 253,0 16384 17289127 /tmp/hsperfdata_root/8542
java 8542 root mem REG 253,0 304600 17325561 /usr/lib/libm-2.17.so
java 8542 root mem REG 253,0 112580 17325563 /usr/lib/libnsl-2.17.so
java 8542 root mem REG 253,0 5224816 903979 /usr/lib/jdk.1.4.2/jre/lib/i386/client/libjvm.so
java 8542 root mem REG 253,0 2107596 16829797 /usr/lib/libc-2.17.so
java 8542 root mem REG 253,0 17716 17325559 /usr/lib/libdl-2.17.so
java 8542 root mem REG 253,0 133736 17380605 /usr/lib/libpthread-2.17.so
java 8542 root mem REG 253,0 33188 33684676 /usr/lib/jdk.1.4.2/jre/lib/i386/native_threads/libhpi.so
java 8542 root mem REG 253,0 158768 17325529 /usr/lib/ld-2.17.so
java 8542 root 0u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 1u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 2u CHR 136,1 0t0 4 /dev/pts/1
java 8542 root 3u IPv6 89489 0t0 TCP *:websm (LISTEN)
java 8542 root 4u sock 0,7 0t0 89487 protocol: TCPv6
java 8542 root 5u IPv6 89490 0t0 TCP bogon:websm->bogon:48734 (ESTABLISHED)
可以看到最后一行,文件描述符5,对应的是一个端口为48734的TCP连接
看到这里,对应到程序里,还只是停留在下面这句代码的输出,再后面的代码还在被阻塞
System.out.println("step2:client\t" + client.getPort());
后面的代码我们使用的是多线程的方式,new了一个Thread来进行处理的,继续追踪上面tail -f out.8542的输出,为了方便,我将上一次的输出贴到下面
accept(3, [root@optimize-node01 netio]# tail -f out.8542
listen(3, 20) = 0
write(1, "step1: new ServerSocket(9090) ", 30) = 30
write(1, "\n", 1) = 1
gettimeofday({tv_sec=1594039721, tv_usec=148811}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148843}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148871}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=148995}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149050}, NULL) = 0
gettimeofday({tv_sec=1594039721, tv_usec=149185}, NULL) = 0
accept(3, {sa_family=AF_INET6, sin6_port=htons(48734), inet_pton(AF_INET6, "::ffff:10.0.0.6", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, [28]) = 5
gettimeofday({tv_sec=1594042173, tv_usec=263776}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=264111}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=264331}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=273727}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=273836}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=274055}, NULL) = 0
write(1, "step2:client\t48734", 18) = 18
write(1, "\n", 1) = 1
gettimeofday({tv_sec=1594042173, tv_usec=274384}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=274419}, NULL) = 0
stat64("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
open("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", O_RDONLY|O_LARGEFILE) = 6
fstat64(6, {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
stat64("/opt/io/netio/org/itliu/sysio/bio/SocketBIOServer4JDK1_4$MyThread.class", {st_mode=S_IFREG|0644, st_size=1062, ...}) = 0
read(6, "\312\376\272\276\0\0\0.\0A\n\0\20\0\33\t\0\17\0\34\n\0\35\0\36\7\0\37\7\0 \n"..., 1062) = 1062
close(6) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275336}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275478}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275562}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=275623}, NULL) = 0
mmap2(NULL, 528384, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xe9dc3000
mprotect(0xe9dc3000, 4096, PROT_NONE) = 0
clone(child_stack=0xe9e43424, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xe9e43ba8, tls={entry_number=12, base_addr=0xe9e43b40, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}, child_tidptr=0xe9e43ba8) = 8619
futex(0x838e57c, FUTEX_WAIT_PRIVATE, 1, NULL) = 0
futex(0x838e42c, FUTEX_WAKE_PRIVATE, 1) = 0
sched_setscheduler(8619, SCHED_OTHER, [5]) = -1 EINVAL (Invalid argument)
futex(0x838e5dc, FUTEX_CMP_REQUEUE_PRIVATE, 1, 2147483647, 0x838e3fc, 2) = 1
accept(3,
从之前分析的第一个accept继续往下找,可以看到下面这个系统调用,通过clone克隆了一个线程,它的返回值返回了8619,此处也证明了java中的线程就是对应了内核中的一个线程。
clone(child_stack=0xe9e43424, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xe9e43ba8, tls={entry_number=12, base_addr=0xe9e43b40, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}, child_tidptr=0xe9e43ba8) = 8619
此时查看我们之前查看out文件的目录下,可见新生成了out.8619文件,这个8619就是上面的clone的结果,也是我们程序里new Thread的结果
[root@optimize-node01 netio]# ll
total 34008
drwxr-xr-x 3 root root 19 Jul 2 20:47 org
-rw-r--r-- 1 root root 177999 Jul 6 09:29 out.8542
-rw-r--r-- 1 root root 974275 Jul 6 09:44 out.8543
-rw-r--r-- 1 root root 1295 Jul 6 08:48 out.8544
-rw-r--r-- 1 root root 1488 Jul 6 08:48 out.8545
-rw-r--r-- 1 root root 1313 Jul 6 08:48 out.8546
-rw-r--r-- 1 root root 1546 Jul 6 08:48 out.8547
-rw-r--r-- 1 root root 20243 Jul 6 08:48 out.8548
-rw-r--r-- 1 root root 23053498 Jul 6 09:44 out.8549
-rw-r--r-- 1 root root 1917 Jul 6 09:29 out.8619
现在开始观察out.8619的系统调用,可以看到停留在recv(5,这个系统调用的地方,如果你没有进行操作的话,可以查看下面的内容,此时内容是out.8619的全部内容
set_robust_list(0xe9e43bb0, 12) = 0
sched_getaffinity(8619, 32, [0, 1, 2, 3]) = 32
mmap2(0xe9dc8000, 40960, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe9dc8000
sigaltstack({ss_sp=0xe9dc8000, ss_flags=0, ss_size=40960}, NULL) = 0
rt_sigaction(SIGHUP, NULL, {sa_handler=0xf730bfa8, sa_mask=~[KILL STOP RTMIN RT_1], sa_flags=SA_RESTART|SA_SIGINFO}, 8) = 0
rt_sigaction(SIGINT, NULL, {sa_handler=0xf730bfa8, sa_mask=~[KILL STOP RTMIN RT_1], sa_flags=SA_RESTART|SA_SIGINFO}, 8) = 0
rt_sigaction(SIGTERM, NULL, {sa_handler=0xf730bfa8, sa_mask=~[KILL STOP RTMIN RT_1], sa_flags=SA_RESTART|SA_SIGINFO}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [HUP INT QUIT USR2 TERM CHLD], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [QUIT], NULL, 8) = 0
futex(0x838e57c, FUTEX_CMP_REQUEUE_PRIVATE, 1, 2147483647, 0x838e42c, 2) = 1
futex(0x838e5dc, FUTEX_WAIT_PRIVATE, 1, NULL) = 0
futex(0x838e3fc, FUTEX_WAKE_PRIVATE, 1) = 0
sched_getaffinity(8619, 32, [0, 1, 2, 3]) = 32
sched_getaffinity(8619, 32, [0, 1, 2, 3]) = 32
mmap2(0xe9dd2000, 12288, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xe9dd2000
mprotect(0xe9dd2000, 12288, PROT_NONE) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278100}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278146}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278180}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278238}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278276}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278383}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278759}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278854}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=278885}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=279001}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=279074}, NULL) = 0
gettimeofday({tv_sec=1594042173, tv_usec=279201}, NULL) = 0
recv(5,
后面就是读取client的消息,继续接收新的连接了