TCP多人聊天室的实现
1. 功能分析
1.1 客户端
- 功能:
- 数据发送
- 数据接收
- 聊天:
- 群聊
- 私聊
1.2 服务器
- 功能:
- 数据转发
- 用户注册
- 数据转发判断:
- 私聊
- 群聊
我们需要知道一点:一个用户对应着一个socket,所以我们需要将用户和socket进行绑定,我们可以使用Map来进行存储,Key用来存储用户id,Value用来存储对应的socket
代码
1. 服务器
public class Server{
private HashMap<Integer, UserSocket> userMap;
//累计访问人数,作为用户的id(userMap中的Key值)
private static int count = 0;
//初始化
public Server () {
userMap = new HashMap<>();
}
//服务器启动方法
public void start() throws IOException {
//启动服务器,监听端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器启动");
while (true) {
//接收用户请求
Socket socket = serverSocket .accept();
count += 1;
UserSocket userSocket = new UserSocket(count, socket);
userMap.put(count, userSocket);
// 启动当前UserSocket服务
new Thread(userSocket).start();
}
}
class UserSocket implements Runnable {
private DataInputStream inputstream;
private DataOutputStream outputStream;
//用户id
private int userId;
//用户名 ,这个是刚开始注册的时候客户端发送给服务器的
private String userName;
//连接标记
private boolean connection;
//构造方法
public UserSocket(int userId, Socket socket) {
this.userId = userId;
try {
inputStream = new DataInpuStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
connection = true;
} catch (IOException e) {
e.printStackTrace();
connetion = false;
}
try {
this.userName = InputStream.readUTF();
//广播所有人XXX上线了,自己除外
sendOther ("ID:" + this.userId + " " + this.userName + "来到直播间", true);
send("欢迎来到聊天室");
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 接收客户端发送的数据,用于转发操作
*/
public String receive() {
String msg = null;
try {
msg = inputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
connetion = false;
//设置的工具类,关闭资源
CloseUtil.closeAll(inputStream, outputStream);
}
return msg;
}
/*
* 发送数据到客户端
*/
public void send(String msg) {
try{
outputStream.writeUTF(msg);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
connetion = false;
CloseUtil.closeAll(inputStream, outputStream);
}
}
public void sendOther(String msg, boolean sys) {
//私聊@1:XXXXXX
if (msg.startsWith("@") && msg.contains(":")) {
//获取私聊的id
Integer id = Integer.parseInt(msg.substring(1, msg.indexOf(":")));
String newMsg = msg.substring(msg.indexOf(":"));
UserSocket userSocket = userMap.get(id);
if (userSocket != null) {
userSocket.send("ID:" + this.userId + " " + this.userName + "悄悄的对你说" + newMsg);
}
} else {
//群聊
Collection<UserSocket> values = userMap.values();
for (UserSocket userSocket : values) {
if (userSocket != this) {
// 判断是不是系统消息
if (sys) {
userSocket.send("系统公告:" + msg);
} else {
userSocket.send("ID:" + this.userId + " " + this.userName + msg);
}
}
}
}
}
@Override
public void run() {
while (connetion) {
// 使用receive收到的消息作为参数,同时标记非系统消息,调用sendOther
sendOther(receive(), false);
}
}
}
public static void main (String[] args) {
Server server = new Server();
try {
server.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 工具类
3. 客户端
3.1
3.2 ClientSend
public calss ClientSend implements Runnable {
private DataOutputStream outputStream;
private BufferedReader console;
private boolean connection;
public ClientSend(Socket socket, String userName) {
try {
outputStream = new DataOutputStream(socket.getOutputStream());
console = new BufferedReader(new InputStreamReader(System.in));
send(userName);
connection = true;
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
}
//从键盘上获取用户输入的数据
public String getMsgFromConsole() {
String msg = null;
try {
// 从键盘上读取一行数据
msg = console.readLine();
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
return msg;
}
//发送数据给服务器
public void send(String msg) {
try {
if (msg != null && !"".equals(msg)) {
outputStream.writeUTF(msg);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
}
@Override
public void run() {
while (connection) {
send(getMsgFromConsole());
}
}
}
3.3 ClientReceive
public class ClientReceive implements Runnable {
private DataInputStream inputStream;
private boolean connection;
public ClientReceive(Socket socket) {
try {
inputStream = new DataInputStream(socket.getInputStream());
connection = true;
} catch (IOException e) {
e.printStackTrace();
connection = false;
}
}
public void receive() {
String msg = null;
try {
msg = inputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(inputStream);
}
System.out.println(msg);
}
@Override
public void run() {
while (connection) {
receive();
}
}
}
4. 效果