Java Socket实现简易多人聊天室传输聊天内容或文件
Java小练手项目:用Java Socket实现多人聊天室,聊天室功能包括传输聊天内容或者文件。相比于其它的聊天室,增加了传输文件的功能供参考。
模块拆解
分成服务端和客户端两部分来写
服务端包括监听线程和处理收发信线程:
- 创建监听线程,监听客户端的连接。将每个连接的客户端加入维护的列表,并为每个连接的客户端开启一个处理收发信的线程。
- 在每个客户端的收发信线程中,接收每个客户端发回的消息,并对其进行转发到相应接收的客户端上,以此实现多人聊天室。
- 添加处理传输文件的判断,通过在传输的字节数组中添加标志位来区分传输的是文本消息,还是文件。
客户端包括发送消息线程和接收消息线程:
- 发送消息线程,用来处理用户的输入信息,判断输入的是文本信息还是文件,并修改传输的字节数组标志位进行区分。最后将信息传输给服务器。
- 接收消息线程,用来处理服务器发回的信息,根据标志位判断输入的是文本信息还是文件,并做相应处理。如果是文本信息,则显示在控制台,如果是文件,则保存在指定目录下。
项目的目录结构如下所示
接下来,给出实际的代码进行分析
项目代码
服务器端
监听线程
package Server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class MultiServer {
public static void main(String[] args) {
ServerSocket ss = null;
Socket s = null;
// 定义一个List列表来保存每个客户端,每新建一个客户端连接,就添加到List列表里。
List<Socket> listSocket = new ArrayList<>();
try {
// 1. 创建ServerSocket类型的对象并提供端口号
ss = new ServerSocket(9999);
// 2. 等待客户端的连接请求,调用accept方法
// 采用多线程的方式,允许多个用户请求连接。
int i = 0;
while (true) {
System.out.println("等待客户端的连接请求...");
s = ss.accept();
listSocket.add(s);
//sArr[i] = s;
i++;
System.out.printf("欢迎用户%d加入群聊!\n", i);
System.out.printf("目前群聊中共有%d人\n", listSocket.size());
InetAddress inetAddress = s.getInetAddress();
System.out.println("客户端" + inetAddress + "连接成功!");
// 调用多线程方法,每一个连上的客户端,服务器都有一个线程为之服务
new MultiServerThread(s, inetAddress, listSocket).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭流
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
上述代码实现服务器监听客户端连接,利用 accept
方法,每加入一个客户端,服务器都创建一个线程为之服务,同时将其加入一个List集合中,用来保存已加入聊天室的所有客户端。
处理收发信的线程
package Server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
public class MultiServerThread extends Thread {
private Socket s;
private InetAddress inetAddress;
private List<Socket> listSockets;
public MultiServerThread(Socket s, InetAddress inetAddress, List<Socket> listSockets) {
this.s = s;
this.inetAddress = inetAddress;
this.listSockets = listSockets;
}
public void BroadCast(Socket s, byte[] by, int res)
{
// 将服务器接收到的消息发送给除了发送方以外的其他客户端
int i = 0;
for (Socket socket: listSockets)
{
if (s!=socket) // 判断不是当前发送的客户端
{
System.out.println("发送给用户: " + listSockets.indexOf(socket));
BufferedOutputStream ps = null;
try {
ps = new BufferedOutputStream(socket.getOutputStream());
ps.write(by, 0, res); // 写入输出流,将内容发送给客户端的输入流
ps.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 服务器与客户端的交互线程
@Override
public void run() {
BufferedInputStream ois = null;
BufferedOutputStream oos = null;
try {
ois = new BufferedInputStream(s.getInputStream());
oos = new BufferedOutputStream(s.getOutputStream());
int i = 0;
while (true) {
//System.out.println("进入MultiChatServerThread");
byte[] by = new byte[1024+2];
//System.out.println("by.length: " + by.length);
int res = 0;
res = ois.read(by);
// 对读取到的字节数组第一位位置进行修改,标识该数据流是由哪个用户发送来的
by[0] = (byte)listSockets.indexOf(s);
if (by[1] == 2){