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

回到顶部