Java Socket实现简易多人聊天室传输聊天内容或文件

Java Socket 是一种用于在网络上进行通信的机制,可以实现客户端和服务器之间的数据传输。在简易多人聊天室中,使用 Java Socket 实现聊天内容或文件的传输的原理如下:

  1. 服务器端启动:聊天室的服务器端在指定的端口上监听客户端的连接。它创建一个 ServerSocket 对象,并通过调用 accept() 方法等待客户端的连接请求。

  2. 客户端连接:聊天室的客户端通过创建一个 Socket 对象并指定服务器的地址和端口,与服务器建立连接。客户端和服务器之间的连接建立后,可以进行数据传输。

  3. 服务器端接收消息:当客户端连接到服务器后,服务器会为每个客户端创建一个独立的线程,用于处理与该客户端的通信。在服务器端的线程中,通过调用输入流的 readLine() 方法读取客户端发送的消息。服务器可以根据接收到的消息类型(例如普通消息或文件传输请求),采取相应的处理逻辑。

  4. 服务器端广播消息:服务器在接收到客户端发送的消息后,可以将该消息广播给其他连接到服务器的客户端。通过遍历保存所有客户端的列表,并调用相应客户端的输出流发送消息给客户端。

  5. 客户端发送消息:客户端可以通过输出流向服务器发送消息。客户端将消息写入输出流,然后通过网络发送给服务器。

  6. 客户端接收消息:客户端在一个独立的线程中通过输入流不断监听服务器端的消息。通过调用输入流的 readLine() 方法读取服务器端发送的消息,并进行相应的处理,如将消息显示在用户界面上。

  7. 文件传输:客户端可以通过输入流读取文件内容,并通过输出流将文件数据发送给服务器。服务器在接收到文件数据后,可以将文件广播给其他客户端。

以上就是使用 Java Socket 实现简易多人聊天室传输聊天内容或文件的基本原理。通过建立客户端和服务器之间的连接,以及使用输入流和输出流进行数据的读写,可以实现实时的聊天和文件传输功能。

---------------------------------------------------------------------------------------------------------------------------------

项目结构如下

 

Server类

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
    private static final int PORT = 12345;
    private List<ChatClientHandler> clients;

    public ChatServer() {
        clients = new ArrayList<>();
    }

    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket(PORT);
            System.out.println("Server started on port " + PORT);

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("New client connected");

                ChatClientHandler handler = new ChatClientHandler(clientSocket, this);
                clients.add(handler);
                new Thread(handler).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void broadcastMessage(String message, ChatClientHandler sender) {
        for (ChatClientHandler client : clients) {
            if (client != sender) {
                client.sendMessage(message);
            }
        }
    }

    public void broadcastFile(String fileName, byte[] fileData, ChatClientHandler sender) {
        for (ChatClientHandler client : clients) {
            if (client != sender) {
                client.sendFile(fileName, fileData);
            }
        }
    }

    public void removeClient(ChatClientHandler client) {
        clients.remove(client);
        System.out.println("Client disconnected");
    }

    public static void main(String[] args) {
        ChatServer server = new ChatServer();
        server.start();
    }
}
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
    private static final int PORT = 12345;
    private List<ChatClientHandler> clients;

    public ChatServer() {
        clients = new ArrayList<>();
    }

    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket(PORT);
            System.out.println("Server started on port " + PORT);

            while (true) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("New client connected");

                ChatClientHandler handler = new ChatClientHandler(clientSocket, this);
                clients.add(handler);
                new Thread(handler).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void broadcastMessage(String message, ChatClientHandler sender) {
        for (ChatClientHandler client : clients) {
            if (client != sender) {
                client.sendMessage(message);
            }
        }
    }

    public void broadcastFile(String fileName, byte[] fileData, ChatClientHandler sender) {
        for (ChatClientHandler client : clients) {
            if (client != sender) {
                client.sendFile(fileName, fileData);
            }
        }
    }

    public void removeClient(ChatClientHandler client) {
        clients.remove(client);
        System.out.println("Client disconnected");
    }

    public static void main(String[] args) {
        ChatServer server = new ChatServer();
        server.start();
    }
}
  • import语句导入了所需的Java类和接口。
  • ChatServer类是服务器端的主类。
  • PORT常量指定了服务器将要监听的端口号。
  • clients是一个存储ChatClientHandler对象的列表,用于跟踪连接到服务器的客户端。
  • start()方法启动服务器的主要逻辑。
  • 创建一个ServerSocket对象,绑定到指定的端口,并开始监听客户端连接请求。
  • serverSocket.accept()方法等待客户端连接并返回一个Socket对象表示与客户端的通信。
  • 为每个客户端连接创建一个ChatClientHandler对象,并将其添加到clients列表中。
  • 启动一个新的线程来处理每个客户端连接的消息传输。
  • broadcastMessage()方法用于向所有连接的客户端广播消息,但不发送给消息的发送者。
  • 遍历clients列表中的每个ChatClientHandler对象,并调用其sendMessage()方法发送消息。
  • broadcastFile()方法用于向所有连接的客户端广播文件内容,但不发送给文件的发送者。
  • 遍历clients列表中的每个ChatClientHandler对象,并调用其sendFile()方法发送文件内容。
  • removeClient()方法从clients列表中移除指定的ChatClientHandler对象,表示该客户端已断开连接。

