版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
在基于传统的同步阻塞模型中,ServerSocket负责绑定IP地址,启动监听端口;Socket负责发起连接操作;连接成功后双方通过输入和输出流进行同步阻塞方式通信。
2.1.1 BIO通信模型图
服务端通常由一个独立的Acceptor线程负责监听客户端的连接,收到客户端连接请求后为每个客户端创建一个新的线程进行链路处理,处理完成后通过输出流返回应答给客户端,线程销毁,模型如下图:
该模型的问题是有多少个客户端连接服务端就要为之创建多少个服务线程,当客户端并发访问量增加后,可能会导致服务器性能下降甚至宕机。下一节将通过实例寻找同步阻塞IO的弊端。
2.1.2 BIO TimeServer
服务端包括一个监听类TimeServer和处理客户端请求类TimeServerHandler。当TimeServer接收到客户端请求时,为客户端创建处理线程,在本例TimeServerHandler处理线程中,先循环获取客户端请求的内容,判断请求类型,若是请求服务端当前的时间,则将服务端当前的时间转换为字符串返回给客户端,当处理结束后,处理线程自动销毁。
package mybio.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
ServerSocket server = null;;
try {
server = new ServerSocket(port);
Socket socket = null;
while(true) {
socket = server.accept();
new Thread(new TimeServerHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(server != null) {
System.out.println("server closing");
server.close();
server = null;
}
}
}
}
package mybio.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
public class TimeServerHandler implements Runnable{
Socket socket = null;
public TimeServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String currentTime = null;
String body = null;
while(true) {
body = in.readLine();
if(body == null)
break;
System.out.println("The time server receive order :" + body);
currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ?
new Date(System.currentTimeMillis()).toString()
: "BAD ORDER";
out.println(currentTime);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(in != null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
if(out != null)
out.close();
if(socket != null)
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.1.3 BIO TimeClient
在本例的客户端,每个1秒向服务端发送一次QUERY TIME ORDER请求,将服务端的返回内容进行打印。
package mybio.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TimeClient {
public static void main(String[] args) {
int port = 8080;
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket("127.0.0.1", port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while(true) {
out.println("QUERY TIME ORDER");
System.out.println("Send order to server succeed!");
String ret;
ret = in.readLine();
System.out.println("Now is :" + ret);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out != null) {
out.close();
out = null;
}
if(in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null) {
try {
socket.close();
socket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}