当前位置:   article > 正文

Java 网络编程之TCP(二):基于BIO的聊天室

Java 网络编程之TCP(二):基于BIO的聊天室

在上一篇【Java 网络编程之TCP(一):基于BIO】中,介绍Java中I/O和TCP的基本概念,本文在上文的基础上,实现一个基本的聊天室的功能。

聊天室需求描述:

聊天客户端:发送消息给所有其他客户端,接收其他客户端的消息

实现说明:

要想实现上面的聊天室的功能,我们需要一个服务端,和客户端

服务端:接收客户端的消息,并转发给其他客户端

客户端:发送消息给服务端,接收服务端的消息

由于基于BIO,那么服务端都需要用两个线程,来分别进行收发消息

代码如下:

服务端:

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. import java.util.LinkedList;
  6. import java.util.List;
  7. /**
  8. * 基于BIO的TCP网络通信的服务端,可以接收多个客户端连接,通过字节流接收客户端发送的消息;
  9. * 并发每个客户端的数据,转发给其余所有的客户端
  10. * 一个客户端需要使用一个线程
  11. * todo:线程资源复用; 字符流readLine 没有换行符阻塞的问题
  12. *
  13. * @author freddy
  14. */
  15. class ChatServer {
  16. // 存放所有和服务端建立连接的客户端,客户端断开,需要去除
  17. public static List<Socket> clients = new LinkedList<>();
  18. public static void main(String[] args) throws IOException {
  19. // 开启server 监听端口
  20. ServerSocket serverSocket = new ServerSocket(9999);
  21. while (true) {
  22. Socket client = serverSocket.accept(); // 阻塞操作,需要新的线程处理客户端
  23. // 客户端保存,方便后面转发数据
  24. clients.add(client);
  25. // 接收Client数据,并转发
  26. new Thread(new ServerThread(client, clients)).start();
  27. }
  28. }
  29. }
  30. /**
  31. * 服务端的线程,一个客户端对应一个
  32. */
  33. class ServerThread implements Runnable {
  34. Socket socket;
  35. List<Socket> clients;
  36. public ServerThread(Socket socket, List<Socket> clients) {
  37. this.socket = socket;
  38. this.clients = clients;
  39. }
  40. @Override
  41. public void run() {
  42. // 获取输入流程,读取用户输入
  43. // 持续接收Client数据,并打印
  44. System.out.println("server had a client" + socket);
  45. try (InputStream inputStream = socket.getInputStream()) {
  46. byte[] buffer = new byte[1024];
  47. int len;
  48. // read操作阻塞,直到有数据可读
  49. // -1 表示流关闭,或者读到文件末尾
  50. while ((len = inputStream.read(buffer)) != -1) {
  51. System.out.println("serer receive data from " + socket + " : " + new String(buffer, 0, len));
  52. // 转发数据到其他Client
  53. for (Socket client : clients) {
  54. if (client != socket) {
  55. client.getOutputStream().write(new String(buffer, 0, len).getBytes());
  56. }
  57. }
  58. }
  59. } catch (IOException e) {
  60. System.out.println(socket + " disconnect ");
  61. // 去除当前client
  62. clients.remove(socket);
  63. }
  64. }
  65. }

客户端代码:

  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.net.Socket;
  5. /**
  6. * 基于BIO的TCP网络通信的客户端,接收控制台输入的数据,然后通过字节流发送给服务端
  7. *
  8. * @author freddy
  9. */
  10. class ChatClient {
  11. public static void main(String[] args) throws IOException {
  12. // 连接server
  13. Socket serverSocket = new Socket("localhost", 9999);
  14. System.out.println("client connected to server");
  15. // 读取用户在控制台上的输入,并发送给服务器
  16. new Thread(new ClientThread(serverSocket)).start();
  17. // 接收服务端发送过来的数据
  18. try (InputStream serverSocketInputStream = serverSocket.getInputStream();) {
  19. byte[] buffer = new byte[1024];
  20. int len;
  21. while ((len = serverSocketInputStream.read(buffer)) != -1) {
  22. System.out.println(
  23. "client receive data from server" + serverSocketInputStream + " : " + new String(buffer, 0, len));
  24. }
  25. }
  26. }
  27. }
  28. class ClientThread implements Runnable {
  29. private Socket serverSocket;
  30. public ClientThread(Socket serverSocket) {
  31. this.serverSocket = serverSocket;
  32. }
  33. @Override
  34. public void run() {
  35. // 读取用户在控制台上的输入,并发送给服务器
  36. InputStream in = System.in;
  37. byte[] buffer = new byte[1024];
  38. int len;
  39. try (OutputStream outputStream = serverSocket.getOutputStream();) {
  40. // read操作阻塞,直到有数据可读,由于后面还要接收服务端转发过来的数据,这两个操作都是阻塞的,所以需要两个线程
  41. while ((len = in.read(buffer)) != -1) {
  42. System.out.println("client receive data from console" + in + " : " + new String(buffer, 0, len));
  43. // 发送数据给服务器端
  44. outputStream.write(new String(buffer, 0, len).getBytes()); // 此时buffer中是有换行符
  45. }
  46. } catch (IOException e) {
  47. throw new RuntimeException(e);
  48. }
  49. }
  50. }

测试:

先开启服务端,再开启两个客户端,在客户端1的控制台发送i'm client1,在客户端1的控制台发送this is client2,通过日志可以看到,聊天室的功能符合要求:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/485846
推荐阅读
相关标签
  

闽ICP备14008679号