目录
题设:
多人可以同时聊天
客户端之间是不能之间交互,需要通过服务器端中转
客户端与服务器端聊天交互流程图
代码
服务器端功能:
1、启动服务器端,在服务器端循环监听客户端的连接
2、把循环接收到的多个客户端Socket对象存储起来(集合)
3、在服务器端每个socket都有监听来自客户端向他发送的消息
4、一旦某一个客户端发送了消息,那么在服务器端就将此消息发送给其他客户端
服务器监控界面+服务器接收
java
package com.ffyc.chatroomserver;
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.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server extends JFrame {
JTextArea displayTextArea;
//存放所有连接到服务器的socket集合
ArrayList<Socket> sockets = new ArrayList<>();
public Server(){
this.setTitle("聊天室服务器端监控");
//设置宽高
this.setSize(500,400);
//水平垂直居中
this.setLocationRelativeTo(null);
//点击关闭按钮时什么都不做
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
//设置禁止窗口拖拽调整大小
this.setResizable(false);
//最大面板 边界布局
JPanel jPanel = new JPanel(new BorderLayout());
//显示聊天内容的面板
displayTextArea = new JTextArea();
//设置内容只能靠不能改
displayTextArea.setEditable(false);
//用它当作面板
JScrollPane diaplayScrollPane = new JScrollPane(displayTextArea);
//添加中间位置 而且自动充满整个区域
jPanel.add(diaplayScrollPane);
//发送聊天内容面板
JPanel sendPanel = new JPanel();
JTextArea sendTextArea = new JTextArea(3,30);
sendTextArea.setLineWrap(true);
JScrollPane sendScrollPane = new JScrollPane(sendTextArea);
JButton sendButton = new JButton("发送公告");
sendPanel.add(sendScrollPane);
sendPanel.add(sendButton);
jPanel.add(sendPanel, BorderLayout.SOUTH);
this.add(jPanel);
this.setVisible(true);
sendButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//获取的是通知公告内容
String notice = sendTextArea.getText();
for(Socket soc:sockets){
DataOutputStream dataOutputStream = null;
try {
dataOutputStream = new DataOutputStream(soc.getOutputStream());
dataOutputStream.writeUTF("来自服务器的通知:"+notice);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
});
}
//启动服务器
public void startServer(){
try {
//启动服务
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器启动成功");
//监听客户端连接,监听多个客户端连接
while (true){
//监听客户端的连接
Socket socket = serverSocket.accept();
//加入集合
sockets.add(socket);
System.out.println("有客户端连接,连接数量为:" + sockets.size());
//为每一个连接到服务器的客户端开启一个线程
new SocketThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败");
}
}
//创建一个内部类,继承Thread类,用来监听自己客户端有没有发送消息
class SocketThread extends Thread{
boolean mark = true;
DataInputStream dataInputStream;
Socket socket;
public SocketThread(Socket socket) throws IOException {
this.socket = socket;
dataInputStream = new DataInputStream(socket.getInputStream());
}
@Override
public void run() {
//一直死循环,监听客户端发送的消息
while (mark){
try {
String msg = dataInputStream.readUTF();
displayTextArea.append(msg+"\n");
System.out.println(msg);
//向不同的客户端转发消息
//遍历socket集合 A B C
for(Socket soc:sockets){
DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());
dataOutputStream.writeUTF(msg);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端下线了!");
sockets.remove(socket);
//停止循环监听
mark = false;
}
}
}
}
}
服务器端为每一个客户端开启一个线程监听
启动服务器
java
package com.ffyc.chatroomserver;
public class ServerRun {
public static void main(String[] args) {
new Server().startServer();
}
}
客户端功能:
1、用户登录(只需要账号不为空即可),创建socket
2、如果socket创建成功,打开聊天窗口
3、输入内容点击发送按钮发送消息
4、在客户端监听服务器端发送回来的消息,并把消息显示出来
登录注册界面
java
package com.ffyc.chatroomclient.frame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;
public class LoginFrame extends JFrame {
public LoginFrame(){
this.setTitle("欢迎登录");
//设置宽高
this.setSize(500,400);
//水平垂直居中
this.setLocationRelativeTo(null);
//关闭窗口时退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置禁止窗口拖拽调整大小
this.setResizable(false);
//最大的面板 网格布局 4行1列
JPanel jPanel = new JPanel(new GridLayout(4,1));
//欢迎面板
JPanel welcomePanel = new JPanel();
JLabel welcomeLabel = new JLabel("欢迎登录");
welcomeLabel.setFont(new Font("宋体", Font.BOLD, 35));
welcomeLabel.setForeground(Color.black);
welcomePanel.add(welcomeLabel);
//账号面板
JPanel accountPanel = new JPanel();
JLabel accountLabel = new JLabel("账号");
JTextField accountField = new JTextField(15);
accountPanel.add(accountLabel);
accountPanel.add(accountField);
//密码面板
JPanel passwordPanel = new JPanel();
JLabel passwordLabel = new JLabel("密码");
JPasswordField passwordField = new JPasswordField(15);
passwordPanel.add(passwordLabel);
passwordPanel.add(passwordField);
//登录面板
JPanel buttonPanel = new JPanel();
JButton loginButton = new JButton("登录");
JButton regButton = new JButton("注册");
buttonPanel.add(loginButton);
buttonPanel.add(regButton);
jPanel.add(welcomePanel);
jPanel.add(accountPanel);
jPanel.add(passwordPanel);
jPanel.add(buttonPanel);
this.add(jPanel);
//让窗口显示 放在设置的最后一行
this.setVisible(true);
//为登录按钮添加事件监听
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//获得账号和密码
String account = accountField.getText();
String password = new String(passwordField.getPassword());
if(account.length()==0){
JOptionPane.showMessageDialog(null, "账号不能为空!");
return;
}
if(password.length()==0){
JOptionPane.showMessageDialog(null, "密码不能为空!");
return;
}
//后期预留与数据库交互
//创建Socket
try {
Socket socket = new Socket("127.0.0.1",9999);
//创建聊天窗口
new ChatFrame(account,socket);
//释放窗口
dispose();
} catch (IOException ioException) {
ioException.printStackTrace();
JOptionPane.showMessageDialog(null, "服务器连接失败,请稍后再试!");
}
}
});
}
}
聊天窗口
java
package com.ffyc.chatroomclient.frame;
import com.ffyc.chatroomclient.util.DateUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ChatFrame extends JFrame{
JTextArea displayTextArea;
public ChatFrame(String account, Socket socket) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
this.setTitle("欢迎"+account+"登录");
//设置宽高
this.setSize(500,400);
//水平垂直居中
this.setLocationRelativeTo(null);
//点击关闭按钮时什么都不做
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
//设置禁止窗口拖拽调整大小
this.setResizable(false);
//最大面板 边界布局
JPanel jPanel = new JPanel(new BorderLayout());
//显示聊天内容的面板
displayTextArea = new JTextArea();
//设置内容只能靠不能改
displayTextArea.setEditable(false);
//用它当作面板
JScrollPane diaplayScrollPane = new JScrollPane(displayTextArea);
//添加中间位置 而且自动充满整个区域
jPanel.add(diaplayScrollPane);
//发送聊天内容面板
JPanel sendPanel = new JPanel();
JTextArea sendTextArea = new JTextArea(3,35);
sendTextArea.setLineWrap(true);
JScrollPane sendScrollPane = new JScrollPane(sendTextArea);
JButton sendButton = new JButton("发送");
sendPanel.add(sendScrollPane);
sendPanel.add(sendButton);
jPanel.add(sendPanel,BorderLayout.SOUTH);
this.add(jPanel);
this.setVisible(true);
//来到聊天窗口后,可以开启一个线程监听服务器端发送的消息
new ClientThread(socket).start();
//为发送按钮添加事件监听
sendButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String message = sendTextArea.getText();
if(message.length() == 0){
JOptionPane.showMessageDialog(null, "发送内容不能为空!");
return;
}
//不为空,向服务器端发送此消息
String msg = account+" "+ DateUtil.dateToString("yyyy-MM-dd HH:mm:ss")+"\n";
msg += message;
try {
//发送消息
dataOutputStream.writeUTF(msg);
//清空发送框
sendTextArea.setText("");
} catch (IOException ioException) {
ioException.printStackTrace();
JOptionPane.showMessageDialog(null, "内容发送失败!请检查网络是否异常");
}
}
});
//为窗口添加事件监听
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
int res = JOptionPane.showConfirmDialog(null, "是否退出聊天", "操作提示", JOptionPane.OK_CANCEL_OPTION);
if(res == 0){
//点击确认
new LoginFrame();
//释放聊天窗口
dispose();
}
}
});
}
//线程监听服务器发送的消息
class ClientThread extends Thread{
boolean mark = true;
DataInputStream dataInputStream;
public ClientThread(Socket socket) throws IOException {
dataInputStream = new DataInputStream(socket.getInputStream());
}
@Override
public void run() {
while (mark){
try {
String msg = dataInputStream.readUTF();
//显示聊天内容,追加 保留之前的内容
displayTextArea.append(msg+"\n");
} catch (IOException e) {
e.printStackTrace();
//停止循环监听
mark = false;
}
}
}
}
}
启动客户端
java
package com.ffyc.chatroomclient.frame;
public class ClientRun {
public static void main(String[] args) {
new LoginFrame();
}
}