java tcp 多人聊天_Java TCP简易多人聊天室内

这是一个简单的Java TCP多人聊天室示例,通过启动服务器端和多个客户端,用户可以输入用户名并进行聊天。当用户发送消息时,所有在线用户都会收到。服务器端负责处理客户端连接,而客户端线程处理接收和发送消息。
摘要由CSDN通过智能技术生成

一.说明:

​本例是一个简易的Java TCP多人聊天室,先启动服务器端,再启动客户端,客户端敲入用户名,然后可以开始聊天,敲入信息,每一个在线的用户都会收到相应信息。

演示如下图:

3ae5411c3604c330141c5dd720f5a715.gif

二.服务器端代码

ServerMain.java

import java.io.*;

public class ServerMain {

public static void main(String[] args) {

ChatServer server = new ChatServer();

try {

server.ServerStart();

}

catch (IOException e) {

e.printStackTrace();

}

}

}

ChatServer.java

import java.io.*;

import java.net.*;

import java.util.HashMap;

public class ChatServer {

// 设定端口号

private final int port = 12345;

public static HashMap clientMap = new HashMap<>();

public static int onlineNum = 0;

public static void ServerSendToAll(ClientThread thread,String msg) throws IOException {

for (ClientThread t : clientMap.keySet()) {

if (t.clientName.equals(thread.clientName)) {

Message.printMessage(msg);

continue;

}

t.objOutput.writeObject(new DataPacket(Message.CMD.SENDALL, msg));

}

}

public static void ServerSendToAll(ClientThread thread) throws IOException {

onlineNum++;

// 服务端记录

Message.printMessage(thread.clientName + "上线了,当前在线人数" + onlineNum + "人");

// 群发

for (ClientThread t : clientMap.keySet()) {

if (t.login == true) {

t.objOutput.writeObject(new DataPacket(Message.CMD.LOGIN, "当前在线人数" + onlineNum + "人"));

}

}

}

public void ServerStart() throws IOException {

ServerSocket serverSocket = new ServerSocket(port);

Message.printMessage("Server Start.");

// 死循环等待客户端连接

while (true) {

// 每来一个客户端连接,保存Socket对象

Socket clientSocket = serverSocket.accept();

ClientThread client = new ClientThread(clientSocket);

// 每连接一个客户端,创建一个对应的线程类

Thread clientThread = new Thread(client);

// 添加对象-Socket映射

clientMap.put(client, clientSocket);

// 启动线程

clientThread.start();

}

}

}

ClientThread.java

import java.io.*;

import java.net.*;

/*

线程类:处理每一个登录成功的客户端

*/

