知识储备
实现功能
- 基础群聊功能
- 私聊功能
- 新加入用户实时通知
- 用户控制台关闭(用户退出)实时通知
代码实现
Constant.java
public class Constant {
private Constant() {}
public final static String SERVER_HOST = "localhost";
public final static int SERVER_PORT = 6666;
}
CloseUtil.java
import java.io.Closeable;
import java.io.IOException;
public class CloseUtil {
private CloseUtil() {}
public static void close(Closeable... targets) {
try {
for (Closeable target : targets) {
if (target != null) {
target.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
UserSend.java
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class UserSend extends Thread {
private boolean isRunning;
private DataOutputStream dos;
private BufferedReader console;
public UserSend(Socket client) {
isRunning = true;
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
isRunning = false;
CloseUtil.close(console);
e.printStackTrace();
}
}
@Override
public void run() {
while (isRunning) {
sendMessage(getMsgFromConsole());
}
}
private String getMsgFromConsole() {
String messge = "";
try {
messge = console.readLine();
} catch (IOException e) {
isRunning = false;
CloseUtil.close(console,dos);
e.printStackTrace();
}
return messge;
}
private void sendMessage(String message) {
try {
dos.writeUTF(message);
dos.flush();
} catch (IOException e) {
isRunning = false;
CloseUtil.close(console,dos);
e.printStackTrace();
}
}
}
UserReceive.java
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class UserReceive extends Thread {
private boolean isRunning;
private DataInputStream dis;
public UserReceive(Socket client) {
isRunning = true;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
isRunning = false;
e.printStackTrace();
}
}
@Override
public void run() {
while (isRunning) {
getAndOutputMessage();
}
}
private void getAndOutputMessage() {
try {
String message = dis.readUTF();
System.out.println(message);
} catch (IOException e) {
isRunning = false;
CloseUtil.close(dis);
e.printStackTrace();
}
}
}
User.java
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Map;
import java.util.Set;
public class User extends Thread {
private boolean isRunning;
private DataInputStream dis;
private DataOutputStream dos;
public User(Socket client) {
isRunning = true;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
init();
} catch (IOException e) {
isRunning = false;
CloseUtil.close(dis);
e.printStackTrace();
}
}
private void init() throws IOException {
while (true) {
dos.writeUTF("******请输入用户名******");
dos.flush();
String name = dis.readUTF().trim();
if (name.length() == 0) {
dos.writeUTF("******警告:用户名不能为空!******");
dos.flush();
}else {
this.setName(name);
dos.writeUTF( "******欢迎您! " + name + "******");
dos.flush();
messageTrans("用户" + name + "加入了群聊!",true);
break;
}
}
}
@Override
public void run() {
while (isRunning) {
try {
String message = getMessage();
if (message.length() > 0)
messageTrans(message,false);
} catch (IOException e) {
isRunning = false;
CloseUtil.close(dis,dos);
ChatServer.users.remove(this.getName());
try {
messageTrans("用户" + this.getName() + "退出群聊!",true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
private String getMessage() throws IOException {
String message = dis.readUTF().trim();
return message;
}
private void messageTrans(String message,boolean isSys) throws IOException {
if (isSys) {
message = "******系统消息:" + message + "******";
broadcast(message);
}else {
if (message.startsWith("@")) {
if (message.contains(":")) {
int i = message.indexOf(":");
String name = message.substring(1,i);
if (name.equals(this.getName())) {
dos.writeUTF("******警告:不能私聊自己!******");
dos.flush();
}else {
message = message.substring(i+1);
if (ChatServer.users.containsKey(name)) {
User user = ChatServer.users.get(name);
user.dos.writeUTF(this.getName() + "悄悄对你说: " + message);
user.dos.flush();
}else {
dos.writeUTF("******警告:您私聊的用户不存在!******");
dos.flush();
}
}
}else {
dos.writeUTF("******警告:您私聊的格式不正确!******");
dos.flush();
}
}else {
message = this.getName() + ": " + message;
broadcast(message);
}
}
}
private void broadcast(String message) throws IOException {
Set<Map.Entry<String, User>> users = ChatServer.users.entrySet();
for (Map.Entry<String, User> user : users) {
if (user.getKey().equals(this.getName())) continue;
DataOutputStream dos = user.getValue().dos;
dos.writeUTF(message);
dos.flush();
}
}
}
ChatServer.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatServer {
public static Map<String,User> users = new HashMap<>();
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(Constant.SERVER_PORT);
System.out.println("服务器已启动!");
while (true) {
Socket client = server.accept();
new Thread(()->{
User user = new User(client);
users.put(user.getName(),user);
user.start();
}).start();
}
}
}
ChatClient.java
import java.io.IOException;
import java.net.Socket;
public class ChatClient {
public static void main(String[] args) throws IOException {
Socket client = new Socket(Constant.SERVER_HOST,Constant.SERVER_PORT);
new UserSend(client).start();
new UserReceive(client).start();
}
}