在传统的同步阻塞网络编程之中,服务器端有一个ServerSocket负责绑定IP地址,启动端口监听,并且通过这个ServerSocket创建新的socket,然后这个socket就负责和client端的socket的连接操作.两个socket之间的输入流,输出流都是阻塞式通信,
about:blocking-mode and non-blocking mode
https://docs.oracle.com/javase/7/docs/api/java/nio/channels/SelectableChannel.html#bm
接下来通过一个例子来说明传统的I/O模型(同步阻塞式)。
下面是srver端的代码:分别由两部分组成
BIOServerIO.java
package learningNote.IO;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class BIOServer {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
int port=8090;
ServerSocket ss=new ServerSocket(port);
System.out.println("server start in port "+port);
while(true){
Socket s=ss.accept();
System.out.println("a client connect to me");
new Thread(new BIOSocketHandler(s)).start();
}
}
}
BIOSocketHandler.java
package learningNote.IO;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class BIOSocketHandler implements Runnable{
private Socket s;
public BIOSocketHandler(Socket s) {
// TODO Auto-generated constructor stub
this.s = s;
}
@Override
public void run() {
// TODO Auto-generated method stub
try (BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));//获取socket的输入流
PrintWriter out=new PrintWriter(s.getOutputStream(),true);//获取socket的输出流,并且设置自动刷新缓冲区
){
//读取输入消息并打印
String message=" ";
while(true){
//读取输入消息
while(true){
String temp=in.readLine();
if(temp.equals("ok")){
break;
}
message+=temp+"\n";
}
//打印收到的消息
System.out.print(message);
//返回消息
String now=new java.util.Date().toString();
out.println(now+" "+message+"ok");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(1);
}
}
}
下面是client端的代码:(由两部分组成)
BIOClient.java
package learningNote.IO;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class BIOClient {
public BIOClient() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
Socket s=new Socket("127.0.0.1",8090);
new Thread(new BIOClientHandler(s)).start();
}
}
BIOClientHandler.java
package learningNote.IO;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class BIOClientHandler implements Runnable {
private Socket s;
public BIOClientHandler(Socket s) {
// TODO Auto-generated constructor stub
this.s=s;
}
@Override
public void run() {
// TODO Auto-generated method stub
try(BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(s.getOutputStream(),true)){
while(true){
//从控制台读取输入
String message=" ";
while(true){
String temp=br.readLine();
if(temp.equals("ok"))break;
message+=temp+"\n";
}
//发送消息
out.println(message+"ok");
//读取输入消息
String body=" ";
while(true){
String temp=in.readLine();
if(temp.equals("ok"))break;
body+=temp+"\n";
}
System.out.print(body);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
从上面的例子我们可以看出,这种模式存在着很大的问题,
- 每次有新的连接请求,server就会建立一条新的线程来处理这个请求
- 当客户端并发连接较大的时候,线程过多会大大降低性能
- 同时,主线程在ss.accept()处会一直阻塞