服务端:
- 转发消息
- 群聊功能
- 私聊功能
服务端:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class Server {
// 记录在线客户端
public static Map<Socket,String> onlineSockets = new HashMap<>();
// 方便私发消息,找到客户端
public static Map<String, Socket> nameSockets = new HashMap<>();
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(8888);
while (true) {
Socket socket = ss.accept();
new ServerThread(socket).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
服务端处理消息
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Map;
public class ServerThread extends Thread {
private Socket socket;
private String name;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (DataInputStream dis = new DataInputStream(socket.getInputStream())){
while (true) {
// 1 登录
// 2 / 3 发送信息
// 4 下线
int clientStatus = dis.readInt();
if (clientStatus == 1) {
String name = dis.readUTF();
System.out.println("用户:"+name);
this.name = name;
Server.onlineSockets.put(socket, name);
Server.nameSockets.put(name,socket);
}
send(clientStatus, dis);
}
} catch (Exception e) {
System.out.println(e);
System.out.println("有人下线了");
Server.onlineSockets.remove(socket);
Server.nameSockets.remove(name);
send(4, null);
}
}
public void send(int flag, DataInputStream dis) {
Map<Socket, String> onlineSockets = Server.onlineSockets;
if (flag == 2) {
try {
String m = dis.readUTF();
for (Map.Entry<Socket, String> client : onlineSockets.entrySet()) {
Socket socketClient = client.getKey();
if (!socket.equals(socketClient)) {
DataOutputStream dos = new DataOutputStream(socketClient.getOutputStream());
String msg = this.name + "&&&" + m;
// 要先发此flag, 否则客户端无法处理
dos.writeInt(flag);
dos.writeUTF(msg);
dos.flush();
}
}
}catch (Exception e) {
System.out.println(e);
}
} else if (flag == 3) {
try {
String m = dis.readUTF();
String[] split = m.split(" ");
String clientName = split[0].replace("@", "");
Socket socket = Server.nameSockets.get(clientName);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
String msg = this.name + "&&&" + split[1];
System.out.println(msg);
// 要先发此flag, 否则客户端无法处理
dos.writeInt(flag);
dos.writeUTF(msg);
dos.flush();
}catch (Exception e) {
System.out.println("eeeeeeeeeeeeeee");
System.out.println(e);
}
} else {
}
}
}
客户端
- 使用GUI搭建一个注册socket服务器
- 构建聊天室
- 处理客户端不同的消息
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Client extends JFrame {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Socket socket;
public static void main(String[] args) {
login();
}
public static void login() {
int width = 400;
int height = 876;
int textFieldWidth = 120;
int textFieldHeight = 24;
JFrame frame = new JFrame();
frame.setBounds(Window.WIDTH / 2 - width, 40, width, height);
frame.setTitle("登录页面");
frame.setLayout(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
JTextField ip = new JTextField();
ip.setLocation(160, 80);
ip.setText("127.0.0.1");
ip.setSize(textFieldWidth, textFieldHeight);
frame.add(ip);
JLabel ipLabel = new JLabel("Socket IP:");
ipLabel.setLocation(40, 80);
ipLabel.setSize(120, 24);
frame.add(ipLabel);
JTextField name = new JTextField();
name.setLocation(160, 110);
name.setSize(textFieldWidth, textFieldHeight);
frame.add(name);
JLabel nameLabel = new JLabel("昵称:");
nameLabel.setLocation(40, 110);
nameLabel.setSize(120, 24);
frame.add(nameLabel);
JButton jbtn = new JButton("登录");
jbtn.setLocation(110, 140);
jbtn.setSize(100, 30);
frame.add(jbtn);
frame.setVisible(true);
jbtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
socket = new Socket(ip.getText(), 8888);
DataOutputStream dis = new DataOutputStream(socket.getOutputStream());
dis.writeInt(1);
dis.writeUTF(name.getText());
frame.setVisible(false);
chat(name.getText());
System.out.println("用户登录了");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
});
}
public static void chat(String name) {
int width = 400;
int height = 876;
JFrame mainFrame = new JFrame();
mainFrame.setBounds(Window.WIDTH / 2 - width, 40, width, height);
mainFrame.setTitle("聊天界面: " + name);
mainFrame.setLayout(null);
Container con = mainFrame.getContentPane();
JTextArea showArea = new JTextArea();
showArea.setEditable(false);
showArea.setLineWrap(true);
JScrollPane jPanel = new JScrollPane(showArea);
jPanel.setSize(width, height - 200);
JTextArea inputArea = new JTextArea();
inputArea.setRows(9);
inputArea.setColumns(27);
JButton jButton = new JButton("发送");
jButton.setSize(120, 80);
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String text = inputArea.getText();
if (text.length() > 0) {
boolean contains = text.contains("@");
inputArea.setText("");
try {
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
// @ 是私聊, 不加是群聊
dos.writeInt(contains ? 3 : 2);
dos.writeUTF(text);
dos.flush();
Date sendDate = new Date();
showArea.append("我:" + simpleDateFormat.format(sendDate) + "\n");
showArea.append(text + "\n");
} catch (Exception exception) {
System.out.println("发送消息异常");
System.out.println(exception);
}
}
}
});
JPanel op = new JPanel();
op.setBackground(Color.pink);
op.setLocation(0, 676);
op.setSize(width, 200);
// 加入到对应的容器中
op.add(inputArea);
op.add(jButton);
con.add(jPanel, BorderLayout.CENTER);
con.add(op, BorderLayout.SOUTH);
mainFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
// 最后渲染
mainFrame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
// 获取返回的消息
try {
DataInputStream dis = new DataInputStream(socket.getInputStream());
while (true) {
int status = dis.readInt();
String msg = dis.readUTF();
if (status == 1) {
// 可以记录在线人是谁
String onLineUserName = msg;
System.out.println(onLineUserName);
} else if (status == 2) { // 接收别人发送的消息
String msgText = msg;
String[] split = msgText.split("&&&");
Date sendDate = new Date();
showArea.append(split[0] + " :" + simpleDateFormat.format(sendDate) + "\n");
showArea.append(split[1] + "\n");
} else if (status == 3) { // 接收别人发送的消息
String msgText = msg;
String[] split = msgText.split("&&&");
Date sendDate = new Date();
showArea.append(split[0] + " :" + simpleDateFormat.format(sendDate) + " 向你私法了消息" + "\n");
showArea.append(split[1] + "\n");
}
}
} catch (Exception e) {
System.out.println("异常信息");
e.printStackTrace();
}
}
}).start();
}
}
GUI使用时,注意组件的加载顺序,将组件最后加入到要显示的地方。
启动server 和 客户端
image.png