BIO学习
1. BIO介绍
同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
2. 代码介绍BIO
2.1 简单通信
实现一个简单功能,服务器端启动之后等待客户端连接,连接之后互相通信就结束
2.1.1 服务器端
public class Server { public static void main(String[] args) throws IOException {
//服务器端绑定888端口
ServerSocket ss = new ServerSocket(888);
//这里一直循环是一直可以等待处理客户端请求,可以处理多个客户端请求,但是一次只能处理一个
while(true) {
//阻塞方法,一直等待客户端接入
Socket s = ss.accept();
//客户端接入后就开启一个线程与客户端通信
new Thread(() -> {
handle(s);
}).start();
}
}
static void handle(Socket s) {
try {
byte[] bytes = new byte[1024];
int len = s.getInputStream().read(bytes);
System.out.println(new String(bytes, 0, len));
s.getOutputStream().write(bytes, 0, len);
s.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.1.2 客户端
public class Client { public static void main(String[] args) throws IOException {
//和服务端建立连接
Socket s = new Socket("127.0.0.1", 888);
//向服务端发送一条信息
s.getOutputStream().write("HelloServer".getBytes());
s.getOutputStream().flush();
System.out.println("write over, waiting for msg back...");
byte[] bytes = new byte[1024];
//读取服务器端消息
int len = s.getInputStream().read(bytes);
System.out.println(new String(bytes, 0, len));
s.close();
}
}
2.2 两个用户通信
实现功能:服务端和客户端可以互相通信
2.2.1 服务端
public class Server { static ExecutorService executor = Executors.newFixedThreadPool(2);
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(888);
Socket socket = serverSocket.accept();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//开启一个线程,专门用于读取数据
executor.submit(()->{
try{
String line = null;
while (true){
line = reader.readLine();
System.out.println(line);
}
}catch (Exception e){}
});
//开启一个线程,专门用于从键盘读入数据之后通信
executor.submit(()->{
while (true){
try{
BufferedReader consoleReader = new BufferedReader( new InputStreamReader(System.in));
String input = consoleReader.readLine();
writer.write(input + "
");
writer.flush();
}catch (Exception e){}
}
});
while(true){}
}
}
2.2.2 客户端
public class Client { static ExecutorService executor = Executors.newFixedThreadPool(2);
public static void main(String[] args) throws Exception{
Socket socket = new Socket("127.0.0.1",888);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//开启一个线程,专门用于读取数据
executor.submit(()->{
try{
String line = null;
while (true){
line = reader.readLine();
System.out.println(line);
}
}catch (Exception e){}
});
//开启一个线程,专门用于从键盘读入数据之后通信
executor.submit(()->{
while (true){
try{
BufferedReader consoleReader = new BufferedReader( new InputStreamReader(System.in));
String input = consoleReader.readLine();
writer.write(input + "
");
writer.flush();
}catch (Exception e){}
}
});
while(true){}
}
}
2.3 多人通信
服务器端用于接收客户端数据并转发到其他客户端
2.3.1 服务器端
public class ChatServer { private int DEFAULT_PORT = 8888;
private final String QUIT = "quit";
private ServerSocket serverSocket;
/**
* 保存连接的客户端信息
*/
private Map<Integer, Writer> connectedClients;
public ChatServer() {
connectedClients = new HashMap<>();
}
/**
* 添加客户端
*
* @param socket
*/
public synchronized void addClient(Socket socket) throws IOException {
if (socket != null) {
int port = socket.getPort();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())
);
connectedClients.put(port, writer);
System.out.println("客户端[" + port + "]已连接到服务器");
}
}
/**
* 移除客户端
*
* @param socket
* @throws IOException
*/
public synchronized void removeClient(Socket socket) throws IOException {
if (socket != null) {
int port = socket.getPort();
if (connectedClients.containsKey(port)) {
connectedClients.get(port).close();
}
connectedClients.remove(port);
System.out.println("客户端[" + port + "]已断开连接");
}
}
/**
* 转发消息
*
* @param socket
* @param fwdMsg
*/
public synchronized void forwardMessage(Socket socket, String fwdMsg) throws IOException {
for (Integer id : connectedClients.keySet()) {
// 排除发送者本人
if (!id.equals(socket.getPort())) {
Writer writer = connectedClients.get(id);
writer.write(fwdMsg);
writer.flush();
}
}
}
/**
* 监听是否准备退出标志
*
* @param msg
* @return
*/
public boolean readyToQuit(String msg) {
return QUIT.equals(msg);
}
/**
* 关闭serverSocket
*/
public synchronized void close() {
if (serverSocket != null) {
try {
serverSocket.close();
System.out.println("关闭serverSocket");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void start() {
try {
// 监听端口
serverSocket = new ServerSocket(DEFAULT_PORT);
System.out.println("启动服务器,监听端口:" + DEFAULT_PORT + "...");
while (true) {
// 等待客户端连接
Socket socket = serverSocket.accept();
// 创建ChatHandler线程
new Thread(new ChatHandler(this, socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
public static void main(String[] args) {
ChatServer server = new ChatServer();
server.start();
}
}
public class ChatHandler implements Runnable { private ChatServer server;
private Socket socket;
public ChatHandler(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
@Override
public void run() {
try {
// 存储上线用户
server.addClient(socket);
// 读取用户发送的消息
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String msg = null;
while ((msg = reader.readLine()) != null) {
String fwdMsg = "客户端[" + socket.getPort() + "]:" + msg + "
";
System.out.println(fwdMsg);
// 将消息转发给聊天室里在线的其他用户
server.forwardMessage(socket, fwdMsg);
// 检查用户是否准备退出
if (server.readyToQuit(msg)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
server.removeClient(socket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.3.2 客户端
public class ChatClient { private final String DEFAULT_SERVER_HOST = "127.0.0.1";
private final int DEFAULT_SERVER_PORT = 8888;
private final String QUIT = "quit";
private Socket socket;
private BufferedReader reader;
private BufferedWriter writer;
/**
* 发送消息给服务器
*
* @param msg
* @throws IOException
*/
public void send(String msg) throws IOException {
if (!socket.isOutputShutdown()) {
writer.write(msg + "
");
writer.flush();
}
}
/**
* 从服务器接收消息
*
* @return
* @throws IOException
*/
public String receive() throws IOException {
String msg = null;
if (!socket.isInputShutdown()) {
msg = reader.readLine();
}
return msg;
}
/**
* 检查用户是否准备退出
*
* @param msg
* @return
*/
public boolean readyToQuit(String msg) {
return QUIT.equals(msg);
}
/**
* 关闭socket
*/
public void close() {
if (writer != null) {
try {
System.out.println("关闭socket");
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void start() {
try {
// 创建socket
socket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);
// 创建io流
reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())
);
// 处理用户的输入
new Thread(new UserInputHandler(this)).start();
// 读取服务器转发的消息
String msg = null;
while ((msg = receive()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
public static void main(String[] args) {
ChatClient chatClient = new ChatClient();
chatClient.start();
}
}
public class UserInputHandler implements Runnable { private ChatClient chatClient;
public UserInputHandler(ChatClient chatClient) {
this.chatClient = chatClient;
}
@Override
public void run() {
BufferedReader consoleReader = new BufferedReader(
new InputStreamReader(System.in)
);
while (true) {
try {
String input = consoleReader.readLine();
// 向服务器发送消息
chatClient.send(input);
// 检查用户是否准备退出
if (chatClient.readyToQuit(input)) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
以上是 BIO学习 的全部内容, 来源链接: utcz.com/z/517102.html