public class ClientThread implements Runnable {

// 保存每个客户端Socket

private Socket client = null;

public ObjectInputStream objInput = null;

public ObjectOutputStream objOutput = null;

public String clientName = null;

public boolean login = false;

public ClientThread(Socket client) {

this.client = client;

try {

this.objInput = new ObjectInputStream(this.client.getInputStream());

this.objOutput = new ObjectOutputStream(this.client.getOutputStream());

} catch (IOException e) {

Message.printLog(Message.logType.ERROR, "ClientThread:IOException!", true);

e.printStackTrace();

}

}

public int HandleReceiveMsg(Object data) throws IOException {

DataPacket dataPacket = (DataPacket) data;

switch (dataPacket.cmd) {

case LOGIN:

clientName = dataPacket.msg;

login = true;

ChatServer.ServerSendToAll(this);

break;

case SEND:

// 收到消息,调用群发其他用户

String msg = this.clientName + "说:" + dataPacket.msg;

ChatServer.ServerSendToAll(this, msg);

break;

case SENDALL:

// 收到其他用户群发的消息

SendMessage(dataPacket);

break;

}

return 0;

}

public void SendMessage(DataPacket data) throws IOException {

this.objOutput.writeObject(data);

}

public Object ReceiveMessage() throws ClassNotFoundException, IOException {

try {

Object obj = this.objInput.readObject();

return obj;

} catch (EOFException e) {

}

return null;

}

@Override

public void run() {

try {

Object data;

while ((data = ReceiveMessage()) != null) {

HandleReceiveMsg(data);

}

} catch (SocketException e) {

login = false;

} catch (IOException e) {

Message.printLog(Message.logType.ERROR, "ClientThread-run:IOException!", true);

e.printStackTrace();

} catch (ClassNotFoundException e) {

Message.printLog(Message.logType.ERROR, "ClientThread-run:ClassNotFoundException!", true);

e.printStackTrace();

} finally {

// 用户断开连接

if (login == false) {

// 从HashMap 移走映射

ChatServer.clientMap.remove(this);

// 释放资源

if (client != null) {

try {

client.close();

} catch (IOException e) {

e.printStackTrace();

}

}

ChatServer.onlineNum--;

// 打印信息

String msg = this.clientName + "下线了,当前在线" + ChatServer.onlineNum + "人";

Message.printMessage(msg);

try {

ChatServer.ServerSendToAll(this, msg);

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

三.客户端代码

ClientMain.java

public class ClientMain {

public static void main(String[] args) {

ChatClient client = new ChatClient();

client.ClientStart();

}

}

ChatClient.java

import java.io.*;

import java.net.*;

import java.util.Scanner;

public class ChatClient {

private static final int port = 12345;

private static String serverAddress = "localhost";

private Socket client = null;

private ObjectOutputStream objOutput = null;

private ObjectInputStream objInput = null;

public void SendMessage(DataPacket data) throws IOException {

// 发送数据给服务器

objOutput.writeObject(data);

}

public void ClientStart() {

Scanner in = new Scanner(System.in);

String userInput = null;

// 用户输入用户名登录

Message.printLog(Message.logType.INFO, "请输入你的用户名:", false);

userInput = in.nextLine();

// 连接服务器

try {

this.client = new Socket(serverAddress, port);

// 服务器已连接

if (this.client.isConnected()) {

// 获取输出流

this.objOutput = new ObjectOutputStream(this.client.getOutputStream());

// 获取输入流

this.objInput = new ObjectInputStream(this.client.getInputStream());

SendMessage(new DataPacket(Message.CMD.LOGIN, userInput));

// 创建一个线程用于接收信息

ClientReceiveMessageThread receiveMessage = new ClientReceiveMessageThread(this.objInput, userInput);

Thread receiveThread = new Thread(receiveMessage);

receiveThread.start();

// 这个线程用于发送信息

while (true) {

userInput = in.nextLine();

if (userInput != null) {

SendMessage(new DataPacket(Message.CMD.SEND, userInput));

}

}

}

} catch (ConnectException e) {

Message.printLog(Message.logType.ERROR, "ChatClient-ClientStart:ConnectException!", true);

e.printStackTrace();

} catch (SocketException e) {

Message.printLog(Message.logType.ERROR, "服务器异常!", true);

System.exit(0);

} catch (IOException e) {

Message.printLog(Message.logType.ERROR, "ChatClient-ClientStart:IOException!", true);

e.printStackTrace();

}

}

}

class ClientReceiveMessageThread implements Runnable {

private ObjectInputStream in = null;

private String clientName = null;

public ClientReceiveMessageThread(ObjectInputStream in, String name) {

this.in = in;

this.clientName = name;

}

public int HandleReceiveMsg(Object data) throws IOException {

DataPacket dataPacket = (DataPacket) data;

switch (dataPacket.cmd) {

case LOGIN:

case SEND:

case SENDALL:

Message.printMessage(dataPacket.msg);

break;

}

return 0;

}

@Override

public void run() {

Object data;

try {

while ((data = in.readObject()) != null) {

HandleReceiveMsg(data);

}

} catch (EOFException e) {

} catch (SocketException e) {

Message.printLog(Message.logType.ERROR, "服务器异常!", true);

System.exit(0);

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

}

四.共用的类

Message.java

import java.text.SimpleDateFormat;

import java.util.Date;

public class Message {

// 是否打开debug输出

private static boolean debug = false;

// 设定日期时间格式

public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyy-MM-dd hh:mm:ss");

public static enum logType {

ERROR,

INFO,

WARN,

DEBUG,

};

public static enum CMD {

LOGIN,

SEND,

SENDALL,

}

public static void printLog(logType type, String msg, boolean newLine) {

if( debug == true || type != logType.DEBUG ) {

StringBuilder sb = new StringBuilder(128);

sb.append("[").append(type).append("]").append(msg);

if (newLine)

System.out.println(sb);

else

System.out.print(sb);

}

}

public static void printMessage(String msg) {

StringBuilder sb = new StringBuilder(1024);

sb.append("[").append(dateFormat.format(new Date())).append("]").append(msg);

System.out.println(sb);

}

}

DataPacket.java

import java.io.Serializable;

public class DataPacket implements Serializable {

/**

* 自动生成的UID

*/

private static final long serialVersionUID = -5366828169862565011L;

public Message.CMD cmd;

public String msg;

public DataPacket(Message.CMD cmd, String msg) {

this.cmd = cmd;

this.msg = msg;

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值