简单的TCP多人聊天小程序
截图:
代码:
服务器:
//version 2.0
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;
public class Server implements ActionListener {
private static final int SERVER_PORT = 2222;
private ServerSocket server;
private JFrame frame;
private JPanel panel;
private JTextArea textArea;
private JScrollPane scrollPane;
private JTextField textField;
private JButton button;
private boolean isStarted = false; // 服务器是否启动
private List clients = new ArrayList();
public Server() {
frame = new JFrame("服务器");
panel = new JPanel();
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
scrollPane = new JScrollPane(textArea);
scrollPane.setBounds(5, 5, 275, 290);
scrollPane.setBorder(BorderFactory.createLoweredSoftBevelBorder());
textField = new JTextField();
textField.setBounds(6, 305, 210, 30);
button = new JButton("发送");
button.setBounds(220, 305, 60, 30);
button.addActionListener(this);
textField.addActionListener(this);
panel.add(scrollPane);
panel.add(textField);
panel.add(button);
panel.setLayout(null);
frame.add(panel);
frame.setSize(300, 400);
frame.setLocation((1366 - 640) >> 1, (768 - 400) >> 1);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// 使用Windows的界面风格
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
new Server().serverStart();
}
public void serverStart() {
while (!isStarted) { // 无限循环尝试启动服务器
try {
server = new ServerSocket(SERVER_PORT);
isStarted = true;
Thread.sleep(500);
} catch (BindException e) {
textArea.setText("端口2222被占用,请关闭对应的程序!\n");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
textArea.append("服务器启动,等待客户端连接……\n");
try {
// 无限循环检测是否有客户端加入,有则加到list
while (isStarted) {
Socket s = server.accept();
ChatroomClient client = new ChatroomClient(s);
clients.add(client);
client.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 服务器发送消息
public void send() {
if (textField.getText().length() < 1) { // 没有输入东西
return;
} else if (clients.size() == 0) {
textArea.append("无客户端连接!\n");
return;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = "服务器 " + dateFormat.format(new Date()) + "\n " + textField.getText() + "\n";
textArea.append(s);
// 循环给列表中的客户端发送信息
for (int i = 0; i < clients.size(); ++i) {
ChatroomClient client = clients.get(i);
client.send(s);
}
textField.setText(null);
}
public void actionPerformed(ActionEvent arg0) {
send();
}
// Inner Class ChatroomClient
class ChatroomClient extends Thread {
private Socket client;
private DataInputStream in;
private DataOutputStream out;
//private boolean isConnected = false;
// 客户端初始化
public ChatroomClient(Socket client) {
this.client = client;
try {
in = new DataInputStream(client.getInputStream());
out = new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
textArea.append("客户端已连接 " + dateFormat.format(new Date()) + "\n");
textArea.append("地址:" + client.getInetAddress().getHostAddress() + "\n端口:" + client.getPort() + "\n\n");
}
// 发送消息
public void send(String str) {
try {
out.writeUTF(str);
out.flush();
} catch (IOException e) {
clients.remove(this);
textArea.append("客户端已退出,从列表删除!\n");
}
}
public void run() {
try {
while (true) {
textArea.setCaretPosition(textArea.getDocument().getLength()); // 显示JTextArea最末
String str = in.readUTF();
//str = str.substring(0, 3) + (clients.indexOf(this) + 1) + str.substring(3);
textArea.append(str);
for (int i = 0; i < clients.size(); ++i) {
ChatroomClient client = clients.get(i);
client.send(str);
}
Thread.sleep(100); // 每100ms读取对方信息一次
}
} catch (IOException e) {
textArea.append("客户端断开连接!\n");
clients.remove(this);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
clients.remove(this);
try {
if (in != null)
client.close();
if (out != null)
client.close();
if (client != null)
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端:
//version 2.0
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;
public class Client {
public static void main(String[] args) {
// 使用Windows的界面风格
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
new TCPClient().start();
}
}
class TCPClient extends Thread implements ActionListener, MouseListener {
private String des = "127.0.0.1"; // 服务器地址
private int port = 2222; // 服务器端口
private Socket client;
private DataInputStream in;
private DataOutputStream out;
private JFrame frame;
private JPanel panel;
private JTextArea textArea;
private JScrollPane scrollPane;
private JTextField textField;
private JTextField tfDes, tfPort;
private JLabel label1, label2, addrChange;
private JButton button;
private boolean isConnected = false; // 是否连接上
public TCPClient() {
frame = new JFrame("客户端");
panel = new JPanel();
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
scrollPane = new JScrollPane(textArea);
scrollPane.setBounds(5, 5, 275, 290);
scrollPane.setBorder(BorderFactory.createLoweredSoftBevelBorder());
textField = new JTextField();
textField.setBounds(6, 305, 210, 30);
textField.addActionListener(this);
button = new JButton("发送");
button.setBounds(220, 305, 60, 30);
button.addActionListener(this);
label1 = new JLabel("服务器地址:");
label1.setBounds(10, 340, 75, 20);
tfDes = new JTextField(des);
tfDes.setBounds(75, 341, 80, 20);
tfDes.setBorder(null);
label2 = new JLabel("端口:");
label2.setBounds(160, 340, 40, 20);
tfPort = new JTextField(Integer.toString(port));
tfPort.setBounds(190, 341, 35, 20);
tfPort.setBorder(null);
addrChange = new JLabel("连接");
addrChange.setForeground(Color.BLUE);
addrChange.setBounds(235, 337, 30, 20);
addrChange.setBorder(BorderFactory.createRaisedBevelBorder());
addrChange.addMouseListener(this);
panel.add(scrollPane);
panel.add(textField);
panel.add(button);
panel.add(label1);
panel.add(tfDes);
panel.add(label2);
panel.add(tfPort);
panel.add(addrChange);
panel.setLayout(null);
frame.add(panel);
frame.setSize(300, 400);
frame.setLocation(1366 >> 1, (768 - 400) >> 1);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// 发送消息
public void send() {
if (textField.getText().length() < 1) { // 没有输入东西
return;
} else if (out == null || client.isClosed()) {
textArea.append("没有与服务器连接!\n");
return;
}
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
out.writeUTF(InetAddress.getLocalHost().getHostName() + " " + dateFormat.format(new Date()) + "\n " + textField.getText() + "\n");
out.flush();
//textArea.append("客户端 " + new Date().toLocaleString() + "\n " + textField.getText() + "\n");
textField.setText(null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent arg0) {
send();
}
@Override
public void mouseClicked(MouseEvent arg0) {
}
@Override
public void mouseEntered(MouseEvent arg0) {
}
@Override
public void mouseExited(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent arg0) {
addrChange.setBorder(BorderFactory.createLoweredBevelBorder());
}
@Override
public void mouseReleased(MouseEvent arg0) {
addrChange.setBorder(BorderFactory.createRaisedBevelBorder());
if (!tfDes.getText().matches(
"([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}")
|| !tfPort.getText().matches(
"[0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]")) {
textArea.append("请输入正确的地址和端口!!\n");
return;
}
String tmpd = tfDes.getText();
int tmpp = Integer.parseInt(tfPort.getText());
if (des.equals(tmpd) && port == tmpp) {
if (isConnected == true)
textArea.append("已经和指定服务器连上,请不要重复连接!\n");
return;
}
des = tmpd;
port = tmpp;
try {
if (in != null)
in.close();
if (out != null)
out.close();
if (client != null)
client.close();
} catch (IOException e) {
e.printStackTrace();
}
if (isConnected == false) {
textArea.append("正在连接服务器……\n");
textArea.append("目标地址:" + des + "\n");
textArea.append("目标端口:" + port + "\n");
} else {
textArea.append("用户中断当前连接!\n");
}
isConnected = false;
}
public void run() {
while (true) {
textArea.append("正在连接服务器……\n");
textArea.append("目标地址:" + des + "\n");
textArea.append("目标端口:" + port + "\n");
while (!isConnected) {
try {
client = new Socket(des, port);
in = new DataInputStream(client.getInputStream());
out = new DataOutputStream(client.getOutputStream());
isConnected = true;
Thread.sleep(500);
} catch (IOException e) {
continue;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
textArea.append("连接服务器成功!" + dateFormat.format(new Date()) + "\n\n");
try {
while (isConnected) {
textArea.setCaretPosition(textArea.getDocument().getLength()); // 显示JTextArea最末
textArea.append(in.readUTF()); // 每100ms读取对方信息一次
Thread.sleep(100);
}
} catch (IOException e) {
textArea.append("与服务器失去连接!\n\n");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
if (out != null)
out.close();
if (client != null)
client.close();
} catch (IOException e) {
e.printStackTrace();
}
isConnected = false;
}
}
}
}