我们今天做一个局域聊天室
1.创建一个名为Client的包,代码如下:
package javab;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
public class Client{
private JFrame frame;
private JList userList;
private JTextArea textArea;
private JTextField textField;
private JTextField txt_port;
private JTextField txt_hostIp;
private JTextField txt_name;
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 static void main(String[] args) {
new Client();
}
public void send() {
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;
}
sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message);
textField.setText(null);
}
public Client() {
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setForeground(Color.blue);
textField = new JTextField();
txt_port = new JTextField("6666");
txt_hostIp = new JTextField("127.0.0.1");
txt_name = new JTextField("刘帆");
btn_start = new JButton("连接");
btn_stop = new JButton("断开");
btn_send = new JButton("发送");
listModel = new DefaultListModel();
userList = new JList(listModel);
northPanel = new JPanel();
northPanel.setLayout(new GridLayout(1, 7));
northPanel.add(new JLabel("端口"));
northPanel.add(txt_port);
northPanel.add(new JLabel("服务器IP"));
northPanel.add(txt_hostIp);
northPanel.add(new JLabel("姓名"));
northPanel.add(txt_name);
northPanel.add(btn_start);
northPanel.add(btn_stop);
northPanel.setBorder(new TitledBorder("连接信息"));
rightScroll = new JScrollPane(textArea);
rightScroll.setBorder(new TitledBorder("消息显示区"));
leftScroll = new JScrollPane(userList);
leftScroll.setBorder(new TitledBorder("在线用户"));
southPanel = new JPanel(new BorderLayout());
southPanel.add(textField, "Center");
southPanel.add(btn_send, "East");
southPanel.setBorder(new TitledBorder("写消息"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll,
rightScroll);
centerSplit.setDividerLocation(100);
frame = new JFrame("客户机");
frame.setLayout(new BorderLayout());
frame.add(northPanel, "North");
frame.add(centerSplit, "Center");
frame.add(southPanel, "South");
frame.setSize(600, 400);
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();
}
});
btn_send.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});
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);
}
});
}
public boolean connectServer(int port, String hostIp, String name) {
try {
socket = new Socket(hostIp, port);
writer = new PrintWriter(socket.getOutputStream());
reader = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
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;
}
}
public void sendMessage(String message) {
writer.println(message);
writer.flush();
}
@SuppressWarnings("deprecation")
public synchronized boolean closeConnection() {
try {
sendMessage("CLOSE");
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();
if (command.equals("CLOSE"))
{
textArea.append("服务器已关闭!\r\n");
closeCon();
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.创建一个名为Server的包,代码如下:
package javab;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.StringTokenizer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
public class Server {
private JFrame frame;
private JTextArea contentArea;
private JTextField txt_message;
private JTextField txt_max;
private JTextField txt_port;
private JButton btn_start;
private JButton btn_stop;
private JButton btn_send;
private JPanel northPanel;
private JPanel southPanel;
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;
public static void main(String[] args) {
new Server();
}
public void send() {
if (!isStart) {
JOptionPane.showMessageDialog(frame, "server not start,!", "ERROR",
JOptionPane.ERROR_MESSAGE);
return;
}
if (clients.size() == 0) {
JOptionPane.showMessageDialog(frame, "NOT User", "ERROR",
JOptionPane.ERROR_MESSAGE);
return;
}
String message = txt_message.getText().trim();
if (message == null || message.equals("")) {
JOptionPane.showMessageDialog(frame, "Information is not null!", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
sendServerMessage(message);
contentArea.append("server:" + txt_message.getText() + "\r\n");
txt_message.setText(null);
}
public Server() {
frame = new JFrame("server");
contentArea = new JTextArea();
contentArea.setEditable(false);
contentArea.setForeground(Color.blue);
txt_message = new JTextField();
txt_max = new JTextField("10");
txt_port = new JTextField("6666");
btn_start = new JButton("Start");
btn_stop = new JButton("Stop");
btn_send = new JButton("Send");
btn_stop.setEnabled(false);
listModel = new DefaultListModel();
userList = new JList(listModel);
southPanel = new JPanel(new BorderLayout());
southPanel.setBorder(new TitledBorder("write Information"));
southPanel.add(txt_message, "Center");
southPanel.add(btn_send, "East");
leftPanel = new JScrollPane(userList);
leftPanel.setBorder(new TitledBorder("Online users"));
rightPanel = new JScrollPane(contentArea);
rightPanel.setBorder(new TitledBorder("Message display aera"));
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
rightPanel);
centerSplit.setDividerLocation(100);
northPanel = new JPanel();
northPanel.setLayout(new GridLayout(1, 6));
northPanel.add(new JLabel("Max Connection"));
northPanel.add(txt_max);
northPanel.add(new JLabel("端口"));
northPanel.add(txt_port);
northPanel.add(btn_start);
northPanel.add(btn_stop);
northPanel.setBorder(new TitledBorder("配置信息"));
frame.setLayout(new BorderLayout());
frame.add(northPanel, "North");
frame.add(centerSplit, "Center");
frame.add(southPanel, "South");
frame.setSize(600, 400);
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);
}
});
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, "server已处于启动状态,不要重复启动!",
"Error", 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("server已成功启动!人数上限:" + max + ",端口:" + port
+ "\r\n");
JOptionPane.showMessageDialog(frame, "server成功启动!");
btn_start.setEnabled(false);
txt_max.setEnabled(false);
txt_port.setEnabled(false);
btn_stop.setEnabled(true);
} catch (Exception exc) {
JOptionPane.showMessageDialog(frame, exc.getMessage(),
"Error", 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, "停止服务器发生异常!", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
});
}
public void serverStart(int max, int port) throws 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) {
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println("server:" + 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 void run() {
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(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());
writer.println(user.getName() + user.getIp() + "与服务器连接成功!");
writer.flush();
if (clients.size() > 0) {
String temp = "";
for (int i = clients.size() - 1; i >= 0; i--) {
temp += (clients.get(i).getUser().getName() + "/" + clients
.get(i).getUser().getIp())
+ "@";
}
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();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void run() {
String message = null;
while (true) {
try {
message = reader.readLine();
if (message.equals("CLOSE"))
{
contentArea.append(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();
}
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();
message = source + "说:" + content;
contentArea.append(message + "\r\n");
if (owner.equals("ALL")) {
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter().println(message + "(多人发送)");
clients.get(i).getWriter().flush();
}
}
}
}
}
3.创建一个名为User的包,代码如下:
package javab;
public class User{
private String name;
private String ip;
public User(String name, String ip) {
this.name = name;
this.ip = ip;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
4.运行结果如下图:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6d8c50434917512ac1f983e52934bb94.png#pic_center)