网络编程中,服务端提供IP和监听端口,客户端通过服务端的IP和端口发送请求,进行通信。这篇是讲传统的同步阻塞模型--BIO。
客户端
BioClient主要是创建一个Socket,并通过Socket把请求发送服务端,代码如下:
public class BioClient {
public static void main(String[] args) {
try {
// 通过服务IP,端口创建一个Socket
Socket socket = new Socket(Const.IP, Const.PORT);
// 获取Socket输出流
OutputStream outputStream = socket.getOutputStream();
// 输出流
outputStream.write("hello world".getBytes());
// 关闭流
outputStream.close();
// 关闭Socket
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
服务端先创建一个ServerSocket,用于监听指定端口的连接请求。accept方法会一直阻塞,直到新的连接建立,建立后,创建一个Socket与客户端进行通信。在读取输入流的时候,br.readLine()也是阻塞的。
public class BioServer {
public static void main(String[] args) {
try {
//获取ServerSocket,绑定服务器的端口
ServerSocket serverSocket = new ServerSocket(Const.PORT);
while (true) {
// 创建一个Socket接收连接
Socket socket = serverSocket.accept();
// 获取输入流
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String message;
while (null != (message = br.readLine())) {
System.out.println(message);
}
// 关闭流
inputStream.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上面的实例中,有个比较大的缺点,就是同时只能处理一个连接,要想处理多个并发客户端,我们可以简单地用多线程来管理,每次有新的sockert,创建一个线程或则放入线程池来处理。
我们把sockert的部分抽出来:
public class BioServerHandler implements Runnable {
private Socket socket;
public BioServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 获取输入流
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String message;
while (null != (message = br.readLine())) {
System.out.println(message);
}
// 关闭流
inputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建线程的方式:
public class BioServer2 {
public static void main(String[] args) {
try {
//获取ServerSocket,绑定服务器的端口
ServerSocket serverSocket = new ServerSocket(Const.PORT);
while (true) {
// 创建一个Socket接收连接
Socket socket = serverSocket.accept();
new Thread(new BioServerHandler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建线程池的方式:
public class BioServer3 {
private static ExecutorService executorService
= Executors.newFixedThreadPool(5);
public static void main(String[] args) {
try {
//获取ServerSocket,绑定服务器的端口
ServerSocket serverSocket = new ServerSocket(Const.PORT);
while (true) {
// 创建一个Socket接收连接
Socket socket = serverSocket.accept();
executorService.execute(new BioServerHandler(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BioServer2和BioServer3通过线程,可以比BioServer同时处理更多的客户端请求,但是依然存在着不足:在任何时候,都有大量的线程处于休眠状态,只能等待输入或则输出数据就绪,浪费资源。为此,java提供了另外一直方式-NIO。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。