BIO,NIO,AIO聊天室示例
几个概念
- 同步: 发送方发送请求之后,需要等接收方发回响应后才接着发
- 异步: 发送方发送请求之后,不等待接收方响应,继续发送下一个,系统内核完成请求后主动通知
- 阻塞: 在调用结果返回之前,当前线程会被挂起,需等到得到结果后才会返回。线程在此过程中不进行任何其他处理。
- 非阻塞: 调用结果不会立即返回,当前线程也不会被挂起,而是立即返回执行下一个调用。
socket连接
连接过程:
服务器端:
- 创建socket,绑定端口
- 开始监听
- 等待并接收客户端连接请求,返回新socket
- 由新socket与客户端进行交互
- 关闭连接
客户端:
- 创建socket
- 连接服务器与io交互
- 关闭连接
示例代码:
服务器端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class ChatServer {
/**
* 监听端口号
*/
private int port = 8081;
public ChatServer() {
}
public ChatServer(int port) {
this.port = port;
}
public void service() {
try {
System.out.println("服务器开始建立连接");
// 建立服务器连接
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器开始监听");
// 开始监听
Socket socket = serverSocket.accept();
// 获取输出流,向客户端发送信息
OutputStream outputStream = socket.getOutputStream();
BufferedReader reader = null;
try {
// 获取输入流,读取客户端传过来的信息
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
System.out.println("从客户端接收到一条消息,内容为:" + line);
}
// 发送消息给客户端
outputStream.write("我接收到了".getBytes(StandardCharsets.UTF_8));
} finally {
// 关闭流和连接
if(reader != null) {
reader.close();
}
if(outputStream != null) {
outputStream.close();
}
if(socket != null) {
socket.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ChatServer chatServer = new ChatServer();
chatServer.service();
}
}
客户端:
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class ChatClient {
private int port = 8080;
public ChatClient() {
}
public ChatClient(int port) {
this.port = port;
}
private void consumer() {
System.out.println("客户端开始发送数据");
try {
Socket client = new Socket("localhost", 8081);
OutputStream outputStream = client.getOutputStream();
try {
outputStream.write("这里是8080端口".getBytes(StandardCharsets.UTF_8));
} finally {
if(outputStream != null) {
outputStream.close();
}
if(client != null) {
client.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ChatClient client = new ChatClient();
client.consumer();
}
}
运行结果:
BIO(同步阻塞IO模式)
每一个客户端的请求都需要服务端开启一个线程处理。
package com.alone.study.chat.bio;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newFixedThreadPool;
public class ChatServer {
/**
* 监听端口号
*/
private int port = 8081;
/**
* 处理socket的线程池
*/
private static final ExecutorService EXECUTOR_SERVICE = newFixedThreadPool(10);
private List<Socket> sockets = new ArrayList<>(10);
public ChatServer() {
}
public ChatServer(int port) {
this.port = port;
}
public void service() {
try {
System.out.println("服务器开始建立连接");
// 建立服务器连接
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器开始监听");
// 开始监听
Socket socket = serverSocket.accept();
sockets.add(socket);
EXECUTOR_SERVICE.submit(new SocketThread(socket));
Thread.sleep(2000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
if(sockets != null) {
for (Socket socket : sockets) {
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) {
ChatServer chatServer = new ChatServer();
chatServer.service();
}
private class SocketThread implements Runnable {
private Socket socket;
public SocketThread() {
}
public SocketThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
System.out.println("开始处理来自" + socket.getRemoteSocketAddress() + "的请求");
// 接收客户端的消息
readFromClient();
// 回复客户端说已收到
sendToClient();
}
private void sendToClient() {
OutputStream outputStream = null;
// 回复客户端
try {
outputStream = socket.getOutputStream();
// 发送消息给客户端
outputStream.write("我接收到了".getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流和连接
if(outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void readFromClient() {
// 接收客户端的数据
BufferedReader reader = null;
try {
System.out.println("开始获取客户端接收的消息");
// 获取输入流,读取客户端传过来的信息
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
System.out.println("从客户端接收到一条消息,内容为:" + line);
}
System.out.println("结束获取客户端接收的消息");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流和连接
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
package com.alone.study.chat.bio;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newFixedThreadPool;
public class ChatClient {
private int port = 8080;
private static final ExecutorService EXECUTOR_SERVICE = newFixedThreadPool(1);
public ChatClient() {
}
public ChatClient(int port) {
this.port = port;
}
private void consumer() {
System.out.println("客户端开始发送数据");
try {
Socket client = new Socket("localhost", 8081);
OutputStream outputStream = client.getOutputStream();
try {
outputStream.write("这里是8080端口".getBytes(StandardCharsets.UTF_8));
System.out.println("客户端结束发送数据");
} finally {
if(outputStream != null) {
outputStream.close();
}
if(client != null) {
client.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ChatClient client = new ChatClient();
client.consumer();
}
}
不太理解上面这个服务端为啥会报错。
NIO
to be continue…
参考资料
1.java的socket连接,聊天室通信实现
2. 简述Socket连接的过程
3. Java网络编程之通过代码实现Socket通信
4. BIO、NIO、AIO实现聊天室功能
5. 同步、异步、阻塞、非阻塞傻傻分不清?