Java实战之从同步阻塞IO到NIO

同步阻塞IO

单线程BIO

最原始的网络编程思路就是服务器用一个while循环,不断监听端口是否有新的套接字连接,如果有,那么就调用一个处理函数处理。

while(true){ 
  socket = accept(); 
  handle(socket) 
} 

这种方法的最大问题是无法并发,效率太低。如果当前的请求没有处理完,那么后面的请求只能被阻塞,服务器的吞吐量太低。

多线程BIO

针对上面的问题,很自然想到了使用多线程处理IO,也就是很经典的connection per thread,每一个连接用一个线程处理。

while(true){ 
  socket = accept(); 
  new thread(socket); 
} 

tomcat服务器的早期版本确实是这样实现的。多线程的方式确实一定程度上极大地提高了服务器的吞吐量,因为之前的请求在read阻塞以后,不会影响到后续的请求,因为他们在不同的线程中。这也是为什么通常会讲“一个线程只能对应一个socket”的原因。
那么,线程中创建多个socket不行吗?语法上确实可以,但是实际上没有用,每一个socket都是阻塞的,这就遇到同单线程IO一样的问题。所以在一个线程里只能处理一个socket,就算accept了多个也没用,前一个socket被阻塞了,后面的是无法被执行到的。

Java BIO示例

下面基于同步阻塞式IO创建一个时间服务TimeServer。

TimeServer服务端

public class TimeServer {
  private static int port = 8080;

  public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = null;
    try {
      serverSocket = new ServerSocket(port);
      System.out.println("server starts in port: " + port);

      Socket socket = null;
      while (true) {
        // 监听来自客户端的连接,主线程阻塞在accept操作上
        socket = serverSocket.accept();
        // 创建一个新的线程处理socket链路
        new Thread(new TimeServerHandler(socket)).start();
      }
    } finally {
      if (serverSocket != null) {
        serverSocket.close();
      }
    }
  }
}

TimeServer Handler代码

public class TimeServerHandler implements Runnable {
  private Socket socket;

  public TimeServerHandler(Socket socket) {
    this.socket = socket;
  }

  @Override
  public void run() {
    BufferedReader in = null;
    PrintWriter out = null;

    try {
      in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
      out = new PrintWriter(this.socket.getOutputStream(), true);

      String currTime = null;
      String body = null;

      while (true) {
        body = in.readLine();
        if (body == null) {
          break;
        }

        System.out.println("time server receive: " + body);
        currTime = new Date(System.currentTimeMillis()).toString();
        out.println(currTime);
      }
    } catch (Exception e) {
      // ignore
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException e1) {
          e1.printStackTrace();
        }
      }
      if (out != null) {
        out.close();
      }
      if (this.socket != null) {
        try {
          this.socket.close();
        } catch (IOException e2) {
          e2.printStackTrace();
        }
      }
      this.socket = null;
    }
  }
}

TimeClient客户端

public 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值