BIO(同步阻塞式IO)
在JDK1.4之前,用Java编写网络请求,都是建立一个ServerSocket,然后,客户端建立Socket时就会询问是否有线程可以处理,如果没有,要么等待,要么被拒绝。即:一个连接,要求Server对应一个处理线程。
单线程处理
package one;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* BIO服务端
*/
public class BioService1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10101);
System.out.println("服务器启动!");
while (true){
//获取一个套接字(阻塞)
final Socket socket = serverSocket.accept();
System.out.println("来了一个新客户端!");
//业务处理
handler(socket);
}
}
/**
* 读取数据
* @param socket
*/
private static void handler(Socket socket){
try{
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while (true){
//读取数据 阻塞
int read = inputStream.read(bytes);
if(read != -1){
System.out.println(new String(bytes,0,read));
}else{
break;
}
}
}catch (Exception ex){
ex.printStackTrace();
}finally {
try{
System.out.println("socket关闭");
socket.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
}
本实例是一个简单的BIO的实现,在这里需要说明几个点阻塞点,一个是获取相应的套接字时,一个是读取数据时,通过运行该程序,使用telnet工具可以证实。
上面的demo中存在的问题,运行该demo,通过telnet测试可知,该服务端一次只能接收一个客户端的请求,即:服务端接收了一个客户端请求后,服务端阻塞在读数据上时,此时,有另一个客户端请求链接该服务端,服务器端是无法接收该链接的,因为,服务器端只有一个线程,而该线程现已经被阻塞了。要想让服务器端实现同时处理多个客户端的请求,可以通过多线程进行解决。
多线程的处理
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 采用多线程的方式进行处理
*/
public class BioService2 {
public static void main(String[] args) throws IOException {
ExecutorService newCashedThreadPool = Executors.newCachedThreadPool();
ServerSocket serverSocket = new ServerSocket(10101);
System.out.println("服务器启动!");
while (true){
//获取一个套接字(阻塞)
final Socket socket = serverSocket.accept();
System.out.println("来了一个新客户端!");
newCashedThreadPool.execute(new Runnable() {
@Override
public void run() {
//业务处理
handler(socket);
}
});
}
}
/**
* 读取数据
* @param socket
*/
private static void handler(Socket socket){
try{
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream();
while (true){
//读取数据 阻塞
int read = inputStream.read(bytes);
if(read != -1){
System.out.println(new String(bytes,0,read));
}else{
break;
}
}
}catch (Exception ex){
ex.printStackTrace();
}finally {
try{
System.out.println("socket关闭");
socket.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
}
该服务器端每次接收到一个客户端链接时,就会创建一个线程进行业务处理,即:每个链接都会有单独的一个线程进行为它服务。这种方式是非常消耗资源的,这种方式要求的链接都是短连接,通过这种要求,来使每个链接占用的线程的时间缩减到最小,从而可以进行更多的链接处理。
总结
单线程的服务器端,每次只能处理一个客户端请求;多线程的服务器端,将接收客户端链接和业务分开,将业务处理使用多线程,从而达到可以处理多个客户单请求,即:一个客户端一个线程,这种方式非常的消耗资源。