socket的BIO 演示 -- 补充linux知识

本文学自视频:https://www.bilibili.com/video/BV11K4y1C7rm?p=1

开启服务端以及基础知识铺垫

第一步,写一个服务端ServerSocketTest:

public class ServerSocketTest {
    private static final ExecutorService executorService = Executors.newCachedThreadPool();

    public static void main(String[] args) throws IOException {

        // socket()+bind()+listen()
        ServerSocket serverSocket = new ServerSocket(8090);
        System.out.println("step1: new ServerSocket(80) ");
        while (true) {
            //accept()
            Socket socket = serverSocket.accept();

            Runnable task = () ->{
                try {
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                    String str;
                    while ((str = bufferedReader.readLine()) != null) {
                        System.out.println(str);
                    }
                } catch (IOException e) {

                    e.printStackTrace();

                }
            };
             executorService.submit(task);
        }
    }
}

第二步:将java文件和class文件上传到linux系统中,本文放到了/home/binto/socketTest/

第三步:linux中输入,用于查看程序对系统有没有系统调用:

strace -ff -o ./ooxx java TestSocket

执行后,新开一个窗口,可以看到,多了很多ooxx.数字的文件,每一个文件都代表着一个线程(这里的线程是java启动的线程,还不是我们代码里要生成的线程)。
在这里插入图片描述
第四步,查看main线程是哪一个:
grep 'step1' ./*
在这里插入图片描述

第五步,ooxx.13841这个文件后面再来看

第六步,输入jps看看进程号:
在这里插入图片描述
第七步:cd /proc/13840
在这里插入图片描述
然后进入task cd task,这里可以看到所有的线程
在这里插入图片描述
退回上一级文件夹,然后进入fd文件夹cd ../fd
在这里插入图片描述
可以看到,文件夹中,0-5五个数字,这五个数字就是linux的文件描述符(fd),数字4和5分别表示两个socket(ipv4和ipv6)。

客户端访问

第一步:输入netstat -natp,查看网络监听状态:
在这里插入图片描述
第二步:新建一个窗口,输入nc localhost 8090 表示客户端连接socket服务器:
在这里插入图片描述
再看/proc/13840/fd文件夹时,会发现多了一个socket(client的socket)
在这里插入图片描述
另外,socketTest/文件夹下还多了一个文件ooxx.15155,这是因为我们的代码中,收到一个client连接就会new 一个线程,这个文件就是那个线程的系统调用。

ooxx文件解释

现在回到socketTest/文件夹下的ooxx.13841文件:vi ooxx.13841
第一步:搜索socket():/socket(
在这里插入图片描述
这一行就表示建立了一个socket,结果为5,以后想对这个socket进行操作,也就是对这个文件描述符5进行操作。

第二步:搜索bind():/bind(
在这里插入图片描述
可以看到,这里就是对文件描述符5进行bind()操作,同时绑定的端口号是8090。
第三步:搜索listen()
这里就不搜索了,因为上面bind()的图片可以看到,绑定后立马调用了listen()来对文件描述符5进行监听

第四步:搜索accept()
搜索文件中的client的端口号42010:/42010
在这里插入图片描述
可以看到,调用了系统指令accept()这里的6指的是,监听到的client设置为文件描述符6

第五步:
我们来看ooxx.15155这个文件:
在这里插入图片描述
可以看到,这个线程在recvfrom方法阻塞住了。

接着客户端访问

回到客户端的窗口,随便输入一段字符串,比方说hello word
在这里插入图片描述
此时服务端会收到信息并输出:
在这里插入图片描述
此时再看来看ooxx.15155这个文件:
在这里插入图片描述
可以看到recvfrom的阻塞通了,收到了消息,然后处理完又进入阻塞。

总结:

对于每一个线程而言,都会进入到recvfrom阻塞。
当有client输入数据后,数据会进入到文件描述符6中,然后recvfrom会读到6中的数据,再传递给程序(用户态)。

同时,socket通信时,会走很多系统调用。
整体流程:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值