关于BIO
网络编程的基本模型是Client/Server模型,其中服务端提位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务器端监听地址发起请求。连接成功后,双方通过输入输出流进行同步阻塞式通信。采用BIO通信模式的服务器,通常由一个Acceptor线程负责监听客户端的连接,它接收到请求之后会为每个客户端建一个新的线程,通过输出流返回响应给客户端,线程才销毁。这是一个一请求一响应的模型。如果不启线程,在server.accept时,如果没有其它客户端请求连接,那么已连接的客户端将读不到数据;如果在server.read时,如果没有读到数据,服务端就不能接收到其他请求。
该模型最大的问题就是:当客户端并发访问数量增加时,服务端的线程个数据与客户端并发访问数成1;1的关系,当线程膨胀后,系统会发生线程堆栈溢出、创建线程失败、不能对外提供服务。
BIO简单例子
server端:
package com.netty.bio;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
* @author laughing
*
* @date 2014年10月5日 上午12:36:57
*/
public class TimeServer {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
int port = 8080;
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("Then time server is start in port: " + port);
Socket socket = null;
while (true) {
socket = server.accept();// 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
System.out.println(socket.getInetAddress() + ",已连接");
new Thread(new TimeServerHandler(socket)).start();
}
} finally {
if (server != null) {
System.out.println("The time server close.");
server.close();
server = null;
}
}
}
}
service端:
package com.netty.bio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
*
* @author laughing
* @email john.cha@qq.com
* @date 2014年10月5日 上午12:43:53
*/
public class TimeServerHandler implements Runnable {
private Socket socket;
/**
* @param socket
*/
public TimeServerHandler(Socket socket) {
super();
this.socket = socket;
}
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
@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 currentTime = null;
String body = null;
while (true) {
body = in.readLine();
if (body == null) {
break;
}
currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER";
out.println(currentTime);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (out != null) {
out.close();
out = null;
}
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.socket = null;
}
}
}
}
Client端:
package com.netty.bio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/**
*
* @author laughing
*
* @date 2014年10月5日 上午12:58:36
*/
public class TimeClient {
/**
* @param args
*/
public static void main(String[] args) {
BufferedReader in = null;
PrintWriter out = null;
Socket socket = null;
// TODO Auto-generated method stub
try {
socket = new Socket("127.0.0.1", 8080);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
out.println("QUERY TIME ORDER");
out.flush();
String resp = in.readLine();
System.out.println("Now is : " + resp);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
out.close();
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}