BIO系统调用strace查看IO阻塞

news/2025/2/26 10:08:33/

BIO服务端例子

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

java">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命令去连接服务端

java">nc localhost 8090

strace命令追踪系统调用

java">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中可以看到

java">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语句

java">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文件

java">RETURN VALUEOn 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上
java">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.ppmy.cn/news/1574983.html

相关文章

HPE Aruba Networking推出全新解决方案助力零售商增强物联网数据收集与边缘处理能力

全新网络连接解决方案助力IT 团队加强对零售环境的保护与管理,提升物联网(IoT)安全性,同时优化用户体验与运营效率 纽约 — 2025年2月25日 —慧与科技(NYSE: HPE)日前宣布推出全新功能,借助高效的网络连接和高性能边缘计算,助力零售商提升客户体验与运营效率,从而进一步打造零…

DeepSeek 助力 Vue 开发:打造丝滑的表单验证(Form Validation)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

pnpm的基本用法

以下是 pnpm 的核心命令和使用指南&#xff0c;涵盖从安装依赖到项目管理的常见操作&#xff1a; 1. 基础命令 (1) 安装依赖 pnpm install # 安装 package.json 中的所有依赖 pnpm install <包名> # 安装指定包&#xff08;自动添加到 dependencies&#xf…

【Python爬虫(52)】探秘Scrapy:项目结构与配置全解析

【Python爬虫】专栏简介&#xff1a;本专栏是 Python 爬虫领域的集大成之作&#xff0c;共 100 章节。从 Python 基础语法、爬虫入门知识讲起&#xff0c;深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑&#xff0c;覆盖网页、图片、音频等各类数据爬取&#xff…

【有奖实践】轻量消息队列(原 MNS)订阅 OSS 事件实时处理文件变动

当你需要对对象存储 OSS&#xff08;Object Storage Service&#xff09;中的文件变动进行实时处理、同步、监听、业务触发、日志记录等操作时&#xff0c; 你可以通过设置 OSS 的事件通知规则&#xff0c;自定义关注的文件&#xff0c;并将 OSS 事件推送到轻量消息队列&#x…

Docker基础-常见命令

docker images -查看所有的本地镜像。 docker pull -把远端镜像拉取到本地。 docker rmi -删除镜像。 docker push -推到镜像仓库。 docker run -创建并运行容器&#xff08;自动化&#xff0c;如果发现镜像不存在会先去拉取&#xff0c; 拉取完了以后再去自动创建容器&am…

postman调用ollama的api

按照如下设置&#xff0c;不需要设置key 保持长会话的方法 # 首次请求 curl http://localhost:11434/api/generate -d {"model": "deepseek-r1:32b","prompt": "请永久记住&#xff1a;110&#xff0c;1-12&#xff0c;之后所有数学计算必…

Linux(CentOS)安装 MySQL

CentOS版本&#xff1a;CentOS 7 三种安装方式&#xff1a; 一、通过 yum 安装&#xff0c;最简单&#xff0c;一键安装&#xff0c;全程无忧。 二、通过 rpm 包安装&#xff0c;需具备基础概念及常规操作。 三、通过 gz 包安装&#xff0c;需具备配置相关操作。 --------…