Java Socket实现多人聊天室

Java小练手项目:用Java Socket实现多人聊天室,聊天室功能包括传输聊天内容或者文件。相比于其它的聊天室,增加了传输文件的功能供参考。

模块拆解

分成服务端和客户端两部分来写。

服务端包括监听线程和处理收发信线程:

  1. 创建监听线程,监听客户端的连接。将每个连接的客户端加入维护的列表,并为每个连接的客户端开启一个处理收发信的线程。
  2. 在每个客户端的收发信线程中,接收每个客户端发回的消息,并对其进行转发到相应接收的客户端上,以此实现多人聊天室。
  3. 添加处理传输文件的判断,通过在传输的字节数组中添加标志位来区分传输的是文本消息,还是文件。

客户端包括发送消息线程和接收消息线程:

  1. 发送消息线程,用来处理用户的输入信息,判断输入的是文本信息还是文件,并修改传输的字节数组标志位进行区分。最后将信息传输给服务器。
  2. 接收消息线程,用来处理服务器发回的信息,根据标志位判断输入的是文本信息还是文件,并做相应处理。如果是文本信息,则显示在控制台,如果是文件,则保存在指定目录下。

项目的目录结构如下所示

Java Socket实现多人聊天室

接下来,给出实际的代码进行分析。

服务器端

监听线程

