zoukankan      html  css  js  c++  java
  • 网络编程-关闭连接(2)-Java的NIO在关闭socket时,究竟用了哪个系统调用函数?

    背景

    在上一讲网络编程-关闭连接-C/C++相关系统调用中,提到过,目前项目使用Netty框架来实现的网络编程,查看netty源码可以得知,netty最终是调用了java Nio的close接口做的关闭操作,那么想研究清楚这个close操作究竟做了什么,可以从两个方向入手,这两个方向也是从下至上的。

    1. 搞清楚如果使用C/C++编程,应该调用哪个系统调用函数?函数内部做了什么,涉及到什么TCP/IP的协议参数,这些已经在上一讲中研究明白了。
    2. 搞清楚java nio在调用close方法时,究竟使用了哪个系统调用?

    这一讲,主要研究解决第二个问题,搞清楚java nio在调用close方法时,究竟使用了哪个系统调用?

    实验

    在实验中,我们会使用linux下的strace工具,来跟踪系统调用。

    使用我们的测试代码,用netty框架搭建了一个客户端,其中通过web接口传入ip端口进行连接,连接成功以后,在channelActive回调方法中先调用一个写文件方法,然后关闭channel。

    测试代码上传到github上:

    部分关键代码如图:

    @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            //写入本地文件测试字符,然后关闭channel
            FileWriter fileWriter = new FileWriter("/root/test.txt");
            fileWriter.write("test test hold on");
            fileWriter.flush();
            fileWriter.close();
    
            //调用同步方法关闭
            ChannelFuture sync = ctx.channel().close().sync();
            if(sync.isSuccess()){
                System.out.println("关闭成功!");
            }else{
                System.out.println("关闭失败!");
            }
    }
    

    在linux虚拟机上,使用下面指令运行该程序

    [root@localhost Downloads]# java -jar pro-test-demo-0.0.1-SNAPSHOT.jar 
    

    然后使用ps -ef | grep "java"得到该进程的pid。

    [root@localhost Downloads]# ps -ef | grep "java"
    root       3029   2940 31 13:48 pts/0    00:00:13 java -jar pro-test-demo-0.0.1-SNAPSHOT.jar
    root       3136   3101  0 13:49 pts/2    00:00:00 grep --color=auto java
    

    使用strace跟踪系统调用,命令如下:

    strace -tt -T -f -v -e trace=all -p 3029 -o ouput.log
    

    java程序运行起来如下,我们使用postman传递了ip和端口,看到日志输出为连接成功,并且输出关闭成功!

    [root@localhost Downloads]# java -jar pro-test-demo-0.0.1-SNAPSHOT.jar 
    
      .   ____          _            __ _ _
     /\ / ___'_ __ _ _(_)_ __  __ _    
    ( ( )\___ | '_ | '_| | '_ / _` |    
     \/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.1.4.RELEASE)
    
    2020-07-14 13:48:52.225  INFO 3029 --- [           main] c.n.icomp.protestdemo.jfdj.NettyClient   : Starting NettyClient v0.0.1-SNAPSHOT on localhost.localdomain with PID 3029 (/root/Downloads/pro-test-demo-0.0.1-SNAPSHOT.jar started by root in /root/Downloads)
    2020-07-14 13:48:52.229  INFO 3029 --- [           main] c.n.icomp.protestdemo.jfdj.NettyClient   : No active profile set, falling back to default profiles: default
    2020-07-14 13:48:53.608  INFO 3029 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
    2020-07-14 13:48:53.618  INFO 3029 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
    2020-07-14 13:48:53.694  INFO 3029 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 55ms. Found 0 repository interfaces.
    2020-07-14 13:48:54.374  INFO 3029 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9876 (http)
    2020-07-14 13:48:54.410  INFO 3029 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2020-07-14 13:48:54.410  INFO 3029 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
    2020-07-14 13:48:54.504  INFO 3029 --- [           main] o.a.c.c.C.[.[localhost].[/protest]       : Initializing Spring embedded WebApplicationContext
    2020-07-14 13:48:54.504  INFO 3029 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2187 ms
    2020-07-14 13:48:55.144  INFO 3029 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-07-14 13:48:55.434  INFO 3029 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9876 (http) with context path '/protest'
    2020-07-14 13:48:55.436  INFO 3029 --- [           main] c.n.icomp.protestdemo.jfdj.NettyClient   : Started NettyClient in 3.968 seconds (JVM running for 4.79)
    2020-07-14 13:50:10.685  INFO 3029 --- [nio-9876-exec-1] o.a.c.c.C.[.[localhost].[/protest]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
    2020-07-14 13:50:10.685  INFO 3029 --- [nio-9876-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
    2020-07-14 13:50:10.691  INFO 3029 --- [nio-9876-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 6 ms
    接收到参数:{"ip":"10.43.11.240","port":"20108"}
    连接成功!
    关闭成功!
    

    最后打开output.log查看系统调用
    为了便于我搜索,我提前在代码中加入了关键的一行

    fileWriter.write("test test hold on");
    

    所以搜索的时候,可以先搜索test test hold on,找到对应写入的系统调用,附近应该就是close相关的系统调用了。

    3494  13:53:04.722628 write(103, "test test hold on", 17) = 17 <0.000060>
    3494  13:53:04.722755 close(103)        = 0 <0.000251>
    3494  13:53:04.723141 getsockopt(102, SOL_SOCKET, SO_LINGER, {l_onoff=0, l_linger=0}, [8]) = 0 <0.000080>
    
    3499  13:53:17.206962 close(102)        = 0 <0.000012>
    

    可以发现,fd为102的socket就是我们需要检测的socket,在调用close真正关闭之前,还进行了获取SO_LINGER的系统调用getsockopt,并且l_onoff=0, l_linger=0,会关闭读写两方向连接,并且在后台继续发送发送缓冲区中的内容,后面调用close返回0,代表成功。

    总结

    JAVA nio的close操作,使用的是close系统调用。关于close系统调用,可以参考上一讲中的内容。网络编程-关闭连接-C/C++相关系统调用

  • 相关阅读:
    15. DML, DDL, LOGON 触发器
    5. 跟踪标记 (Trace Flag) 834, 845 对内存页行为的影响
    4. 跟踪标记 (Trace Flag) 610 对索引组织表(IOT)最小化日志
    14. 类似正则表达式的字符处理问题
    01. SELECT显示和PRINT打印超长的字符
    3. 跟踪标记 (Trace Flag) 1204, 1222 抓取死锁信息
    2. 跟踪标记 (Trace Flag) 3604, 3605 输出DBCC命令结果
    1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
    0. 跟踪标记 (Trace Flag) 简介
    SpringBoot + Redis + Shiro 实现权限管理(转)
  • 原文地址:https://www.cnblogs.com/ging/p/13467859.html
Copyright © 2011-2022 走看看