# 网络IO

进程与线程?

进程:操作系统调度单元 --CPU核心

线程: 进程调度的最小单元

实际问题:Nginx worker的数量 进程数量

netty线程的数量

redis worker 一个线程

cpu核心数

tomcat很多线程池 线程的总数加起来远超过CPU的核心数

BIO:一个线程对应一个客户端

测试环境:jdk1.4

使用Java写一个BIO

public Class SocketIO{
    public static void main(String[] args) throw Exception{
        ServerSocket server = new ServerSocket(9090);
        
        System.out.println("step1: new ServerSocket(9090)");
        
        while(true) {
            final Socket client = server.accept();//阻塞
            System.out.println("step2:client\t" + client.getPort());
            new Thread(new Runnable(){
                public void run() {
                    InputStream in = null;
                    try {
                        in = client.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                        while(true) {
                            String dataline = reader.readLine();//阻塞2
                            if(null != dataline){
                               System.out.println(dataline) 
                            }else{
                                System.out.println("发送为空")
                            }
                        }
                    } catch(Exception e){
                        System.out.println("发送错误!")
                    }
                }
            });
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
strace -ff -o ./out /usr/java/j2sdk1.4.2_19/bin/java SocketBIO.class
1

通过nc链接该客户端

nc localhost 9090
1

Recv-Q与Send-Q均处于内核中

BIO最大缺点:每个连接对应一个线程,block 阻塞,造成线程过多。

NIO(NONE_BLOCK IO) linux内核2.26开始支持

Java 中的 NIO 于 Java 1.4 中引入,对应 java.nio 包,提供了 Channel , SelectorBuffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 对于高负载、高并发的(网络)应用,应使用 NIO 。

public class SocketNI0 {
    public static void main(String[] args) throws Exception{
        LinkedL ist<Soc ketChannel> clients = new LinkedL ist<>();
        ServerSocketChannel ss = ServerSocketChannel. open(); //服务 端开启监听:接受客户端
        ss.bind(new InetSocketAddress(9090));
        ss.configureBlocking(false); //重点 0S NONBL OCKING! ! // 只让接受客户端不阻塞
        //ss.setOption (StandardSocketOptions.TCP_NODELAY, false);
        //StandardSocketOptions.TCP_NODELAY
        //StandardSocketOptions.SO_KEEPALIVE
        white (true) {
            //接受客户端的连接
            SocketChannel client = ss.accept()i //不会阻塞? -1 NULL
            if (client == null) {  
                System.out.println("null.....");
            }else {
                client.configureBlocking(false);
                int port = client.socket().getPort();
                System.out.println("client...port:"+port);
                clients.add(client);
            }
            
            ByteBuffer buffer = ByteBuffer .allocateDirect(4096); //可以在堆里
            for(SocketChannel c:clients){
                int num = c.read(buffer); //0 -1 0 //不会阻塞
                if(num > 0) {
                    buffer.flop();
                    byte[] aaa = new byte[buffer.limit()];
                    buffer.get(aaa);
                    
                    String b = new String(aaa);
                 System.out.println(c.socket().getPort() + ":" + b);
                    buffer.clear();
                }
            }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

网络IO从哪里读取出来的?

从自己的队列中读取,而不是要读再发。