本文章主要介绍基于多线程的Java聊天室的整体思路以及如何通过代码一步步的实现多线程的Java聊天室。
1. 聊天室具有4大功能
- 1. 具有用户上线注册和下线注销功能
- 2. 具有私聊功能
- 3. 具有群聊功能
- 4. 具有统计聊天室在线人数的功能
2. 基于多线程的聊天室的整体思路
- 1. 模式:对于聊天室就是处理多个客户端发送的请求与信息,从而需要一个服务器端去处理这些客户端请求与信息,故采用的是服务器端/客户端模式。
- 2. 客户端与服务器端的连接:既然是多个客户端发送的请求与信息从而交给服务器端处理,那么客户端与服务器端之间需要进行连接,在我的博客:Socket编程 中介绍到两台计算机之间如何通过使用套接字建立TCP连接,从而进行通信操作。稍后会通过分析以及代码的方式进行详细操作。
- 3. 处理多线程问题:关于客户端,客户端需要向服务器端发送信息,而客户端也需要接收服务器端的信息,故需要两个线程分别处理客户端向服务器发送信息和客户端接收服务器端信息。关于服务器端,由于服务器端是统一处理多个客户端发送的信息请求,故每当有一个客户端与该服务器端建立连接后,需要创建新的线程去单独处理该客户端发送的信息。
- 4. 客户端方面:客户端在与服务器端建立连接后,通过Socket对象获取输入输出流从而与服务器端之间进行通信。
- 5. 服务器端方面:服务器端的套接字ServerSocket对象在调用accept()方法侦听客户端的连接,当与客户端成功建立连接后,返回Socket对象,从而利用该Socket对象获取输入输出流从而与客户端进行通信。
3. 聊天室的具体实现
3.1 客户端与服务器端建立连接
利用Socket编程,客户端与服务器端建立连接的步骤如下:
(1)服务器端通过java.net.ServerSocket类的构造方法实例化ServerSocket对象,选择的构造方法如下:
public ServerSocket (int port) throws IOException
该构造方法需要传入参数:端口号,从而创建绑定到指定端口的服务器套接字。
(2)客户端通过java.net.Socket类的构造方法创建一个流套接字并将其连接到指定主机上的指定端口号,该构造方法如下:
public Socket(String host,int port) throws UnknowHostException,IOException
(3)服务器端的ServerSocket对象调用accept()方法侦听请求连接指定端口号的该服务器端的客户端,并在接收到客户端请求后返回服务器端的流套接字,即Socket对象,从而服务器端与客户端成功建立连接。
(4)客户端与服务器端之间的通信操作,java.net.Socket类就是提供客户端与服务器端相互通信的套接字。
获取Socket套接字的输入流的方法为:
public InputStream getInputStream() throws IOException
获取Socket套接字的输出流的方法为:
public OutputStream getOutputStream() throws IOException
在获取了服务器端与客户端的输入输出流之后,进行信息输入输出即可进行通信操作。
(5)服务器端与客户端之间通信结束后,需要关闭套接字,调用close()方法即可。close()方法如下:
public void close() throws IOException
经过以上的分析,下面通过代码的方式创建服务器端与客户端之间的连接以及通信操作。
- 服务器端:
package chat.room.server;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class SingleServer {
public static void main(String[] args) throws IOException {
//1.创建服务器端的ServerSocket对象,等待客户端连接其端口
ServerSocket serverSocket=new ServerSocket(6666);
System.out.println("服务器的端口号为:6666,正在等待客户端的连接...");
//2.侦听并接收服务器端的连接,返回套接字Socket对象
Socket socket=serverSocket.accept();
//3.获取客户端的输入流,读取客户端输入的内容
Scanner scanner=new Scanner(socket.getInputStream());
scanner.useDelimiter("\n");
if(scanner.hasNext()){
System.out.println("客户端发来消息:"+scanner.next());
}
//4.获取客户端的输出流,向客户端输出内容
PrintStream printStream=new PrintStream(socket.getOutputStream());
printStream.println("客户端你好!我是服务器端:"+serverSocket.getLocalPort());
//5.关闭流
serverSocket.close();
}
}
- 客户端:
package chat.room.client;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class SingleClient {
public static void main(String[] args) throws IOException {
//1.客户端连接服务器端,返回套接字Socket对象
Socket socket=new Socket("127.0.0.1",6666);
//2.获取服务器端的输出流,向服务器端输出内容
PrintStream printStream=new PrintStream(socket.getOutputStream());
printStream.println("我是客户端"+socket.getLocalPort());
//3.获取服务器端的输入流,读取服务器端的内容
Scanner scanner=new Scanner(socket.getInputStream());
scanner.useDelimiter("\n");
if(scanner.hasNext()){
System.out.println(scanner.next());
}
//4.关闭流
socket.close();
}
}
3.2 多线程客户端的实现
客户端方面,需要做的只有两件事:1. 向服务器端发送信息 2. 接收服务器端信息
故创建两个线程:
3.2.1 客户端读取服务器端信息的线程
- 既然客户端需要读取服务器端信息就需要客户端获取服务器端的输入流,从而将信息显示到客户端