I/O-BIO

2020-11-28  本文已影响0人  麦大大吃不胖

by shihang.mai

1. BIO:ScoketIO

阻塞IO模型,举例:SocketIOPropertites

服务端

public class SocketIOPropertites {



    //server socket listen property:
    private static final int RECEIVE_BUFFER = 10;
    private static final int SO_TIMEOUT = 0;
    private static final boolean REUSE_ADDR = false;
    private static final int BACK_LOG = 2;
    //client socket listen property on server endpoint:
    private static final boolean CLI_KEEPALIVE = false;
    private static final boolean CLI_OOB = false;
    private static final int CLI_REC_BUF = 20;
    private static final boolean CLI_REUSE_ADDR = false;
    private static final int CLI_SEND_BUF = 20;
    private static final boolean CLI_LINGER = true;
    private static final int CLI_LINGER_N = 0;
    private static final int CLI_TIMEOUT = 0;
    private static final boolean CLI_NO_DELAY = false;
/*
    StandardSocketOptions.TCP_NODELAY
    StandardSocketOptions.SO_KEEPALIVE
    StandardSocketOptions.SO_LINGER
    StandardSocketOptions.SO_RCVBUF
    StandardSocketOptions.SO_SNDBUF
    StandardSocketOptions.SO_REUSEADDR
 */


    public static void main(String[] args) {

        ServerSocket server = null;
        try {
            server = new ServerSocket();
            server.bind(new InetSocketAddress( 9090), BACK_LOG);
            server.setReceiveBufferSize(RECEIVE_BUFFER);
            server.setReuseAddress(REUSE_ADDR);
            server.setSoTimeout(SO_TIMEOUT);

        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("server up use 9090!");
        while (true) {
            try {
                System.in.read();  //分水岭:

                Socket client = server.accept();
                System.out.println("client port: " + client.getPort());

                client.setKeepAlive(CLI_KEEPALIVE);
                client.setOOBInline(CLI_OOB);
                client.setReceiveBufferSize(CLI_REC_BUF);
                client.setReuseAddress(CLI_REUSE_ADDR);
                client.setSendBufferSize(CLI_SEND_BUF);
                client.setSoLinger(CLI_LINGER, CLI_LINGER_N);
                client.setSoTimeout(CLI_TIMEOUT);
                client.setTcpNoDelay(CLI_NO_DELAY);

                new Thread(
                        () -> {
                            while (true) {
                                try {
                                    InputStream in = client.getInputStream();
                                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                                    char[] data = new char[1024];
                                    int num = reader.read(data);

                                    if (num > 0) {
                                        System.out.println("client read some data is :" + num + " val :" + new String(data, 0, num));
                                    } else if (num == 0) {
                                        System.out.println("client readed nothing!");
                                        continue;
                                    } else {
                                        System.out.println("client readed -1...");
                                        client.close();
                                        break;
                                    }

                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                ).start();

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    server.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

客户端

public class SocketClient {

    public static void main(String[] args) {

        try {
            Socket client = new Socket("192.168.3.24",9090);

            client.setSendBufferSize(20);
            client.setTcpNoDelay(false);
            client.setOOBInline(false);
            OutputStream out = client.getOutputStream();

            InputStream in = System.in;
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            while(true){
                String line = reader.readLine();
                if(line != null ){
                    byte[] bb = line.getBytes();
                    for (byte b : bb) {
                        out.write(b);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 过程详解

BIO图解

BIO现象过程

  1. 只启动服务端(ServerSocket没accept)。 出现一个fd代表listen
  2. 再启动客户端连接服务端,不发消息。客户端和服务端进行3次握手,服务端会出现一个另外fd代表socket连接,但是还没分配进程处理
  3. 客户端发送消息,socket连接的rev-q有数据
  4. 服务端accept,socket连接已分配进程处理,并打印了客户端发来的消息
属性 位置 备注
BACK_LOG 服务端 可连接客户端的个数。当超出个数时,用netstat -natp查看进程时,发现有SYN_RECV状态,即3次握手未成功建立。
TcpNoDelay 客户端 设置为fasle时,表明打开优化。一次性发送大于设置SendBufferSize的值,会一次性发送所有的消息,并不会受SendBufferSize约束。
CLI_KEEPALIVE 服务端 服务端-客户端自动保持心跳
BIO

系统调用过程

  1. 调用socket()返回一个fd
  2. 调用bind(fd,9090),将fd和端口绑定起来
  3. 调用listen(),监听端口
  4. 调用accept(),会产生一个新fd而且会标注为blocking的
  5. 调用recv(新fd),也是标注为blocking的

3. BIO弊端

它accept和receive都是阻塞的.当我们accept后,开启线程去处理,每个连接均需要调用内核的clone()去创建线程

BIO弊端
上一篇 下一篇

猜你喜欢

热点阅读