基于Java实现简易的局域网对话系统

yizhihongxing

基于Java实现简易的局域网对话系统攻略

介绍

在本文中,我们将基于Java语言开发一款简易的局域网对话系统,方便局域网内的用户之间进行在线聊天。系统将通过Java Socket和Swing进行 GUI 界面设计,并利用Java多线程技术实现并发通信。

准备工作

在开发项目之前,需要准备以下环境:

  1. JDK环境: 可以通过官网下载相关版本并安装。
  2. Eclipse IDE: 后续开发实现以Eclipse为例。
  3. 相关包、jar文件: 项目中需要用到的jar包可在 Maven 仓库中进行下载。

项目结构

在开始实现之前,需要创建相应的项目目录结构来组织后续开发所需的文件。具体如下:

.
├── bin
├── lib
│   ├── commons-io-2.8.0.jar
│   ├── commons-lang3-3.12.0.jar
│   └── log4j-api-2.14.1.jar
    └── log4j-core-2.14.1.jar
└── src
    ├── client
    │   ├── Client.java
    │   └── ClientGUI.java
    ├── common
    │   └── Message.java
    ├── server
    │   ├── Server.java
    │   └── ServerGUI.java
    └── util
        ├── Connection.java
        ├── MessageListener.java
        └── MessageSender.java
  • lib: 存放项目所需的所有第三方jar包。
  • src: 存放所有源码文件。具体分为客户端代码和服务端代码。

服务端实现

设计协议

在开始实现之前,需要先约定客户端和服务端通信所需的协议格式。这里我们采用二进制协议,具体内容如下:

  • 第1-4字节: 表示消息长度(int类型)
  • 第5-6字节: 表示消息类型(short类型)
  • 第7-字节: 表示消息内容(byte数组类型)

编写服务端代码

  1. 创建Server类,用于监听客户端连接并分发消息。

示例代码:

public class Server {
    private ServerSocket serverSocket;
    private final List<Connection> connections;

    public Server(int port) {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
        connections = new ArrayList<>();
    }