<pre class="prettyprint hljs gradle" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package Server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MultiServer {
    public static void main(String[] args) {
        ServerSocket ss = null;
        Socket s = null;

        // 定义一个List列表来保存每个客户端,每新建一个客户端连接,就添加到List列表里。
        List<Socket> listSocket = new ArrayList<>();
        try {
            // 1. 创建ServerSocket类型的对象并提供端口号
            ss = new ServerSocket(9999);
            // 2. 等待客户端的连接请求,调用accept方法
            // 采用多线程的方式,允许多个用户请求连接。
            int i = 0;
            while (true) {
                System.out.println("等待客户端的连接请求...");
                s = ss.accept();
                listSocket.add(s);
                //sArr[i] = s;
                i++;
                System.out.printf("欢迎用户%d加入群聊!n", i);
                System.out.printf("目前群聊中共有%d人n", listSocket.size());
                InetAddress inetAddress = s.getInetAddress();
                System.out.println("客户端" + inetAddress + "连接成功!");
                // 调用多线程方法,每一个连上的客户端,服务器都有一个线程为之服务
                new MultiServerThread(s, inetAddress, listSocket).start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            try {
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

上述代码实现服务器监听客户端连接,利用 accept 方法,每加入一个客户端,服务器都创建一个线程为之服务,同时将其加入一个List集合中,用来保存已加入聊天室的所有客户端。

处理收发信的线程

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package Server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;

public class MultiServerThread extends Thread {
    private Socket s;
    private InetAddress inetAddress;
    private List<Socket> listSockets;

    public MultiServerThread(Socket s, InetAddress inetAddress, List<Socket> listSockets) {
        this.s = s;
        this.inetAddress = inetAddress;
        this.listSockets = listSockets;
    }

    public void BroadCast(Socket s, byte[] by, int res) {
        // 将服务器接收到的消息发送给除了发送方以外的其他客户端
        int i = 0;
        for (Socket socket: listSockets)
        {
            if (s!=socket)  // 判断不是当前发送的客户端
            {
                System.out.println("发送给用户: " + listSockets.indexOf(socket));
                BufferedOutputStream ps = null;
                try {
                    ps = new BufferedOutputStream(socket.getOutputStream());
                    ps.write(by, 0, res);   // 写入输出流,将内容发送给客户端的输入流
                    ps.flush();

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

    // 服务器与客户端的交互线程
    @Override
    public void run() {
        BufferedInputStream ois = null;
        BufferedOutputStream oos = null;
        try {
            ois = new BufferedInputStream(s.getInputStream());

            oos = new BufferedOutputStream(s.getOutputStream());

            int i = 0;
            while (true) {
                //System.out.println("进入MultiChatServerThread");
                byte[] by = new byte[1024+2];
                //System.out.println("by.length: " + by.length);
                int res = 0;
                res = ois.read(by);
                // 对读取到的字节数组第一位位置进行修改,标识该数据流是由哪个用户发送来的
                by[0] = (byte)listSockets.indexOf(s);

                if (by[1] == 2){
                    // 因为前两个位置是标志位,所以length的大小为读取的字节数-2,同时offset也从第三个位置(下标是2)开始读
                    String receive = new String(by, 2, res-2);

                    if (receive.equalsIgnoreCase("bye"))
                    {
                        // 如果客户端发送的是bye, 说明其下线,则从listSockets里删除对应的socket.
                        oos.write(receive.getBytes());  // 把bye给客户端的读取线程,从而可以关闭掉读取线程
                        oos.flush();
                        System.out.printf("用户%d下线, ", listSockets.indexOf(s));
                        listSockets.remove(s);
                        System.out.printf("目前聊天室仍有%d人n", listSockets.size());
                    }
                }
                System.out.println("i" + i + "res = " + res);
                System.out.println("by.length: " + by.length);
                System.out.println("Socket[]: " + Arrays.toString(listSockets.toArray()));
                // 调用函数,将接受到的消息发送给所有客户端
                BroadCast(s, by, res);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (oos != null) {
                    oos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (ois != null) {
                    ois.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

在处理收发信的线程中,利用 BroadCast() 方法将服务器接收到的消息发送给除了发送方以外的其他客户端。

在 run() 方法中,创建字节数组来接收客户端发送的数据流。定义字节数组时, byte[] by = new byte[1024+2]; 这里+2的原因是,为了区分发送的用户以及传输的数据类型是消息文本还是文件。其中,第一位标志位用来表示用户的id,第二位标志位用1,2来表示发送的是消息还是文件,1表示发送的是消息,2表示发送的是文件。 下面客户端代码时可以更好理解。

判断用户下线的标志是用户发送 bye ,说明其下线,则服务端从listSockets里删除对应的socket。同时,将把 bye 发送给客户端的读取线程,提示其可以关闭掉读取线程。

以上就是服务端的实现逻辑。整体思路就是:

  1. 首先创建监听线程,接收每个客户端的连接请求,并创建一个List集合保存。
  2. 创建一个处理收发信的线程,即每个客户端发送的聊天内容,都先统一发回给服务器端,再由服务器端进行集中转发给每个客户端。

客户端的两个线程包括发送消息给服务器和读取服务器发送的消息,用主线程和子线程来分别实现。

客户端1

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package Client;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class MultiClient extends Thread {
    private Socket ss;

    public MultiClient() {
    }

    public MultiClient(Socket ss) {
        this.ss = ss;
    }

    public byte[] reviseArr(byte[] by, int res) {
        byte[] newByteArr = new byte[by.length + 2];
        // 将by字节数组的内容都往后移动两位,即头部的两个位置空出来作为标志位
        for (int i = 0; i < by.length; i++)
        {
            newByteArr[i+2] = by[i];
        }
        return newByteArr;
    }

    // 子线程执行读操作,读取服务端发回的数据
    @Override
    public void run() {
        BufferedInputStream bis = null;
        BufferedOutputStream bosFile = null;    // 与输出文件流相关联
        try {
            bis = new BufferedInputStream(ss.getInputStream());
            //bosFile = new BufferedOutputStream(new FileOutputStream("./directoryTest/src/用户1 IO流的框架图.png"));
            // 等待接收服务器发送回来的消息
            while(true) {
                byte[] by = new byte[1024+2];
                int res = bis.read(by);
                int sendUser = by[0];
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
                String format = sdf.format(date);
                if (by[1] == 1) // 说明传的是文件
                {
                    //String filePath = String.format("./directoryTest/src/用户%d传送来的IO流的框架图.png", sendUser);
                    bosFile = new BufferedOutputStream(new FileOutputStream("./directoryTest/用户" + sendUser + "-传输的文件.png", true));
                    bosFile.write(by, 2, res-2);
                    bosFile.flush();
                    if (res<1026)   // 说明是最后一次在传送文件,所以传送的字节数才会小于字节数组by的大小
                    {
                        System.out.println("用户" + sendUser + "t" + format + ":");
                        System.out.printf("用户%d发送的文件传输完成n", sendUser);
                    }
                }
                else    // 说明传输的是聊天内容,则按字符串的形式进行解析
                {
                    // 利用String构造方法的形式,将字节数组转化成字符串打印出来
                    String receive = new String(by, 2, res);
                    System.out.println("用户" + sendUser + "t" + format + ":");
                    System.out.println(receive);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        // 主线程执行写操作,发送消息到服务器
        Socket ss = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;     // 与文件关联的流
        MultiClient mcc = null;
        try {
            ss = new Socket("127.0.0.1", 9999);
            System.out.println("服务器连接成功");
            System.out.println("-----------聊天室-----------");
            bos = new BufferedOutputStream(ss.getOutputStream());
            Scanner sc = new Scanner(System.in);
            mcc = new MultiClient(ss);
            mcc.start();
            byte[] by = new byte[1024];
            int res = 0;
            int i = 0;
            while(true) {
                // 由用户输入选择执行不同的传输任务
                // 若用户输入传输文件,则传输指定文件,否则,则正常聊天任务
                String str = sc.nextLine();
                if (str.equals("传输文件")) {
                    bis = new BufferedInputStream(new FileInputStream("./directoryTest/壁纸1.png"));

                    while ((res = bis.read(by)) != -1) {
                        //System.out.println("i" + i + " res: " + res);
                        byte[] newByteArr = mcc.reviseArr(by, res);;
                        newByteArr[1] = 1;  // 表示第二个位置上的值为1时表示传输的是文件
                        bos.write(newByteArr, 0, res+2);
                        bos.flush();

                    }
                }
                else{
                    byte[] sb = str.getBytes(); // 转化为字节数组
                    byte[] newByteArr = mcc.reviseArr(sb, sb.length);
                    newByteArr[1] = 2;      // 表示第二个位置上的值为2时表示传输的是聊天内容
                    bos.write(newByteArr);  // 把内容发给服务器
                    bos.flush();
                    if (str.equalsIgnoreCase("bye"))
                    {
                        System.out.println("用户下线!");
                        break;
                    }
                }

            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mcc.stop();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

在客户端实现中,主线程执行写操作,发送消息到服务器,接收键盘的标准输入。在主线程发送消息时,判断用户的输入,如果输入的文本内容是传输文件,则会去读取指定路径下的文件,并利用 BufferedOutputStream 方法将文件转化为字节缓冲输出流发送。

这里 reviseArr 方法,是将读入文件输入流的102大小的字节数组往后移动两位,实现前两位作为标志位,区分用户id和传输数据类型的目的。如果传输的是文件,会在第二个标志位赋1,如果传输的是消息文本,则第二个标志位赋2。

若用户发送的消息是”bye”,则表示用户下线,利用 break 跳出主线程循环,并在 finally 中调用 mcc.stop() 关闭子线程,从而关闭该客户端。

在子线程中,若用户发送的是文件,则利用字节缓冲输入流 BufferedInputStream 将文件写入到指定路径中,并在文件名中简易标识发送用户。若接收的字节数组长度小于设定的1026,说明是最后一次在传送文件,在将最后一次文件的输入流写入后,在控制台打印文件传输完成的提示信息。

以上是客户端1的实现代码,其它客户端的实现代码类似

客户端2

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package Client;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class MultiClient2 extends Thread {
    private Socket ss;

    public MultiClient2() {
    }

    public MultiClient2(Socket ss) {
        this.ss = ss;
    }

    public byte[] reviseArr(byte[] by, int res) {
        byte[] newByteArr = new byte[by.length + 2];
        // 将by字节数组的内容都往后移动两位,即头部的两个位置空出来作为标志位
        for (int i = 0; i < by.length; i++)
        {
            newByteArr[i+2] = by[i];
        }
        return newByteArr;
    }

    @Override
    public void run() {
        BufferedInputStream bis = null;
        BufferedOutputStream bosFile = null;    // 与输出文件流相关联
        try {
            bis = new BufferedInputStream(ss.getInputStream());

            // 等待接收服务器发送回来的消息

            while(true) {
                byte[] by = new byte[1024+2];
                int res = bis.read(by);
                int sendUser = by[0];
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
                String format = sdf.format(date);
                if (by[1] == 1) // 说明传的是文件
                {
                    //String filePath = String.format("./directoryTest/src/用户%d传送来的IO流的框架图.png", sendUser);
                    bosFile = new BufferedOutputStream(new FileOutputStream("./directoryTest/用户" + sendUser + "-传输的文件.png", true));
                    bosFile.write(by, 2, res-2);
                    bosFile.flush();
                    if (res<1026)   // 说明是最后一次在传送文件,所以传送的字节数才会小于字节数组by的大小
                    {
                        System.out.println("用户" + sendUser + "t" + format + ":");
                        System.out.printf("用户%d发送的文件传输完成n", sendUser);
                    }
                }
                else    // 说明传输的是聊天内容,则按字符串的形式进行解析
                {
                    // 利用String构造方法的形式,将字节数组转化成字符串打印出来
                    String receive = new String(by,2, res);
                    System.out.println("用户" + sendUser + "t" + format + ":");
                    System.out.println(receive);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        // 主线程写操作

        Socket ss = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;     // 与文件关联的流
        MultiClient2 mcc = null;
        try {
            ss = new Socket("127.0.0.1", 9999);
            System.out.println("服务器连接成功");
            System.out.println("-----------聊天室-----------");
            bos = new BufferedOutputStream(ss.getOutputStream());
            Scanner sc = new Scanner(System.in);
            mcc = new MultiClient2(ss);
            mcc.start();
            byte[] by = new byte[1024];
            int res = 0;
            int i = 0;
            while(true) {
                String str = sc.nextLine();
                if (str.equals("传输文件")) {
                    bis = new BufferedInputStream(new FileInputStream("./directoryTest/壁纸1.png"));
                    while ((res = bis.read(by)) != -1) {
                        i += 1;
                        //System.out.println("i" + i + " res: " + res);
                        byte[] newByteArr = mcc.reviseArr(by, res);;
                        newByteArr[1] = 1;  // 表示第二个位置上的值为1时表示传输的是文件
                        bos.write(newByteArr, 0, res+2);
                        bos.flush();

                    }
                }
                else{
                    byte[] sb = str.getBytes(); // 转化为字节数组
                    byte[] newByteArr = mcc.reviseArr(sb, sb.length);
                    //System.out.println("newByteArr: " + Arrays.toString(newByteArr));
                    newByteArr[1] = 2;      // 表示第二个位置上的值为2时表示传输的是聊天内容
                    bos.write(newByteArr);  // 把内容发给服务器
                    bos.flush();
                    if (str.equalsIgnoreCase("bye"))
                    {
                        System.out.println("用户下线!");
                        break;
                    }
                }

            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mcc.stop();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端3

<pre class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package Client;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class MultiClient3 extends Thread {
    private Socket ss;

    public MultiClient3() {
    }

    public MultiClient3(Socket ss) {
        this.ss = ss;
    }

    public byte[] reviseArr(byte[] by, int res) {
        byte[] newByteArr = new byte[by.length + 2];
        // 将by字节数组的内容都往后移动两位,即头部的两个位置空出来作为标志位
        for (int i = 0; i < by.length; i++)
        {
            newByteArr[i+2] = by[i];
        }
        return newByteArr;
    }

    @Override
    public void run() {
        BufferedInputStream bis = null;
        BufferedOutputStream bosFile = null;    // 与输出文件流相关联
        try {
            bis = new BufferedInputStream(ss.getInputStream());
            // 等待接收服务器发送回来的消息
            while(true) {
                byte[] by = new byte[1024+2];
                int res = bis.read(by);
                int sendUser = by[0];
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
                String format = sdf.format(date);
                if (by[1] == 1) // 说明传的是文件
                {
                    bosFile = new BufferedOutputStream(new FileOutputStream("./directoryTest/用户" + sendUser + "-传输的文件.png", true));
                    bosFile.write(by, 2, res-2);
                    bosFile.flush();
                    if (res<1026)   // 说明是最后一次在传送文件,所以传送的字节数才会小于字节数组by的大小
                    {
                        //System.out.println("客户端接收到的信息" + receive);
                        System.out.println("用户" + sendUser + "t" + format + ":");
                        System.out.printf("用户%d发送的文件传输完成n", sendUser);
                    }
                }
                else    // 说明传输的是聊天内容,则按字符串的形式进行解析
                {
                    // 利用String构造方法的形式,将字节数组转化成字符串打印出来
                    String receive = new String(by, 2, res);
                    System.out.println("用户" + sendUser + "t" + format + ":");
                    System.out.println(receive);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        // 主线程写操作
        //MultiClient mc = new MultiClient();
        Socket ss = null;
        BufferedOutputStream bos = null;
        BufferedInputStream bis = null;     // 与文件关联的流
        MultiClient3 mcc = null;
        try {
            ss = new Socket("127.0.0.1", 9999);
            System.out.println("服务器连接成功");
            System.out.println("-----------聊天室-----------");
            bos = new BufferedOutputStream(ss.getOutputStream());
            Scanner sc = new Scanner(System.in);
            mcc = new MultiClient3(ss);
            mcc.start();
            byte[] by = new byte[1024];
            int res = 0;
            int i = 0;
            while(true) {
                String str = sc.nextLine();
                if (str.equals("传输文件")) {
                    bis = new BufferedInputStream(new FileInputStream("./directoryTest/壁纸1.png"));
                    while ((res = bis.read(by)) != -1) {
                        byte[] newByteArr = mcc.reviseArr(by, res);;
                        newByteArr[1] = 1;  // 表示第二个位置上的值为1时表示传输的是文件
                        bos.write(newByteArr, 0, res+2);
                        bos.flush();

                    }
                }
                else{
                    byte[] sb = str.getBytes(); // 转化为字节数组
                    byte[] newByteArr = mcc.reviseArr(sb, sb.length);
                    newByteArr[1] = 2;      // 表示第二个位置上的值为2时表示传输的是聊天内容
                    bos.write(newByteArr);  // 把内容发给服务器
                    bos.flush();
                    // 如果用户输入bye则表示用户下线
                    if (str.equalsIgnoreCase("bye"))
                    {
                        System.out.println("用户下线!");
                        break;
                    }
                }

            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                mcc.stop();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

功能展示

开启服务器和3个客户端,初始状态

聊天室

每有一个客户端连接,会打印相应的提示信息

Java Socket实现多人聊天室

三个客户端连接成功,打印提示信息

Java Socket实现多人聊天室

接下来,进行聊天功能的展示

Java Socket实现多人聊天室
Java Socket实现多人聊天室
Java Socket实现多人聊天室

可以看到,聊天室里标识出每个用户以及发送的时间和消息,可以实现基本的聊天功能。

传输文件

在客户端1输入传输文件

Java Socket实现多人聊天室
Java Socket实现多人聊天室
Java Socket实现多人聊天室

进入到写入的目录下,存在相应的文件:

Java Socket实现多人聊天室

即实现了聊天室和传输文件的功能,最后客户端1发送 bye ,该客户端断开连接

Java Socket实现多人聊天室
<pre class="hljs" style="padding: 0.5em; font-family: Menlo, Monaco,

作者:Java熬夜党

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

发表回复

登录后才能评论