欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于socket的多客户端之间互相通信

程序员文章站 2024-03-22 23:22:46
...
  1. 服务端循环监听客户端,为每一个连接的客户端创建一个子线程,并将线程添加到一个集合列表中;
  2. 子线程中将消息以json的格式进行封装并添加到一个集合列表中;
  3. 创建一个线程用于消息的解析与转发;
  4. 客户端新建Socket并指定服务端ip和端口号进行连接;
  5. 客户端发送的消息开头加上消息到达方的id,用斜杠或其他特殊符号区分开;
public class ServerHost {
    // 消息列表
    static List mMsgList = new ArrayList();
    // 线程列表
    static List mThreadList = new ArrayList();

    public static void main(String[] args) throws IOException {
        int mSocketId = 0;
        ServerSocket serverSocket = new ServerSocket(12345);
        Socket socket = null;
     
        //创建一个线程用于解析并转发消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    if (mMsgList.size() > 0) {
                        // 获取列表中第一个json消息
                        JSONObject msgJson2 = (JSONObject)mMsgList.get(0);
                        for (int i = 0; i < mThreadList.size(); i++) {
                            ServerThread serverThread = (ServerThread)mThreadList.get(i);
                            if (serverThread.mSocketId == msgJson2.getInt("to")) {
                                try {
                                    DataOutputStream dos = new DataOutputStream(serverThread.socket.getOutputStream());
                                    dos.writeUTF(msgJson2.get("msg").toString());
                                    dos.flush();
                                    break;
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        // 移除第一个json消息
                        mMsgList.remove(0);
                    }
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        //服务端在while里不断监听是否有新的客户端接入,如果有则为该新的客户端创建一个新的线程,在里面封装消息
        while(true) {
            try {
                socket = serverSocket.accept();
               // 封装消息线程
                ServerThread serverThread =  new ServerThread(socket, mSocketId, mMsgList);
                serverThread.start();
                // 将为每一个客户端新建的子线程添加到集合中
                mThreadList.add(serverThread);
                // mSocketId当作该客户端的id
                mSocketId++;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

为每一个连接的客户端新建的子线程,进行消息的封装: 

class ServerThread extends Thread {
    Socket socket = null;
    int mSocketId = 0;
    static List mMsgList = null;
    DataInputStream dis = null;
    DataOutputStream dos = null;
    public ServerThread(Socket socket, int mSocketId, List mMsgList) {
        super();
        this.socket = socket;
        this.mSocketId = mSocketId;
        this.mMsgList = mMsgList;
    }
    public void run() {
        try {
            //获取socket的输入输出流
            dis = new DataInputStream(socket.getInputStream());
            dos = new DataOutputStream(socket.getOutputStream());
            while (true) {
                String msgRecv = dis.readUTF();
                //json封装消息
                JSONObject msgJson = new JSONObject();
                msgJson.put("from", mSocketId);
                msgJson.put("to", Integer.parseInt(msgRecv.split("/")[0]));
                msgJson.put("msg", msgRecv.split("/")[1]);
                // 将json消息添加到集合中
                mMsgList.add(msgJson);
            }
        } catch (IOException | JSONException e) {
            e.printStackTrace();
        }
    }
}

实现过程

          在服务器中为每一个连接到服务器的客户端开启一个子线程,并在这个子线程中循环监听这个客户端是否发过来消息,在上面可以看到服务端接收到消息后,将这条消息封装到msgJson并添加到了集合mMsgList中。到这里服务器就可以收到客户端发过来的消息了,服务器收到消息后要做的工作就是将这条消息发送给客户端,(从实现原理图中可以看出服务器起到一个中转的作用)

        那么怎样实现这个功能呢?它的实现也不难,从上面的描述我们可以知道只要客户端向服务器发送一条消息,我们就会将这条消息放到一个集合mMsgList,也就是说只要服务器收到消息mMsgList这个集合就不为空,只要mMsgList这个集合不为空就说明服务器还拥有未转发的消息,需要转发。

        怎么实现转发呢? 首先这里有两个集合一个是json消息的集合mMsgList 另一个是为每一个客户端Socket开启的一个子线程SocketThread的集合mThreadList。这两个集合的关系是每一msgJson肯定是mThreadList中的一个SocketThread(客户端)发送的。当SocketThread的idmsgJson的to(即消息的到达方)相等时,因为每一个客户端(假设是clientSocket1)连接到服务器时都要开启一个SocketThread子线程,在这个子线程中有clientSocket1的引用,所以当相等时就说明这个Message是发送给这个clientSocket1的。然后通过这个clientSocket1DataOutputStream这个消息发送给这个客户端。