    public void start() {
        while (true) {
            try {
                Socket clientSocket = serverSocket.accept();
                Connection connection = new Connection(clientSocket);
                connections.add(connection);
                MessageListener listener = new MessageListener(connection, connections);
                listener.start();
            } catch (IOException e) {
                System.err.println("Error: " + e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        new Server(9999).start();
    }
}
  1. 创建ServerGUI类,用于监听服务端的启动和关闭。

示例代码:

public class ServerGUI {
    private JFrame frame;
    private JTextArea textArea;

    public ServerGUI() {
        frame = new JFrame("Server");
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 添加日志记录器
        textArea = new JTextArea();
        JScrollPane scrollPane = new JScrollPane(textArea);
        frame.add(scrollPane);

        frame.setVisible(true);

        // 启动服务端
        new Thread(() -> {
            Server server = new Server(9999);
            server.start();
        }).start();
    }

    public void log(String message) {
        textArea.append(message + "\n");
    }

    public static void main(String[] args) {
        new ServerGUI();
    }
}
  1. 创建Connection类,用于处理客户端连接并向客户端发送消息。每一个Connection实例对应一个客户端连接。

示例代码:

public class Connection {
    private final Socket socket;
    private final OutputStream outputStream;

    public Connection(Socket socket) throws IOException {
        this.socket = socket;
        this.outputStream = socket.getOutputStream();
    }

    public void send(Message message) throws IOException {
        outputStream.write(message.toBytes());
        outputStream.flush();
    }

    public void close() throws IOException {
        socket.close();     // 关闭连接
        // 通知服务端移除连接
    }
}
  1. 创建MessageListener类,用于监听客户端发来的消息并广播给所有客户端。

示例代码:

public class MessageListener extends Thread {
    private final Connection connection;
    private final List<Connection> connections;

    public MessageListener(Connection connection, List<Connection> connections) {
        this.connection = connection;
        this.connections = connections;
    }

    @Override
    public void run() {
        while (true) {
            try {
                DataInputStream in = new DataInputStream(connection.socket.getInputStream());
                int length = in.readInt();
                short type = in.readShort();
                byte[] content = new byte[length - 6];
                in.read(content);
                Message message = new Message(type, content);
                for (Connection conn : connections) {
                    if (conn != connection) {
                        conn.send(message);
                    }
                }
            } catch (IOException e) {
                System.err.println("Error: " + e.getMessage());
                break;
            }
        }

        try {
            connection.close();
        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

客户端实现

设计GUI界面

客户端需要具有如下GUI界面:

  • 连接服务器:
  • 输入服务器IP地址和端口号以建立连接。
  • 点击“Connect”按钮建立连接。
  • 在线聊天:
  • 显示聊天信息。
  • 可以输入发送消息。

编写客户端代码

  1. 创建Message类,用于封装消息类型和内容。

示例代码:

public class Message {
    private short type;
    private byte[] content;

    public Message(short type, byte[] content) {
        this.type = type;
        this.content = content;
    }

    public byte[] toBytes() {
        ByteBuffer buffer = ByteBuffer.allocate(6 + content.length);
        buffer.putInt(6 + content.length);
        buffer.putShort(type);
        buffer.put(content);
        return buffer.array();
    }
}
  1. 创建Client类,用于建立和服务器的连接,并向服务器发送消息。

示例代码:

public class Client {
    private Socket socket;
    private InputStream in;
    private OutputStream out;

    public Client(String serverAddress, int serverPort) throws IOException {
        socket = new Socket(serverAddress, serverPort);
        in = socket.getInputStream();
        out = socket.getOutputStream();
    }

    public void send(Message message) throws IOException {
        out.write(message.toBytes());
        out.flush();
    }

    public void close() throws IOException {
        socket.close();
    }
}
  1. 创建ClientGUI类,用于实现GUI界面和用户交互。

示例代码:

public class ClientGUI implements ActionListener {
    private Client client;
    private JFrame frame;
    private JTextField textField;
    private JTextArea textArea;
    private JButton sendButton;

    public ClientGUI() {
        frame = new JFrame("Client");
        frame.setLayout(new BorderLayout());
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 连接服务器
        JPanel connectPanel = new JPanel();
        connectPanel.setLayout(new FlowLayout());
        JLabel addressLabel = new JLabel("Server Address:");
        JTextField addressField = new JTextField("localhost");
        addressField.setColumns(10);
        JLabel portLabel = new JLabel("Server Port:");
        JTextField portField = new JTextField("9999");
        portField.setColumns(5);
        JButton connectButton = new JButton("Connect");
        connectButton.addActionListener(e -> {
            try {
                client = new Client(addressField.getText(), Integer.parseInt(portField.getText()));
                MessageListener listener = new MessageListener(client, this);
                listener.start();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        });
        connectPanel.add(addressLabel);
        connectPanel.add(addressField);
        connectPanel.add(portLabel);
        connectPanel.add(portField);
        connectPanel.add(connectButton);
        frame.add(connectPanel, BorderLayout.NORTH);

        // 在线聊天
        textArea = new JTextArea();
        textArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(textArea);
        frame.add(scrollPane, BorderLayout.CENTER);

        textField = new JTextField();
        sendButton = new JButton("Send");
        sendButton.addActionListener(this);

        JPanel messagePanel = new JPanel();
        messagePanel.setLayout(new BorderLayout());
        messagePanel.add(textField, BorderLayout.CENTER);
        messagePanel.add(sendButton, BorderLayout.EAST);
        frame.add(messagePanel, BorderLayout.SOUTH);

        frame.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        try {
            String content = textField.getText();
            if (!content.isEmpty()) {
                Message message = new Message((short) 0, content.getBytes(StandardCharsets.UTF_8));
                client.send(message);
            }
            textField.setText("");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public void log(String message) {
        textArea.append(message + "\n");
    }

    public static void main(String[] args) {
        new ClientGUI();
    }
}
  1. 创建MessageListener类,用于监听服务端发来的消息并打印出来。

示例代码:

public class MessageListener extends Thread {

    private final Client client;
    private final ClientGUI clientGUI;

    public MessageListener(Client client, ClientGUI clientGUI) {
        this.client = client;
        this.clientGUI = clientGUI;
    }

    @Override
    public void run() {
        while (true) {
            try {
                DataInputStream in = new DataInputStream(client.in);
                int length = in.readInt();
                short type = in.readShort();
                byte[] content = new byte[length - 6];
                in.read(content);
                Message message = new Message(type, content);
                clientGUI.log(new String(message.getContent(), StandardCharsets.UTF_8));
            } catch (IOException e) {
                System.err.println("Error: " + e.getMessage());
                break;
            }
        }

        try {
            client.close();
        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

测试

在本地启动服务端,然后启动多个客户端,输入相同的IP地址和端口号建立连接,即可进行测试。

结论

本文详细讲解了如何基于Java实现简易的局域网对话系统,在代码实现过程中涉及到了Java Socket、Swing、多线程等技术,涵盖了Java开发常用的技术点。本文提供了完整的代码示例以及目录结构、协议设计的详细说明,可供读者逐步学习和实践。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Java实现简易的局域网对话系统 - Python技术站

(0)
上一篇 2023年5月30日
下一篇 2023年5月30日

相关文章

  • Java后缀数组之求sa数组的实例代码

    Java后缀数组是一种经典的字符串匹配算法,可以实现快速求解字符串的后缀数组(sa数组)。下面我们将介绍如何在Java中编写求解sa数组的实例代码。 步骤一:构造后缀数组 首先我们需要准备一个包含原始字符串所有后缀的数组(称为“后缀数组”)。这个数组的元素类型为Suffix,其中Suffix类的定义如下: class Suffix implements Co…

    Java 2023年5月26日
    00
  • 如何使用Java运行期注解?

    准备工作: 在本地电脑上安装Java开发环境,确保可以运行Java程序。 Step 1:定义注解 在Java中,定义注解需要使用@interface关键字,如下所示: public @interface MyAnnotation { String value(); } 其中,@interface是用来声明一个注解的关键字,MyAnnotation是注解的名称…

    Java 2023年5月11日
    00
  • 什么是Java安全管理器?

    Java安全管理器是Java运行时环境提供的一种访问控制机制,用于控制Java程序的访问权限。它的作用是为Java程序提供安全保障,限制其对系统资源的访问和操作,保证程序的安全性。 Java安全管理器可以通过在程序运行时设置Java安全策略文件来实现,这个策略文件定义了一组规则,规定了Java程序可以访问哪些资源、以什么方式访问、如何检查访问权限等。通过使用…

    Java 2023年5月11日
    00
  • js 生成随机汉字的问题

    让我们来详细讲解一下“JS生成随机汉字的问题”。 随机生成汉字 在js中生成随机汉字,通常需要使用Unicode编码表中汉字的编码范围。根据Unicode编码表,汉字的编码范围为\u4e00到\u9fa5,因此,我们可以使用js的Math.random()函数生成一个随机数,并将其转换为汉字。 function randomChinese() { var i…

    Java 2023年6月15日
    00
  • java读取文件字符集示例方法

    针对“java读取文件字符集示例方法”的完整攻略,我将提供以下过程和两个示例: 一、文件字符集的概念和了解 在学习如何读取文件字符集之前,先了解以下文件字符集的概念。文件字符集可以理解为一个字符集编码方式,它规定了计算机语言在计算机内表示字符或者数字时所采用的编码方式。在不同的操作系统或者软件中,对于字符集的选择会不同。如果我们读取了一个文件,但是文件中的字…

    Java 2023年5月19日
    00
  • Java8中Stream的详细使用方法大全

    Java8中Stream的详细使用方法大全 本文将详细介绍Java8中Stream的使用方法,包括Stream的定义、Stream常用操作、中间操作和终止操作等。 一、Stream的定义 Stream是Java 8中的新特性,它是对数据集合进行流式操作的API。使用Stream可以让我们更方便地对集合进行操作,提高代码的可读性和代码的简洁性。 二、Strea…

    Java 2023年5月26日
    00
  • 常见的Java性能调优工具有哪些?

    Java性能调优是提高应用程序性能和并发运行效率的必要手段,为了提高Java应用程序的性能,需要使用一些专业的性能调优工具。 常见的Java性能调优工具有以下几种: JProfiler:JProfiler是一种动态的Java代码性能分析工具,主要特点是高效和低侵入性,可以帮助开发人员快速定位Java应用程序的性能瓶颈,并提出优化建议。使用JProfiler进…

    Java 2023年5月11日
    00
  • Spring Boot教程之必须了解的核心概念

    下面我将为你讲解Spring Boot教程之必须了解的核心概念的完整攻略。 Spring Boot教程之必须了解的核心概念 Spring Boot是一个基于Spring Framework的快速开发框架,它可以大大简化Spring应用的初始配置。在学习Spring Boot之前,我们需要了解一些核心概念以便更好地理解和应用。 1. Spring Boot的自…

    Java 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部