Java在线聊天室(客户端+服务器)基于webSocket实现模拟在线聊天系统
运行环境: JDK1.8version
开发环境:Eclipse
一、结构
以下是系统主要结构:
1.用户(均实现部分可能会有bug)
(1)自定义用户名登录
(2)端口修改灵活使用服务器端口
(3)断开服务器功能
(4)可查询在线用户列表
(5)可对在线列表用户进行私聊操作(自测)
(6)群发消息在线用户都可以看见消息
client代码参考如下:
public class Client{
private JFrame frame;
public JList userList;
public int i;
public String soloId;
private JTextArea textArea;
private JTextArea systemTextArea;
private JTextField textField;
private JTextField txt_port;
private JTextField txt_hostIp;
private JTextField txt_name;
// private JComboBox select;
// private JList jList;
private JButton btn_start;
private JButton btn_stop;
private JButton btn_send;
private JPanel northPanel;
private JPanel southPanel;
private JScrollPane rightScroll;
private JScrollPane leftScroll;
private JSplitPane centerSplit;
private DefaultListModel listModel;
private boolean isConnected = false;
private Socket socket;
private PrintWriter writer;
private BufferedReader reader;
private MessageThread messageThread;// 负责接收消息的线程
private Map<String, User> onLineUsers = new HashMap<String, User>();// 所有在线用户
public boolean isConnected() {
return isConnected;
}
public void setConnected(boolean isConnected) {
this.isConnected = isConnected;
}
// 主方法,程序入口
public static void main(String[] args) {
new Client();
}
// 执行发送
public void send(String c) {
if (!isConnected) {
JOptionPane.showMessageDialog(frame, "还没有连接服务器,无法发送消息!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
String message = textField.getText().trim();
if (message == null || message.equals("")) {
JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
if (isConnected == false) {
JOptionPane.showMessageDialog(frame, "您已被強制下线!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
if(c=="all") {
sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message+"@"+ soloId);
textField.setText(null);
return;
}
if(c=="solo") {
System.out.println(soloId+"soloId");
sendMessage(frame.getTitle() + "@" + "SOLO" + "@" + message + "@" + soloId);
textField.setText(null);
return;
}
}
// 构造方法
public Client() {
textArea = new JTextArea();
systemTextArea = new JTextArea();
textArea.setEditable(false);
textArea.setForeground(Color.BLACK);
systemTextArea.setEditable(false);
systemTextArea.setForeground(Color.blue);
textField = new JTextField();
txt_port = new JTextField(8);txt_port.setText("8888");//设置大小
txt_hostIp = new JTextField(8);txt_hostIp.setText("127.0.0.1");
txt_name = new JTextField(8);txt_name.setText("xiaohei");
btn_start = new JButton("连接");btn_start.setPreferredSize(new Dimension(120,10));
btn_stop = new JButton("断开");btn_stop.setPreferredSize(new Dimension(120,10));
btn_send = new JButton("发送");btn_send.setPreferredSize(new Dimension(120,10));
listModel = new DefaultListModel();
userList = new JList(listModel);
northPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,10,15));
// northPanel.setLayout(new GridLayout(1, 7));
Box bnorthPanel=Box.createHorizontalBox(); //创建横向Box容器
northPanel.add(bnorthPanel);
bnorthPanel.add(new JLabel("姓名:"));
bnorthPanel.add(Box.createHorizontalStrut(20));
bnorthPanel.add(txt_name);
bnorthPanel.add(Box.createHorizontalStrut(150));
bnorthPanel.add(new JLabel("服务器IP:"));
bnorthPanel.add(Box.createHorizontalStrut(20));
bnorthPanel.add(txt_hostIp);
bnorthPanel.add(Box.createHorizontalStrut(130));
bnorthPanel.add(new JLabel("端口:"));
bnorthPanel.add(Box.createHorizontalStrut(20));
bnorthPanel.add(txt_port);
bnorthPanel.add(Box.createHorizontalStrut(30));
bnorthPanel.add(btn_start);
bnorthPanel.add(Box.createHorizontalStrut(10));
bnorthPanel.add(btn_stop);
northPanel.setBorder(new TitledBorder("连接信息"));
rightScroll = new JScrollPane(textArea);
textArea.add(systemTextArea);
rightScroll.setBorder(new TitledBorder("消息显示区"));
leftScroll = new JScrollPane(userList);
leftScroll.setBorder(new TitledBorder("在线用户"));
southPanel = new JPanel(new BorderLayout());
southPanel.add(textField, "Center");
// southPanel.add(select,"Center");
southPanel.add(btn_send, "East");
southPanel.setBorder(new TitledBorder("写消息"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll,
rightScroll);
centerSplit.setDividerLocation(100);
frame = new JFrame("客户机");
// 更改JFrame的图标:
// frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));
frame.setLayout(new BorderLayout());
frame.add(northPanel, "North");
frame.add(centerSplit, "Center");
frame.add(southPanel, "South");
frame.setSize(1050, 500);
int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
frame.setLocation((screen_width - frame.getWidth()) / 2,
(screen_height - frame.getHeight()) / 2);
frame.setVisible(true);
// 写消息的文本框中按回车键时事件
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
send("all");
}
});
//单击在线用户事件
userList.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
int i = userList.getSelectedIndex();
soloId = (String) listModel.get(i);
send("solo");
// for (int i = listModel.size() - 1; i >= 0; i--) {
//
// System.out.println(listModel.get(i)+"111111111111");
// }
// new SeparateChat();
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
});
// 单击发送按钮时事件
btn_send.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send("all");
}
});
// 单击连接按钮时事件
btn_start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int port;
if (isConnected) {
JOptionPane.showMessageDialog(frame, "已处于连接上状态,不要重复连接!",
"错误", JOptionPane.ERROR_MESSAGE);
return;
}
try {
try {
port = Integer.parseInt(txt_port.getText().trim());
} catch (NumberFormatException e2) {
throw new Exception("端口号不符合要求!端口为整数!");
}
String hostIp = txt_hostIp.getText().trim();
String name = txt_name.getText().trim();
if (name.equals("") || hostIp.equals("")) {
throw new Exception("姓名、服务器IP不能为空!");
}
//
boolean flag = connectServer(port, hostIp, name);
if (flag == false) {
throw new Exception("与服务器连接失败!");
}
frame.setTitle(name);
JOptionPane.showMessageDialog(frame, "成功连接!");
} catch (Exception exc) {
JOptionPane.showMessageDialog(frame, exc.getMessage(),
"错误", JOptionPane.ERROR_MESSAGE);
}
}
});
// 单击断开按钮时事件
btn_stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!isConnected) {
JOptionPane.showMessageDialog(frame, "已处于断开状态,不要重复断开!",
"错误", JOptionPane.ERROR_MESSAGE);
return;
}
try {
boolean flag = closeConnection();// 断开连接
if (flag == false) {
throw new Exception("断开连接发生异常!");
}
JOptionPane.showMessageDialog(frame, "成功断开!");
} catch (Exception exc) {
JOptionPane.showMessageDialog(frame, exc.getMessage(),
"错误", JOptionPane.ERROR_MESSAGE);
}
}
});
// 关闭窗口时事件
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
if (isConnected) {
closeConnection();// 关闭连接
}
System.exit(0);// 退出程序
}
});
}
/**
* 连接服务器
*
* @param port
* @param hostIp
* @param name
*/
public boolean connectServer(int port, String hostIp, String name) {
// 连接服务器
try {
socket = new Socket(hostIp, port);// 根据端口号和服务器ip建立连接
writer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 发送客户端用户基本信息(用户名和ip地址)
sendMessage(name + "@" + socket.getLocalAddress().toString());
// 开启接收消息的线程
messageThread = new MessageThread(reader, textArea);
messageThread.start();
isConnected = true;// 已经连接上了
return true;
} catch (Exception e) {
textArea.append("【系统消息】与端口号为:" + port + " IP地址为:" + hostIp
+ " 的服务器连接失败!" + "\r\n");
isConnected = false;// 未连接上
return false;
}
}
/**
* 发送消息
*
* @param message
*/
public void sendMessage(String message) {
writer.println(message);
writer.flush();
}
/**
* 客户端主动关闭连接
*/
@SuppressWarnings("deprecation")
public synchronized boolean closeConnection() {
try {
sendMessage("CLOSE");// 发送断开连接命令给服务器
listModel.removeAllElements();
messageThread.stop();// 停止接受消息线程
// 释放资源
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
if (socket != null) {
socket.close();
}
isConnected = false;
return true;
} catch (IOException e1) {
e1.printStackTrace();
isConnected = true;
return false;
}
}
// 不断接收消息的线程
class MessageThread extends Thread {
private BufferedReader reader;
private JTextArea textArea;
// 接收消息线程的构造方法
public MessageThread(BufferedReader reader, JTextArea textArea) {
this.reader = reader;
this.textArea = textArea;
}
// 被动的关闭连接
public synchronized void closeCon() throws Exception {
// 清空用户列表
listModel.removeAllElements();
// 被动的关闭连接释放资源
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
if (socket != null) {
socket.close();
}
isConnected = false;// 修改状态为断开
}
public void run() {
String message = "";
while (true) {
try {
message = reader.readLine();
StringTokenizer stringTokenizer = new StringTokenizer(
message, "/@");
String command = stringTokenizer.nextToken();// 命令
System.out.println(command);
if (command.equals("CLOSE"))// 服务器已关闭命令
{
textArea.append("【系统消息】服务器已关闭!\r\n");
closeCon();// 被动的关闭连接
return;// 结束线程
}else if(command.equals("KickCLOSE")) {
closeCon();// 被动的关闭连接
return;// 结束线程
}else if(command.equals("NAME")) {
int size = Integer.parseInt(stringTokenizer.nextToken());
String username = null;
String userIp = null;
String thisName = txt_name.getText().trim();
for (int i = 0; i < size; i++) {
username = stringTokenizer.nextToken();
userIp = stringTokenizer.nextToken();
// User user = new User(username, userIp);
if(username.equals(thisName)) {
// isConnected = false;
sendMessage("CLOSE");// 发送断开连接命令给服务器
closeCon();// 被动的关闭连接
textArea.append("【系统消息】与端口号为:" + txt_port.getText().trim() + " IP地址为:" + txt_hostIp.getText().trim()
+ " 的服务器连接失败!" + "\r\n");
JOptionPane.showMessageDialog(frame, "该姓名已被占用!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
}
// closeCon();// 被动的关闭连接
// JOptionPane.showMessageDialog(frame, "该姓名已被占用!", "错误",
// JOptionPane.ERROR_MESSAGE);
// return;// 结束线程
}else if (command.equals("ADD")) {// 有用户上线更新在线列表
String username = "";
String userIp = "";
if ((username = stringTokenizer.nextToken()) != null
&& (userIp = stringTokenizer.nextToken()) != null) {
User user = new User(username, userIp);
onLineUsers.put(username, user);
listModel.addElement(username);
}
} else if (command.equals("DELETE")) {// 有用户下线更新在线列表
String username = stringTokenizer.nextToken();
User user = (User) onLineUsers.get(username);
onLineUsers.remove(user);
listModel.removeElement(username);
} else if (command.equals("USERLIST")) {// 加载在线用户列表
int size = Integer
.parseInt(stringTokenizer.nextToken());
String username = null;
String userIp = null;
for (int i = 0; i < size; i++) {
username = stringTokenizer.nextToken();
userIp = stringTokenizer.nextToken();
User user = new User(username, userIp);
onLineUsers.put(username, user);
listModel.addElement(username);
}
} else if (command.equals("MAX")) {// 人数已达上限
textArea.append(stringTokenizer.nextToken()
+ stringTokenizer.nextToken() + "\r\n");
closeCon();// 被动的关闭连接
JOptionPane.showMessageDialog(frame, "服务器缓冲区已满!", "错误",
JOptionPane.ERROR_MESSAGE);
return;// 结束线程
}
else {// 普通消息
textArea.append(message + "\r\n");
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
2.服务器(全部已实现)
(1)指定端口开启服务器
(2)设置服务器上线人数
(3)停止服务器响应
(4)查询在线用户列表
(5)群发消息
(6)对指定用户进行移除聊天室
server代码
public class Server {
private JFrame frame;
private JTextArea contentArea;
private JTextField txt_message;
private JTextField txt_max;
private JTextField txt_port;
private JTextField kickOutUser;
private JButton btn_start;
private JButton btn_stop;
private JButton btn_send;
private JButton btn_kick;
private JPanel northPanel;
private JPanel southPanel;
private JPanel eastPanel;
private JPanel eastUpPanel;
private JPanel eastDownPanel;
private JPanel westPanel;
private JScrollPane rightPanel;
private JScrollPane leftPanel;
private JSplitPane centerSplit;
private JList userList;
private DefaultListModel listModel;
private ServerSocket serverSocket;
private ServerThread serverThread;
private ArrayList<ClientThread> clients;
private boolean isStart = false;
private Client client;
// Client client = new Client();
// 主方法,程序执行入口
public static void main(String[] args) {
new Server();
}
// 执行消息发送
public void send() {
if (!isStart) {
JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
if (clients.size() == 0) {
JOptionPane.showMessageDialog(frame, "没有用户在线,不能发送消息!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
String message = txt_message.getText().trim();
if (message == null || message.equals("")) {
JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
sendServerMessage(message);// 群发服务器消息
contentArea.append(Time + " " + "服务器说:" + txt_message.getText() + "\r\n");
txt_message.setText(null);
}
// 构造放法
public Server() {
// client = new Client();
frame = new JFrame("服务器");
// 更改JFrame的图标:
//frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));
// frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("/KeTang/WebContent/img/bg.jpg")));
contentArea = new JTextArea();
contentArea.setEditable(false);
contentArea.setForeground(Color.black);
txt_message = new JTextField();
txt_max = new JTextField(8);txt_max.setText("6");
txt_port = new JTextField(8);txt_port.setText("8888");
kickOutUser = new JTextField(8);kickOutUser.setText("xiaohei");
btn_start = new JButton("启动");btn_start.setPreferredSize(new Dimension(120,10));
btn_stop = new JButton("停止");btn_stop.setPreferredSize(new Dimension(120,10));
btn_send = new JButton("发送");btn_send.setPreferredSize(new Dimension(120,10));
btn_kick = new JButton("踢");
btn_stop.setEnabled(false);
listModel = new DefaultListModel();
userList = new JList(listModel);
southPanel = new JPanel(new BorderLayout());
southPanel.setBorder(new TitledBorder("写消息"));
southPanel.add(txt_message, "Center");
southPanel.add(btn_send, "East");
leftPanel = new JScrollPane(userList);
leftPanel.setBorder(new TitledBorder("在线用户"));
rightPanel = new JScrollPane(contentArea);
rightPanel.setBorder(new TitledBorder("消息显示区"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
rightPanel);
centerSplit.setDividerLocation(100);
northPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,10,15));
// northPanel.setLayout(new GridLayout(1, 6));
Box bnorthPanel=Box.createHorizontalBox(); //创建横向Box容器
northPanel.add(bnorthPanel);
bnorthPanel.add(new JLabel("人数上限:"));
bnorthPanel.add(Box.createHorizontalStrut(20));
bnorthPanel.add(txt_max);
bnorthPanel.add(Box.createHorizontalStrut(150));
bnorthPanel.add(new JLabel("端口:"));
bnorthPanel.add(Box.createHorizontalStrut(20));
bnorthPanel.add(txt_port);
bnorthPanel.add(Box.createHorizontalStrut(30));
bnorthPanel.add(btn_start);
bnorthPanel.add(Box.createHorizontalStrut(10));
bnorthPanel.add(btn_stop);
northPanel.setBorder(new TitledBorder("配置信息"));
eastUpPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,3,15));
eastUpPanel.add(new JLabel("被踢用户:"));
eastUpPanel.add(kickOutUser);
eastUpPanel.add(btn_kick);
eastDownPanel = new JPanel();
Box beastDownPanel=Box.createVerticalBox(); //创建纵向Box容器
eastDownPanel.add(beastDownPanel);
beastDownPanel.add(Box.createVerticalStrut(150));
beastDownPanel.add(new JLabel("未完待续..."));
eastPanel = new JPanel(new BorderLayout());
eastPanel.add(eastUpPanel,"North");
eastPanel.add(eastDownPanel,"Center");
eastPanel.setBorder(new TitledBorder("服务器功能操作"));
westPanel = new JPanel(new BorderLayout());
westPanel.add(northPanel,"North");
westPanel.add(centerSplit, "Center");
westPanel.add(southPanel, "South");
frame.setLayout(new BorderLayout());
frame.add(westPanel, "West");
frame.add(eastPanel, "East");
frame.setSize(1050, 500);
//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏
int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
frame.setLocation((screen_width - frame.getWidth()) / 2,
(screen_height - frame.getHeight()) / 2);
frame.setVisible(true);
// 关闭窗口时事件
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
if (isStart) {
closeServer();// 关闭服务器
}
System.exit(0);// 退出程序
}
});
//单击踢出用户
btn_kick.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String a = kickOutUser.getText().trim();
kickOutUser(a);
}
});
// 文本框按回车键时事件
txt_message.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});
// 单击发送按钮时事件
btn_send.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
send();
}
});
// 单击启动服务器按钮时事件
btn_start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isStart) {
JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!",
"错误", JOptionPane.ERROR_MESSAGE);
return;
}
int max;
int port;
try {
try {
max = Integer.parseInt(txt_max.getText());
} catch (Exception e1) {
throw new Exception("人数上限为正整数!");
}
if (max <= 0) {
throw new Exception("人数上限为正整数!");
}
try {
port = Integer.parseInt(txt_port.getText());
} catch (Exception e1) {
throw new Exception("端口号为正整数!");
}
if (port <= 0) {
throw new Exception("端口号 为正整数!");
}
serverStart(max, port);
contentArea.append("服务器已成功启动!人数上限:" + max + ",端口:" + port
+ "\r\n");
JOptionPane.showMessageDialog(frame, "服务器成功启动!");
btn_start.setEnabled(false);
txt_max.setEnabled(false);
txt_port.setEnabled(false);
btn_stop.setEnabled(true);
} catch (Exception exc) {
JOptionPane.showMessageDialog(frame, exc.getMessage(),
"错误", JOptionPane.ERROR_MESSAGE);
}
}
});
// 单击停止服务器按钮时事件
btn_stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!isStart) {
JOptionPane.showMessageDialog(frame, "服务器还未启动,无需停止!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
try {
closeServer();
btn_start.setEnabled(true);
txt_max.setEnabled(true);
txt_port.setEnabled(true);
btn_stop.setEnabled(false);
contentArea.append("服务器成功停止!\r\n");
JOptionPane.showMessageDialog(frame, "服务器成功停止!");
} catch (Exception exc) {
JOptionPane.showMessageDialog(frame, "停止服务器发生异常!", "错误",
JOptionPane.ERROR_MESSAGE);
}
}
});
}
// 踢出用户方法
public void kickOutUser(String kickOutUser){
User user = new User(kickOutUser, kickOutUser);
boolean exist = false;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
//当前是否有启动服务器
if (!isStart) {
JOptionPane.showMessageDialog(frame, "服务器还未启动,不能踢出!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
//当前是否有用户
if (clients.size() == 0) {
JOptionPane.showMessageDialog(frame, "没有用户在线,踢出失败!", "错误",
JOptionPane.ERROR_MESSAGE);
return;
}
for (int i = clients.size() - 1; i >= 0; i--) {
ClientThread temp = clients.get(i);
if (clients.get(i).getUser().getName().equals(kickOutUser)) {
//服务器窗口显示该用户强制下线消息
contentArea.append(Time+" "+clients.get(i).getUser().getName()
+ clients.get(i).getUser().getIp() + "被强制下线!\r\n");
//给该用户发送强制下线消息
clients.get(i).getWriter().println(
"【系统消息】用户"+clients.get(i).getUser().getName()+"您已被强制下线!\r\n");
clients.get(i).getWriter().flush();
// 更新在线列表
listModel.removeElement(clients.get(i).getUser().getName());
clients.get(i).getWriter().println("KickCLOSE");
clients.get(i).getWriter().flush();
clients.remove(i);// 删除此用户的服务线程
temp.stop();// 停止这条服务线程
exist = true;
// client.setConnected(false);
}
}
if (exist == false) {
JOptionPane.showMessageDialog(frame, "该用户不在线,踢出失败!", "错误",
JOptionPane.ERROR_MESSAGE);
}
for (int i = clients.size() - 1; i >= 0; i--) {
// 向所有在线用户发送该用户的下线命令
clients.get(i).getWriter().println(
"DELETE@" + user.getName());
clients.get(i).getWriter().println(
"【系统消息】用户"+user.getName()+"被强制下线!\r\n");
clients.get(i).getWriter().flush();
}
}
// 启动服务器
public void serverStart(int max, int port) throws java.net.BindException {
try {
clients = new ArrayList<ClientThread>();
serverSocket = new ServerSocket(port);
serverThread = new ServerThread(serverSocket, max);
serverThread.start();
isStart = true;
} catch (BindException e) {
isStart = false;
throw new BindException("端口号已被占用,请换一个!");
} catch (Exception e1) {
e1.printStackTrace();
isStart = false;
throw new BindException("启动服务器异常!");
}
}
// 关闭服务器
@SuppressWarnings("deprecation")
public void closeServer() {
try {
if (serverThread != null)
serverThread.stop();// 停止服务器线程
for (int i = clients.size() - 1; i >= 0; i--) {
// 给所有在线用户发送关闭命令
clients.get(i).getWriter().println("CLOSE");
clients.get(i).getWriter().flush();
// 释放资源
clients.get(i).stop();// 停止此条为客户端服务的线程
clients.get(i).reader.close();
clients.get(i).writer.close();
clients.get(i).socket.close();
clients.remove(i);
}
if (serverSocket != null) {
serverSocket.close();// 关闭服务器端连接
}
listModel.removeAllElements();// 清空用户列表
isStart = false;
} catch (IOException e) {
e.printStackTrace();
isStart = true;
}
}
// 群发服务器消息
public void sendServerMessage(String message) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println("【系统消息】"+"服务器:" + message);
clients.get(i).getWriter().flush();
}
}
// 服务器线程
class ServerThread extends Thread {
private ServerSocket serverSocket;
private int max;// 人数上限
// 服务器线程的构造方法
public ServerThread(ServerSocket serverSocket, int max) {
this.serverSocket = serverSocket;
this.max = max;
}
public synchronized void run() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
while (true) {// 不停的等待客户端的链接
try {
Socket socket = serverSocket.accept();
if (clients.size() == max) {// 如果已达人数上限
BufferedReader r = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter w = new PrintWriter(socket.getOutputStream());
// 接收客户端的基本用户信息
String inf = r.readLine();
StringTokenizer st = new StringTokenizer(inf, "@");
User user = new User(st.nextToken(), st.nextToken());
// 反馈连接成功信息
w.println("MAX@【系统消息】服务器:对不起," + user.getName()
+ user.getIp() + ",服务器在线人数已达上限,请稍后尝试连接!");
w.flush();
// 释放资源
r.close();
w.close();
socket.close();
continue;
}
ClientThread client = new ClientThread(socket);
client.start();// 开启对此客户端服务的线程
clients.add(client);
listModel.addElement(client.getUser().getName());// 更新在线列表
contentArea.append(Time+" "+client.getUser().getName()
+ client.getUser().getIp() + "上线了!\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 为一个客户端服务的线程
class ClientThread extends Thread {
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
private User user;
public BufferedReader getReader() {
return reader;
}
public PrintWriter getWriter() {
return writer;
}
public User getUser() {
return user;
}
// 客户端线程的构造方法
public ClientThread(Socket socket) {
try {
this.socket = socket;
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream());
// 接收客户端的基本用户信息
String inf = reader.readLine();
StringTokenizer st = new StringTokenizer(inf, "@");
user = new User(st.nextToken(), st.nextToken());
String temp = "";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
// 反馈连接成功信息
writer.println("【系统消息】" + user.getName() + user.getIp() + "与服务器连接成功!");
writer.flush();
// 反馈当前在线用户信息
if (clients.size() > 0) {
for (int i = clients.size() - 1; i >= 0; i--) {
temp += (clients.get(i).getUser().getName() + "/" + clients
.get(i).getUser().getIp())
+ "@";
if(clients.get(i).getUser().getName().equals(user.getName())) {
writer.println("NAME@" + clients.size() + "@" + temp);//判断姓名是否重复
writer.flush();
}
}
writer.println("USERLIST@" + clients.size() + "@" + temp);
writer.flush();
}
// 向所有在线用户发送该用户上线命令
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(
"ADD@" + user.getName() + user.getIp());
// clients.get(i).getWriter().flush();
// clients.get(i).getWriter().println(
// "【系统消息】用户"+user.getName()+"上线了!\r\n");
clients.get(i).getWriter().flush();
}
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(
"【系统消息】用户"+user.getName()+"上线了!\r\n");
clients.get(i).getWriter().flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void run() {// 不断接收客户端的消息,进行处理。
String message = null;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
while (true) {
try {
message = reader.readLine();// 接收客户端消息
if (message.equals("CLOSE"))// 下线命令
{
contentArea.append(Time+" "+this.getUser().getName()
+ this.getUser().getIp() + "下线了!\r\n");
// 断开连接释放资源
reader.close();
writer.close();
socket.close();
// 向所有在线用户发送该用户的下线命令
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(
"DELETE@" + user.getName());
clients.get(i).getWriter().flush();
}
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(
"【系统消息】用户"+user.getName()+"下线了!\r\n");
clients.get(i).getWriter().flush();
}
listModel.removeElement(user.getName());// 更新在线列表
// 删除此条客户端服务线程
for (int i = clients.size() - 1; i >= 0; i--) {
if (clients.get(i).getUser() == user) {
ClientThread temp = clients.get(i);
clients.remove(i);// 删除此用户的服务线程
temp.stop();// 停止这条服务线程
return;
}
}
}
else {
dispatcherMessage(message);// 多人转发消息
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 转发消息
public void dispatcherMessage(String message) {
StringTokenizer stringTokenizer = new StringTokenizer(message, "@");
String source = stringTokenizer.nextToken();
String owner = stringTokenizer.nextToken();
String content = stringTokenizer.nextToken();
String soloId = stringTokenizer.nextToken();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String Time = df.format(new Date());
if (owner.equals("ALL")) {// 群发
message =Time + " " + source + ":" + content;
contentArea.append(message + "\r\n");
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(message);
clients.get(i).getWriter().flush();
}
} else if (owner.equals("SOLO")) {
message =Time + " " + source + "对" + soloId+ ":" + content;
contentArea.append(message + "\r\n");
for (int i = clients.size() - 1; i >= 0; i--) {
if (clients.get(i).getUser().getName().equals(user.getName())) {//当前用户一对一发送
message =Time + " " + "你对" + soloId + ":" + content;
clients.get(i).getWriter().println(message);
clients.get(i).getWriter().flush();
}
if (clients.get(i).getUser().getName().equals(soloId)) {//一对一发送给soloId
message =Time + " " +source + "对你:" + content;
clients.get(i).getWriter().println(message);
clients.get(i).getWriter().flush();
}
}
}
}
// public void dispatcherSoloMessage(String message) {
// StringTokenizer stringTokenizer = new StringTokenizer(message, "@");
// String source = stringTokenizer.nextToken();
// String owner = stringTokenizer.nextToken();
// String content = stringTokenizer.nextToken();
// String soloId = stringTokenizer.nextToken();
// message = source + ":" + content;
// contentArea.append(message + "\r\n");
//
String soloString = client.soloId;
System.out.println("2222222222");
System.out.println(soloString+"11111111111");
for (int i = clients.size() - 1; i >= 0; i--) {
if(clients.get(i).getName().equals(soloString)) {
clients.get(i).getWriter().println(message + "(单独发送)");
clients.get(i).getWriter().flush();
}
//
// }
}
}
代码仅供参考~
附上运行截图:
获取项目:点击这里