当前位置: 首页 > article >正文

BIO系统调用strace查看IO阻塞

BIO服务端例子

服务端监听8090端口,每一个客户端用一个线程处理,不断的获取客户端的输入数据并打印

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @Author mubi
 * @Date 2020/6/25 18:54
 */
public class TestSocket {
    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = new ServerSocket(8090);
        System.out.println("step1 new ServerSocket(8090)");
        while(true){
            final Socket client = serverSocket.accept();
            System.out.println("step2 client:" + client.getPort());
            new Thread(()->{
                try{
                    InputStream in = client.getInputStream();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
                    while (true){
                        System.out.println(bufferedReader.readLine());
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }).start();
        }

    }
}

nc命令去连接服务端

nc localhost 8090

strace命令追踪系统调用

javac TestSocket.java
strace -ff -o ./stracefile java TestSocket

ServerSocket启动过程

  1. socket系统调用, 得到文件描述符,如 fd5
  2. bind端口
  3. listen,文件描述符
  4. accept(阻塞状态), 有客户端连接得到新的socket, 产生文件描述符 如 fd6,fd7

在这里插入图片描述

在这里插入图片描述

查看进程下所有线程

通过进程ID号能知道有多少个线程(linux的/proc/<pid>/task目录下)

在这里插入图片描述

补充:linux创建线程是clone系统调用,在主线程的stracefile中可以看到

clone(child_stack=0x7fd8d8508ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_     PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fd8d85099d0, tls=0x7fd8d8509700, child_tidptr=0x7fd8d85099d0) = 4787

netstat查看tcp相关

Listen,ESTABLISHED状态的TCP

在这里插入图片描述

文件描述符的查看

在工作目录会看到很多stracefile,以.线程id结尾;本地nc命令起的56544端口的客户端连接,vim stracefile.4772(4772是服务端开启的主线程),可以找到accept语句

accept(5, {sa_family=AF_INET6, sin6_port=htons(56544), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 6
fcntl(6, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(6, F_SETFL, O_RDWR)               = 0
lseek(3, 62493071, SEEK_SET)            = 62493071
read(3, "PK\3\4\n\0\0\10\0\0000\211|L9\267\215\270R\6\0\0R\6\0\0;\0\0\0", 30) = 30
lseek(3, 62493160, SEEK_SET)            = 62493160
read(3, "\312\376\272\276\0\0\0004\0:\7\0!\n\0\v\0\"\t\0\10\0#\n\0\1\0$\t\0\v\0"..., 1618) = 1618
write(1, "step2 client:56544", 18)      = 18

man 2 accept了解到 accept 的返回:系统会产生一个文件描述符,关联接收到的socket文件

RETURN VALUE
       On success, these system calls return a nonnegative integer that is a descriptor for the accepted socket.  On error,  -1  is returned, and errno is set appropriately.

从上可以看出是文件描述符6的一个文件,即代表了连接上的一个客户端socket(在/proc/<pid>/fd目录下可见,pid为Java程序进程ID,本地同jps命令看到的程序运行ID):

在这里插入图片描述

  • strace给客户端起的线程,会阻塞在recvfrom接收数据上(查看上文clone产生的线程tid=4787),vim stracefile.4787可以看到阻塞在recvfrom(6,上,即阻塞在read客户端socket fd上
set_robust_list(0x7fd8d85099e0, 24)     = 0
gettid()                                = 4787
rt_sigprocmask(SIG_BLOCK, NULL, [QUIT], 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [HUP INT ILL BUS FPE SEGV USR2 TERM], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [QUIT], NULL, 8) = 0
futex(0x7fd8f000b354, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7fd8f000b350, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x7fd8f000b328, FUTEX_WAKE_PRIVATE, 1) = 1
sched_getaffinity(4787, 32, [1, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) = 32
sched_getaffinity(4787, 32, [1, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) = 32
(0x7fd8d8409000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd8d8409000
mprotect(0x7fd8d8409000, 12288, PROT_NONE) = 0
lseek(3, 30054856, SEEK_SET)            = 30054856
read(3, "PK\3\4\n\0\0\10\0\0006\211|L\24w\0067E\3\0\0E\3\0\0\27\0\0\0", 30) = 30
lseek(3, 30054909, SEEK_SET)            = 30054909
read(3, "\312\376\272\276\0\0\0004\0-\t\0\6\0\34\n\0\7\0\35\t\0\32\0\36\n\0\37\0\33\n\0"..., 837) = 837
lseek(3, 30056639, SEEK_SET)            = 30056639
read(3, "PK\3\4\n\0\0\10\0\0B\211|L\305SF\t\265\r\0\0\265\r\0\0 \0\0\0", 30) = 30
lseek(3, 30056701, SEEK_SET)            = 30056701
read(3, "\312\376\272\276\0\0\0004\0\242\n\0Y\0Z\n\0-\0[\t\0,\0\\\t\0,\0]\t\0"..., 3509) = 3509
recvfrom(6, "helloABC\n", 8192, 0, NULL, NULL) = 9
ioctl(6, FIONREAD, [0])                 = 0
write(1, "helloABC", 8)                 = 8
write(1, "\n", 1)                       = 1
recvfrom(6,

http://www.kler.cn/a/562396.html

相关文章:

  • 【Java 基础】-- Java 接口中的 @Public 和 @FunctionalInterface 注解详解
  • SpringBoot整合sharding-jdbc 实现分库分表操作
  • Android SDK封装打包流程详解
  • Flutter - 基础Widget
  • 如何优化频繁跳槽后的简历?
  • 华为hcia——Datacom实验指南——二层交换原理
  • 企业级服务器如何初始化数据磁盘
  • C#与AI的交互(以DeepSeek为例)
  • STM32 最小系统
  • ubuntu开机自动挂载硬盘
  • 获取GitHub的OAuth2的ClientId和ClientSecrets
  • nv docker image 下载与使用命令备忘
  • 《云豹录屏大师:免费解锁高清录屏新体验》
  • Kronecker分解(K-FAC):让自然梯度在深度学习中飞起来
  • matlab ylabel怎么让y轴显示的标签是正的
  • VMware虚拟机安装win10系统详细图文安装教程(附安装包) 2025最新版详细图文安装教程
  • 《炎龙骑士团 1 邪神之封印》游戏信息
  • 深搜专题2:组合问题
  • 易基因:RNA甲基化修饰和R-loop的交叉调控:从分子机制到临床意义|深度综述
  • 使用Python爬虫获取孔夫子旧书网已售商品数据:调用item_search_sold接口