java tcp多人聊天室

简介: java tcp多人聊天室

TCP的多人聊天室


上次写了一个只能两个人通信的TCP,这次写了个可以多人聊天的,利用多线程实现。


设计模式:


服务端:首先运行服务器,然后启动一个专门处理客户端消息的线程,然后监听是否有客户端连接,如果有人连接就单独为这个客户端开辟一个线程来处理。有多少人就开辟几个线程,并把客户端的消息放到消息集合里面,并把这些消息发送给出自己之外的其他所有人。


客户端:连接服务器后就会发送一条消息给服务器告诉服务器我已经连上来了,并开启一个线程专门接收服务器发送的信息。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
 * 
 * @Description 多人聊天服务器
 * @author Bush罗
 * @date 2018年4月3日
 *
 */
public class Server extends ServerSocket {
  private static final int SERVER_PORT = 5566;
  private static boolean isPrint = false;// 是否输出消息标志
  private static List<String> user_list = new ArrayList<String>();// 登录用户集合
  private static List<ServerThread> thread_list = new ArrayList<ServerThread>();// 服务器已启用线程集合
  private static LinkedList<Message> message_list = new LinkedList<Message>();// 存放用户消息的队列
  /**
   * 创建服务端Socket,创建向客户端发送消息线程,监听客户端请求并处理
   */
  public Server() throws IOException {
    super(SERVER_PORT);// 创建ServerSocket
    new PrintOutThread();// 处理所有客户端发送的消息
    System.out.println("服务器已启动");
    try {
      while (true) {// 监听客户端请求,启个线程处理
        Socket socket = accept();
        new ServerThread(socket);
      }
    } catch (Exception e) {
    } finally {
      close();
    }
  }
  /**
   * 监听是否有消息在队列里的线程类,向除自己之外的客户端发送消息
   */
  class PrintOutThread extends Thread {
    public PrintOutThread() {
      start();
    }
    @Override
    public void run() {
      while (true) {
        //如果消息队列没有消息则暂停当前线程,把cpu片段让出给其他线程,提高性能
        if (!isPrint) {
          try {
            Thread.sleep(500);
            sleep(100);
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          continue;
        }
        // 将缓存在队列中的消息按顺序发送到各客户端,并从队列中清除。
        Message message = (Message) message_list.getFirst();
        // 对所有的用户的线程遍历,如果不是自己发的消息就广播给其他人
        for (int i = 0; i < thread_list.size(); i++) {
          // 由于添加线程和用户是一起的,所以i所对应的用户就是i所对应的线程,可以根据这个判断是不是自己的线程
          ServerThread thread = thread_list.get(i);
          if (message.getName() != user_list.get(i)) {
            thread.sendMessage(message);
          }
        }
        message_list.removeFirst();
        isPrint = message_list.size() > 0 ? true : false;
      }
    }
  }
  /**
   * 服务器线程类
   */
  class ServerThread extends Thread {
    // 客户端
    private Socket client;
    // 打印流
    private PrintWriter out;
    // 读取客户端发的消息的缓冲流
    private BufferedReader in;
    // 客户名字
    private String name;
    public ServerThread(Socket s) throws IOException {
      client = s;
      out = new PrintWriter(client.getOutputStream(), true);
      in = new BufferedReader(new InputStreamReader(
          client.getInputStream()));
      in.readLine();
      start();
    }
    @Override
    public void run() {
      out.println("成功连上聊天室,请输入你的名字:");
      System.out.println(getName());
      try {
        int flag = 0;
        String line = in.readLine();
        while (!"byeClient".equals(line)) {
          // 查看在线用户列表
          if ("showuser".equals(line)) {
            out.println(this.listOnlineUsers());
            line = in.readLine();
          }
          if ("showmessage".equals(line)) {
            out.println(this.listmassage());
            line = in.readLine();
          }
          // 第一次进入,保存名字
          if (flag == 0) {
            name = line;
            user_list.add(name);
            thread_list.add(this);
            out.println(name + "你好,可以开始聊天了...");
            System.out.println(name + "连接服务器");
            pushMessage(name, "进入聊天室");
          } else {
            pushMessage(name, line);
          }
          flag++;
          line = in.readLine();
          System.out.println(name + ":" + line);
        }
        out.println("byeClient");
      } catch (Exception e) {
        e.printStackTrace();
      } finally {// 用户退出聊天室
        try {
          client.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
        thread_list.remove(this);
        user_list.remove(name);
        pushMessage(name, "退出了聊天室");
      }
    }
    // 放入消息队列末尾,准备发送给客户端
    public void pushMessage(String name, String msg) {
      Message message = new Message(name, msg);
      // 放入用户信息
      message_list.addLast(message);
      // 表示可以向其他用户发送消息
      isPrint = true;
    }
    // 向客户端发送一条消息
    public void sendMessage(Message message) {
      out.println(message.getName() + ":" + message.getMessage());
    }
    // 统计在线用户列表
    private String listOnlineUsers() {
      String s = "--- 在线用户列表 ---\015\012";
      for (int i = 0; i < user_list.size(); i++) {
        s += "[" + user_list.get(i) + "]\015\012";
      }
      s += "--------------------";
      return s;
    }
    // 统计在线用户列表
    private String listmassage() {
      String s = "--- 消息列表 ---\015\012";
      for (int i = 0; i < message_list.size(); i++) {
        s += "[" + message_list.get(i) + "]\015\012";
      }
      s += "--------------------";
      return s;
    }
  }
  public static void main(String[] args) throws IOException {
    new Server();// 启动服务端
  }
}
// 消息类,用户以及用户发的一条消息
class Message {
  // 用户名
  String client;
  // 消息
  String message;
  public Message() {
    super();
    // TODO Auto-generated constructor stub
  }
  public Message(String client, String message) {
    super();
    this.client = client;
    this.message = message;
  }
  public String getName() {
    return client;
  }
  public void setName(String name) {
    this.client = name;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
  @Override
  public String toString() {
    return "Message [client=" + client + ", message=" + message + "]";
  }
}

客户端代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
 * 
 * @Description 多人聊天客户端
 * @author Bush罗
 * @date 2018年4月3日
 *
 */
public class SocketClient extends Socket{
    private static final String SERVER_IP = "127.0.0.1";
    private static final int SERVER_PORT = 5566;
    private Socket client;
    private PrintWriter out;
    private BufferedReader in;
    /**
     * 与服务器连接,并输入发送消息
     */
    public SocketClient() throws Exception{
        super(SERVER_IP, SERVER_PORT);
        client = this;
        out = new PrintWriter(this.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(this.getInputStream()));
        new readLineThread();
        out.println("我已经连接服务器");
        while(true){
            in = new BufferedReader(new InputStreamReader(System.in));
            String input = in.readLine();
            out.println(input);
        }
    }
    /**
     * 用于监听服务器端向客户端发送消息线程类
     */
    class readLineThread extends Thread{
        private BufferedReader buff;
        public readLineThread(){
            try {
                buff = new BufferedReader(new InputStreamReader(client.getInputStream()));
                start();
            } catch (Exception e) {
            }
        }
        @Override
        public void run() {
            try {
                while(true){
                    String result = buff.readLine();
                    if("byeClient".equals(result)){//客户端申请退出,服务端返回确认退出
                        break;
                    }else{//输出服务端发送消息
                        System.out.println(result);
                    }
                }
                in.close();
                out.close();
                client.close();
            } catch (Exception e) {
            }
        }
    }
    public static void main(String[] args) {
        try {
            new SocketClient();//启动客户端
        } catch (Exception e) {
        }
    }
}

效果图:开了一个服务器连个客户端:

微信图片_20221209211211.png我的编码格式是utf-8的

相关文章
|
4月前
|
网络协议 Java
Java之UDP,TCP的详细解析
练习四:文件名重复
31 0
|
5月前
|
数据采集 网络协议 Java
Java爬虫框架下代理使用中的TCP连接池问题及解决方案
Java爬虫框架下代理使用中的TCP连接池问题及解决方案
|
7月前
|
网络协议 Java
Java TCP通信详解
TCP(Transmission Control Protocol)是一种面向连接的、可靠的网络传输协议,它提供了端到端的数据传输和可靠性保证。TCP通信适用于对数据传输的可靠性和完整性要求较高的场景,如文件传输、网页浏览等。本文将详细介绍Java中如何使用TCP协议进行网络通信,包括TCP套接字、服务器和客户端的创建、数据传输等。
128 0
|
6月前
|
网络协议 Java
【Java】TCP的三次握手和四次挥手
【Java】TCP的三次握手和四次挥手
|
7月前
|
网络协议 Java 容器
Java实现聊天室
Java实现聊天室
80 0
|
1天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
5月前
|
监控 网络协议 Java
Java TCP长连接详解:实现稳定、高效的网络通信
Java TCP长连接详解:实现稳定、高效的网络通信
|
1月前
|
网络协议 Java
Java基于TCP的网络编程
Java基于TCP的网络编程
|
2月前
|
网络协议 Java 数据安全/隐私保护
如何使用Java实现基于TCP/IP协议的即时通讯系统
TCP/IP协议是现代计算机网络通信中最常用的协议之一,而即时通讯系统则是当前互联网应用中非常普遍的一种场景。本文将介绍如何使用Java编程语言来实现基于TCP/IP协议的即时通讯系统,包括建立服务端和客户端、发送和接收消息等方面的详细步骤和示例。
|
3月前
|
存储 网络协议 算法
TCP粘包问题与解决方案详解及Java代码演示
TCP粘包问题与解决方案详解及Java代码演示
29 0