Java|从操作系统层面分析 Java IO 演进之路( 五 )


bind(20 {sa_family=AF_INET sin_port=htons(8023) sin_addr=inet_addr(\"0.0.0.0\") 16) = 0listen(20 128) = 0getsockname(20 {sa_family=AF_INET sin_port=htons(8023) sin_addr=inet_addr(\"0.0.0.0\") [16
) = 0getsockname(20 {sa_family=AF_INET sin_port=htons(8023) sin_addr=inet_addr(\"0.0.0.0\") [16
) = 0 ##将fd为7号epoll和fd为20号的socket绑定 , 事件:epoll_ctl_add和epoll_ctl_modepoll_ctl(7 EPOLL_CTL_ADD 20 {EPOLLIN {u32=20 u64=14198059139132817428) = 0epoll_ctl(7 EPOLL_CTL_MOD 20 {EPOLLIN {u32=20 u64=20) = 0epoll_wait(7 [{EPOLLIN {u32=5 u64=17295150779149058053
8192 1000) = 1epoll_wait(7 [
8192 1000) = 0(不断轮训 , 1S超时一次) 概括为:
将上一步中main线程创建的fd:20绑定端口8023 , 并开启监听(网卡负责监听和接受连接和数据 , kernel则负责路由到具体进程 , 具体参见:关于socket和bind和listen , TODO ) 。 将7号socket对应的fd绑定到20号对应的epoll数据结构上去(都是操作kernel中的内存) 。 开始1S中一次阻塞等待epoll有任何连接或数据到达 。 3 客户端连接
boss (23130)
accept(20 {sa_family=AF_INET sin_port=htons(11144) sin_addr=inet_addr(\"42.120.74.122\") [16
) = 24getsockname(24 {sa_family=AF_INET sin_port=htons(8023) sin_addr=inet_addr(\"192.168.0.120\") [16
) = 0getsockname(24 {sa_family=AF_INET sin_port=htons(8023) sin_addr=inet_addr(\"192.168.0.120\") [16
) = 0setsockopt(24 SOL_TCP TCP_NODELAY [1
4) = 0getsockopt(24 SOL_SOCKET SO_SNDBUF [87040
[4
) = 0getsockopt(24 SOL_SOCKET SO_SNDBUF [87040
[4
) = 0##抛出 work线程clone(child_stack=0x7fc3c4c98fb0 flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID parent_tidptr=0x7fc3c4c999d0 tls=0x7fc3c4c99700 child_tidptr=0x7fc3c4c999d0) = 2301 worker (2301)
writev(24 [{\"Welcome to iZbp14e1g9ztpshfrla9m\"... 37 {\"It is Sun Aug 23 15:44:14 CST 20\"... 41
2) = 78epoll_ctl(13 EPOLL_CTL_ADD 24 {EPOLLIN {u32=24 u64=24) = 0epoll_ctl(13 EPOLL_CTL_MOD 24 {EPOLLIN {u32=24 u64=14180008216221450264) = 0epoll_wait(13 [{EPOLLIN {u32=11 u64=17042151607409573899
8192 1000) = 1 read(11 \"\\1\" 128) = 1##开始无限loopepoll_wait(13 [
8192 1000) = 0epoll_wait(13 [{EPOLLIN {u32=24 u64=24
8192 1000) = 1 概括:
当BOSS轮训epoll_wait等到了连接后 , 首先accept得到该socket对应的fd 。 连接建立后 BOSS立马抛出一个线程(clone函数) 。 worker(即新建的线程)写入了一段数据(这里是业务逻辑) 。 worker将该client对应的fd绑定到了13号epoll上 。 worker继续轮训监听13号epoll 。 4 客户端主动发送数据
worker(2301)
read(24 \"i am daojian\\r\\" 1024) = 14write(24 \"Did you say 'i am daojian'?\\r\\" 29) = 29##继续无限loopepoll_wait(13 [
8192 1000) = 0 概括为:
wait到数据后 , 立即read到用户控件内存中(读取1024个字节到 用户控件某个buff中) 。 写入数据(业务逻辑 , 不必太关注) 。 继续轮训等待13号epoll 。 5 客户端发送bye报文 , 服务器断开TCP连接
worker(2301)
read(24 \"bye\\r\\" 1024) = 5write(24 \"Have a good day!\\r\\" 18) = 18getsockopt(24 SOL_SOCKET SO_LINGER {onoff=0 linger=0 [8
) = 0dup2(25 24) = 24##从epoll数据结构中(OS)中删除fd为24的socketepoll_ctl(13 EPOLL_CTL_DEL 24 0x7f702dd531e0) = -1 ENOENT##关闭24 socketclose(24) = 0##继续等待13 epoll数据epoll_wait(13 [
8192 1000) = 0 断开客户端连接概括为:
从epoll中删除该客户端对应的fd(这里触发源头没找到 , 可能是boss) 。 close关闭客户端24号fd 。 继续轮训epoll 。 6 五个客户端同时连接
boss线程(23130)
accept(20 {sa_family=AF_INET sin_port=htons(1846) sin_addr=inet_addr(\"42.120.74.122\") [16
) = 24clone(child_stack=0x7f702cc51fb0 flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID parent_tidptr=0x7f702cc529d0 tls=0x7f702cc52700 child_tidptr=0x7f702cc529d0) = 10035accept(20 {sa_family=AF_INET sin_port=htons(42067) sin_addr=inet_addr(\"42.120.74.122\") [16