基于BIO实现 Client与Server通信
1、BIO模型中服务端与客户端的响应过程
根据上图可清晰看出,Client与Server的响应流程如下:
1、Server 服务器端 serverSocket
先要和端口
进行绑定
ServerSocket serverSocket = new ServerSocket(6767);
2、绑定完成后,通过accept方法
,阻塞式等待客户端的连接,这个方法是阻塞式调用
,直到有客户端连接才往下执行;
Socket accept = serverSocket.accept();
3、客户端创建Socket
对象,绑定
服务器的ip地址
与端口号
,与服务器进行连接
//建立socket连接 host=127.0.0.1 port=6767
socket = new Socket(host, port);
4、服务器接收到客户端的连接请求,accept方法获取到客户端的socket信息
,连接成功
服务器与客户端创建各自的io流
,实现全双工通信
2、案例一(BIO 版 服务端——客户端 聊天实现)
客户端:
package com.xiaojie.net;
import java.io.*;
import java.net.Socket;
/**
* @author Mrli
* @date 2020/9/25 19:36
*/
public class Client {
public static void main(String[] args) {
final String host = "127.0.0.1";
final int port = 6767;
final String QUIT = "quit";
Socket socket = null;
BufferedReader reader = null;
BufferedWriter writer = null;
try {
//建立socket连接
socket = new Socket(host, port);
//获取输入字符流
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()
));
//获取输出字符流
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()
));
//获取输入字符流
BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = scan.readLine();
//向服务器发送消息
writer.write(msg + "\n");
writer.flush();
//接收消息
String line = reader.readLine();
System.out.println("server:" + line);
if (msg.equals(QUIT)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(writer != null) {
try {
writer.close();
System.out.println("Client close!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端:
package com.xiaojie.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author Mrli
* @date 2020/9/25 19:37
*/
public class Server {
public static void main(String[] args) {
final int port = 6767;
final String QUIT = "quit";
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("服务器已启动,监听端口:" + port);
while(true) {
Socket accept = serverSocket.accept();
System.out.println("客户端" + accept.getPort() + ":" + "已经连接");
//获取输入字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(
accept.getInputStream()
));
//获取输出字符流
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
accept.getOutputStream()
));
String msg = null;
while ((msg = reader.readLine()) != null ) {
//接收消息
System.out.println("client[" + accept.getPort() + "]:" +msg);
//转发到Client,
writer.write( msg + "\n");
writer.flush();
if(msg.equals(QUIT)) {
System.out.println("client close!");
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
client端:
服务端:
3、案例二(BIO多客户端聊天室实现)
此案例分为:
Server(服务端)
ChartHandler(服务端多线程监听客户端发送的信息)
Client(客户端)
InputHandler( 客户端监听用户输入的信息)
Server.java
package com.xiaojie.net.bio.chatRoom;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* @author Mrli
* @date 2020/9/26 16:20
* 多人聊天室,服务端
*/
public class Server {
private int port = 6767;
private final String QUIT = "quit";
private ServerSocket serverSocket = null;
/**
* 存放所有的客户端连接(socket、writer)
*/
private Map<Integer, Writer> clientList;
/**
*构建线程池
*/
private ExecutorService executor;
/**
* 构造初始化
*/
public Server() {
this.clientList = new HashMap<>();
this.executor = new ThreadPoolExecutor(10,10,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* 添加客户端
* @param socket
*/
public synchronized void addClient(Socket socket) throws IOException {
if(socket != null) {
int key = socket.getPort();
Writer writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()
));
clientList.put(key,writer);
System.out.println("客户端["+port + "]:已连接!");
}
}
/**
* 删除客户端
* @param socket
*/
public synchronized void removeClient(Socket socket) throws IOException {
if(socket != null) {
int key = socket.getPort();
clientList.get(key).close();
clientList.remove(key);
System.out.println("客户端["+port + "]:已断开连接!");
}
}
/**
* 将消息转发给所有客户端
* @param socket
* @param msg
*/
public synchronized void forwardMsg(Socket socket, String msg) throws IOException {
for (Integer key : clientList.keySet()) {
if(!key.equals(socket.getPort())) {
Writer writer = clientList.get(key);
writer.write(msg);
writer.flush();
}
}
}
/**
* 判断用户消息是否为quit指令
* @param msg
* @return
*/
public synchronized boolean isQuit(String msg) {
return QUIT.equals(msg);
}
/**
* 关闭serverSocket
*/
public synchronized void close(){
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void start() {
try {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务器启动,正在监听端口:" + port);
while (true) {
//监听客户端连接
Socket socket = serverSocket.accept();
//创建线程处理
//new Thread(new ChartHandler(this,socket)).start();
executor.execute(new ChartHandler(this,socket));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
/**
* 通过主线程启动server
* @param args
*/
public static void main(String[] args) {
Server server = new Server();
server.start();
}
}
ChartHandler.java
package com.xiaojie.net.bio.chatRoom;
import java.io.*;
import java.net.Socket;
/**
* @author Mrli
* @date 2020/9/26 16:22
*/
public class ChartHandler implements Runnable{
private Server server;
private Socket socket;
/**
* 构造器初始化server、socket
* @param server
* @param socket
*/
public ChartHandler(Server server, Socket socket) {
this.server = server;
this.socket = socket;
}
/**
* 线程主要业务逻辑
*/
@Override
public void run() {
try {
//添加客户端socket
server.addClient(socket);
//获取客户端输入字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()
));
//阻塞获取客户端的消息
String msg = null;
while ((msg = reader.readLine()) != null) {
String fwdmsg = "客户端[" + socket.getPort() + "] : " + msg + "\n";
System.out.println(fwdmsg);
//转发消息给所有客户端
server.forwardMsg(socket,fwdmsg);
//检测是否退出
if(server.isQuit(msg)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
server.removeClient(socket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client.java
package com.xiaojie.net.bio.chatRoom;
import java.io.*;
import java.net.Socket;
/**
* @author Mrli
* @date 2020/9/26 16:20
* 多人聊天室客户端
*/
public class Client {
private final String host = "127.0.0.1";
private final int port = 6767;
private final String QUIT = "quit";
private Socket socket;
private BufferedReader reader;
private BufferedWriter writer;
/**
* 默认构造器
*/
public Client() {
}
/**
* 给服务端发送消息
* @param msg
*/
public void sendMsg(String msg) throws IOException {
//socket的输出流未关闭
if(!socket.isOutputShutdown()) {
writer.write(msg+"\n");
writer.flush();
}
}
/**
* 接收服务端消息
*/
public String receive() throws IOException {
String msg = null;
//socket的输入流未关闭
if(!socket.isInputShutdown()) {
msg = reader.readLine();
}
return msg;
}
/**
* 检测是否退出
* @param msg
* @return
*/
public boolean isQuit(String msg) {
return QUIT.equals(msg);
}
/**
* 关闭socket、输出流
*/
public void close() {
try {
writer.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 多人聊天室客户端启动
*/
public void start() {
try {
//创建socket,与serverSocket简历连接
socket = new Socket(host,port);
//创建IO流
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()
));
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()
));
//创建线程处理,
new Thread(new InputHandler(this)).start();
//监听服务器转发的消息
String msg = null;
while ((msg = receive()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
close();
}
}
/**
* 通过Client主线程启动客户端
* @param args
*/
public static void main(String[] args) {
Client client = new Client();
client.start();
}
}
InputHandler.java
package com.xiaojie.net.bio.chatRoom;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author Mrli
* @date 2020/9/26 16:22
*/
public class InputHandler implements Runnable{
private Client client;
/**
* 初始化构造函数
* @param client
*/
public InputHandler(Client client) {
this.client = client;
}
/**
* 主要监听用户输入状态
*/
@Override
public void run() {
//获取本地输入流,监听用户输入
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
try {
String msg = reader.readLine();
if(msg != null) {
client.sendMsg(msg);
}
if(client.isQuit(msg)) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BIO学习到这里,后面IO学习继续更新!