上图啦!!!
首先运行:
Server.java
然后启动:
Client.java
最后退出客户端:
代码实现
Client
package chat;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();}
}
Server
package chat;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<ChatroomClient> clients = new ArrayList<ChatroomClient>();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 {// 无限循环检测是否有客户端加入,有则加到listwhile (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 ChatroomClientclass 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(); } } } } }
TCPClient
package chat;import java.awt.Color;
import java.awt.event.*;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.*;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();}public void mouseClicked(MouseEvent arg0) {}public void mouseEntered(MouseEvent arg0) {}public void mouseExited(MouseEvent arg0) {}public void mousePressed(MouseEvent arg0) {addrChange.setBorder(BorderFactory.createLoweredBevelBorder());}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;}}}}