这个类是 ChatServer 中的一个线程类,用于处理与客户端的通信。它实现了 Runnable 接口,通过在独立的线程中运行来处理客户端的消息。

ChatClientHandler 类的作用是与客户端建立连接并处理与客户端的通信,包括接收和发送消息以及接收和发送文件。通过该类,服务器可以与多个客户端同时进行通信并实现聊天室的功能。

ChatClientHandler 类

package com.qqcc.server;

/**
 * @author Scyth1
 * @create 2023/7/17 16:28
 */
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatClientHandler implements Runnable {
    private Socket clientSocket;
    private BufferedReader reader;
    private PrintWriter writer;
    private ChatServer server;

    public ChatClientHandler(Socket clientSocket, ChatServer server) {
        this.clientSocket = clientSocket;
        this.server = server;

        try {
            reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            writer = new PrintWriter(clientSocket.getOutputStream(), true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            String message;
            while ((message = reader.readLine()) != null) {
                if (message.startsWith("/file ")) {
                    String fileName = message.substring(6);
                    int fileSize = Integer.parseInt(reader.readLine());
                    byte[] fileData = new byte[fileSize];

                    // 使用 DataInputStream 读取字节数据
                    DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
                    dis.readFully(fileData);

                    server.broadcastFile(fileName, fileData, this);
                } else {
                    server.broadcastMessage(message, this);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            server.removeClient(this);
            close();
        }
    }

    public void sendMessage(String message) {
        writer.println(message);
    }

    public void sendFile(String fileName, byte[] fileData) {
        writer.println("/file " + fileName);
        writer.println(fileData.length);

        try {
            // 使用 DataOutputStream 发送字节数据
            DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream());
            dos.write(fileData, 0, fileData.length);
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void close() {
        try {
            if (reader != null) {
                reader.close();
            }
            if (writer != null) {
                writer.close();
            }
            if (clientSocket != null) {
                clientSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 ChatClient类(客户端)

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 12345;

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(SERVER_HOST, SERVER_PORT);

            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);

            // 创建并启动接收消息的线程
            Thread receiverThread = new Thread(new MessageReceiver(reader));
            receiverThread.start();

            // 读取用户输入并发送消息或文件给服务器
            BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in));
            String userInput;
            while ((userInput = userInputReader.readLine()) != null) {
                if (userInput.startsWith("/sendfile ")) {
                    String filePath = userInput.substring(10);
                    sendFile(filePath, writer);
                } else {
                    writer.println(userInput);
                }
            }

            // 关闭资源
            writer.close();
            reader.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void sendFile(String filePath, PrintWriter writer) {
        try {
            File file = new File(filePath);
            String fileName = file.getName();

            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] fileData = new byte[(int) file.length()];
            fileInputStream.read(fileData);

            writer.println("/file " + fileName);
            writer.flush();
            writer.println(fileData.length);
            writer.flush();
            writer.println(Base64.getEncoder().encodeToString(fileData));
            writer.flush();

            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class MessageReceiver implements Runnable {
        private BufferedReader reader;

        public MessageReceiver(BufferedReader reader) {
            this.reader = reader;
        }

        @Override
        public void run() {
            try {
                String message;
                while ((message = reader.readLine()) != null) {
                    if (message.startsWith("/file ")) {
                        String fileName = message.substring(6);
                        receiveFile(fileName, reader);
                    } else {
                        System.out.println(message);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private void receiveFile(String fileName, BufferedReader reader) {
            try {
                int fileSize = Integer.parseInt(reader.readLine());
                String fileData = reader.readLine();
                byte[] fileBytes = Base64.getDecoder().decode(fileData);

                FileOutputStream fileOutputStream = new FileOutputStream(fileName);
                fileOutputStream.write(fileBytes);
                fileOutputStream.close();

                System.out.println("Received file: " + fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • import语句导入了所需的Java类和接口。
  • ChatClient类是客户端的主类。
  • SERVER_HOSTSERVER_PORT常量分别指定服务器的主机名和端口号。
  • main()方法是程序的入口点。
  • 创建一个接收消息的线程,并通过Thread类进行管理和启动。
  • MessageReceiver类是一个实现Runnable接口的内部类,用于在单独的线程中接收服务器发送的消息。
  • 从标准输入读取用户输入的消息。
  • 使用BufferedReaderInputStreamReader从标准输入流(System.in)读取用户输入。
  • 循环读取用户输入,直到用户输入为null(按下Ctrl + D或输入结束标记)。
  • 如果用户输入以"/sendfile "开头,则解析文件路径,并调用sendFile()方法发送文件给服务器。
  • 否则,将用户输入的消息通过PrintWriterprintln()方法发送给服务器。
  • sendFile()方法用于发送文件给服务器。
  • 解析文件路径并获取文件名。
  • 使用FileInputStream读取文件的字节数据。
  • 将文件名、文件大小和文件内容依次发送给服务器,通过PrintWriterprintln()方法发送。
  • 使用Base64编码将文件内容转换为字符串形式发送。
  • MessageReceiver类实现了Runnable接口,用于在单独的线程中接收服务器发送的消息。
  • run()方法是线程的执行逻辑。
  • 通过BufferedReaderreadLine()方法从服务器接收消息。
  • 如果接收到的消息以"/file "开头,则解析文件名,并调用receiveFile()方法接收文件内容。
  • 否则,将接收到的消息打印到控制台。
  • receiveFile()方法用于接收文件内容。
  • 解析文件大小和文件内容,并进行Base64解码。
  • 使用FileOutputStream将文件内容写入到指定文件中。
  • 打印接收到的文件名到控制台。

客户端2

package com.qqcc.Client;

/**
 * @author Scyth1
 * @create 2023/7/17 16:34
 */
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatClient1 {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 12345;

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(SERVER_HOST, SERVER_PORT);

            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);

            // 创建并启动接收消息的线程
            Thread receiverThread = new Thread(new MessageReceiver(reader));
            receiverThread.start();

            // 读取用户输入并发送消息或文件给服务器
            BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in));
            String userInput;
            while ((userInput = userInputReader.readLine()) != null) {
                if (userInput.startsWith("/sendfile ")) {
                    String filePath = userInput.substring(10);
                    sendFile(filePath, writer);
                } else {
                    writer.println(userInput);
                }
            }

            // 关闭资源
            writer.close();
            reader.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void sendFile(String filePath, PrintWriter writer) {
        try {
            File file = new File(filePath);
            String fileName = file.getName();

            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] fileData = new byte[(int) file.length()];
            fileInputStream.read(fileData);

            writer.println("/file " + fileName);
            writer.flush();
            writer.println(fileData.length);
            writer.flush();
            writer.println(Base64.getEncoder().encodeToString(fileData));
            writer.flush();

            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class MessageReceiver implements Runnable {
        private BufferedReader reader;

        public MessageReceiver(BufferedReader reader) {
            this.reader = reader;
        }

        @Override
        public void run() {
            try {
                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端3

package com.qqcc.Client;

/**
 * @author Scyth1
 * @create 2023/7/17 16:34
 */
import java.io.*;
import java.net.*;
import java.util.*;

public class ChatClient1 {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 12345;

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(SERVER_HOST, SERVER_PORT);

            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);

            // 创建并启动接收消息的线程
            Thread receiverThread = new Thread(new MessageReceiver(reader));
            receiverThread.start();

            // 读取用户输入并发送消息或文件给服务器
            BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in));
            String userInput;
            while ((userInput = userInputReader.readLine()) != null) {
                if (userInput.startsWith("/sendfile ")) {
                    String filePath = userInput.substring(10);
                    sendFile(filePath, writer);
                } else {
                    writer.println(userInput);
                }
            }

            // 关闭资源
            writer.close();
            reader.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void sendFile(String filePath, PrintWriter writer) {
        try {
            File file = new File(filePath);
            String fileName = file.getName();

            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] fileData = new byte[(int) file.length()];
            fileInputStream.read(fileData);

            writer.println("/file " + fileName);
            writer.flush();
            writer.println(fileData.length);
            writer.flush();
            writer.println(Base64.getEncoder().encodeToString(fileData));
            writer.flush();

            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class MessageReceiver implements Runnable {
        private BufferedReader reader;

        public MessageReceiver(BufferedReader reader) {
            this.reader = reader;
        }

        @Override
        public void run() {
            try {
                String message;
                while ((message = reader.readLine()) != null) {
                    System.out.println(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果图

 

 

 

 

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java聊天模块是一种基于Java语言开发的用于实现聊天功能的模块。CSDN作为一个技术社区网站,也提供了相关的Java聊天模块的学习资源和文章。以下是关于Java聊天模块的一些介绍。 首先,Java聊天模块通常用于在网络环境下实现聊天功能。通过使用Java相关的网络编程技术,可以实现在不同的计算机之间进行消息的实时传输和交流。聊天模块可以基于客户端-服务器模型,其中一个计算机作为服务器,其他计算机作为客户端。服务器负责接受和转发消息,客户端负责发送和接收消息。 其次,Java聊天模块除了基本的聊天功能外,还可以提供其他附加功能,例如在线用户列表、聊天室创建和管理等。在线用户列表可以显示当前在线的用户信息,方便用户之间的查找和选择。聊天室创建和管理功能可以实现不同的聊天环境,例如私聊、群聊和讨论组等。 在CSDN上,有很多关于Java聊天模块的学习资源和文章。这些资源可以包括教程、代码示例、开发经验等等。通过学习这些资源,我们可以了解到如何使用Java编程语言实现聊天模块的核心功能,以及如何处理网络连接、消息传输、用户管理等问题。 总之,Java聊天模块是一种基于Java语言开发的模块,可以实现在网络环境下进行实时的聊天和消息传输。CSDN上提供了丰富的学习资源和文章,可以帮助我们学习和掌握Java聊天模块的开发技术和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值