簡體   English   中英

Java 多客戶端聊天服務器私信選項

[英]Java multi-client chat server private message options

我是 stackoverflow 的新手,如果之前有人問過這種問題,我很抱歉,但我快速搜索了一下,但找不到像我這樣的標題。 我正在開發 Java 上的多客戶端聊天應用程序。 我按照教程進行操作,我可以發送應用程序中的每個用戶都可以看到的消息。 但我想知道如何創建私人消息並將其發送給特定用戶到聊天中。

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

public class ChatServer {
    private int port;

    private Set<String> userNames = new HashSet<>();
    private Set<UserThread> userThreads = new HashSet<>();

    public ChatServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        new ChatServer(9999).execute();
    }

    private void execute() {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("Server is running");
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("New user connected");
                UserThread newUser = new UserThread(socket, this);
                userThreads.add(newUser);
                newUser.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void addUserName(String s) {
        this.userNames.add(s);
    }

    public void broadcast(String serverMessage, UserThread excludeUser) {
        for (UserThread aUser : userThreads) {
            if (aUser != excludeUser)
                aUser.sendMessage(serverMessage);
        }
    }
}

上面的代碼是我的服務器代碼。

public void run() {
    Console console = System.console();
    String userName = console.readLine("Enter your username : ");
    writer.println(userName);
    String text;
    do {
        text = console.readLine("[" + userName + "]: ");
        if (text.startsWith("[")) {
            isTargeted = true;
            this.aimUserName = text.substring(text.indexOf("[") + 1, text.indexOf("]"));
            //System.out.println("Private Message to: " + aimUserName);
        } else {
            isTargeted = false;
        }
        writer.println(text);
    } while (!text.equals("bye"));

    try {
        socket.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

上面的代碼是我寫線程 class 的一部分。 如您所見,如果消息以 '[name]' 部分開頭,則“name”表示我們要發送私人消息的用戶。 通過這樣做,我可以獲得我想要發送私人消息的用戶的名稱,但我無法弄清楚如何將此消息廣播給那個特定的用戶。 我相信我需要在 ChatServer class 中配置我的廣播 function 但我真的不知道該怎么做。 我應該遵循哪些步驟?

- 編輯 -

我一直在研究我的問題,並做了一些補充來解決我的問題。 首先,我想我應該和你分享我所擁有的一切。 我之前分享了我的 ChatServer class。 我的其他課程是:

import java.io.IOException;
import java.net.Socket;

public class ChatClient {

    public static void main(String[] args) {
        new ChatClient().execute();
    }

    private void execute() {
        try {
            Socket socket = new Socket("localhost", 3);
            System.out.println("Connected to chat server");
            new ReadThread(socket, this).start();
            new WriteThread(socket, this).start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

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

public class ReadThread extends Thread{
    private BufferedReader reader;
    private Socket socket;
    private ChatClient client;
    public ReadThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;

        InputStream input;
        try {
            input = this.socket.getInputStream();
            this.reader = new BufferedReader(new InputStreamReader(input));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public void run() {
        while(true) {
            try {
                String response = this.reader.readLine();
                System.out.println("\n" + response);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                break;
            }
        }
    }
}

import java.net.Socket;
import java.io.*;
public class UserThread extends Thread {

    private Socket socket;
    private ChatServer server;
    PrintWriter writer = null;
    public String userName;
    public UserThread(Socket socket, ChatServer chatServer) {
        this.socket = socket;
        this.server = chatServer;
    }


    public void run() {
        try {
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            OutputStream output = socket.getOutputStream();
            writer = new PrintWriter(output,true);

            String userName = reader.readLine();
            this.userName = userName;
            server.addUserName(userName);
            String serverMessage = "New user connected: " + userName;
            server.broadcast(serverMessage,this);



            String clientMessage;
            do {
                clientMessage = reader.readLine();
                serverMessage = "[" + userName + "] : " + clientMessage;
                server.broadcast(serverMessage, this);      

            }while(!clientMessage.equals("bye"));



        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


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


}

import java.net.*;
import java.io.*;
public class WriteThread extends Thread {
    private Socket socket;
    private ChatClient client;
    private PrintWriter writer;
    public WriteThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;
        OutputStream output;
        try {
            output = socket.getOutputStream();
            this.writer = new PrintWriter(output, true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public void run() {
        Console console = System.console();
        String userName = console.readLine("Enter your username : ");
        writer.println(userName);
        String text;
        do {
            text = console.readLine("[" + userName + "]: ");
            if(text.startsWith("[")){
                String aimUserName = text.substring(text.indexOf("[")+1,text.indexOf("]"));
                System.out.println("Private Message to: " + aimUserName);}
            writer.println(text);
        }while(!text.equals("bye"));

        /*do {
            text = console.readLine("[" + userName + "]: ");
            writer.println(text);
        }while(!text.equals("bye"));*/

        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}

這些代碼可以正常工作,我可以非常干凈地進行多方聊天。 但是在處理私人聊天內容時,我在 ChatServer 中添加了以下行:

public void privatebr(String serverMessage, String targetUserName){
        for(UserThread aUser: userThreads){
            if(aUser.userName == targetUserName)
                aUser.sendMessage(serverMessage);
        }

到 UserThread,我將部分編輯為:

String clientMessage;
            do {
                clientMessage = reader.readLine();
                serverMessage = "[" + userName + "] : " + clientMessage;
                if(clientMessage.startsWith("[")){
                    String targetUserName = clientMessage.substring(clientMessage.indexOf("[")+1,clientMessage.indexOf("]"));
                    serverMessage = "[" + userName + "] : " + clientMessage;
                    server.privatebr(serverMessage, targetUserName);
                }else{

                    server.broadcast(serverMessage, this);
                }


            }while(!clientMessage.equals("bye"));

但是當我進行所有這些編輯時,正常的多聊天進度就被破壞了,我的錯在哪里? 為什么一切都壞了?

好問題! 要回答您提出的問題,您應該維護用戶的Map到他們的 Socket 連接,這樣對於 DM,您只需 select 用戶想要發送消息。 您還需要一個消息傳遞協議(見下文)

...但我必須告訴你,在當今時代使用 Sockets 和 SocketServer 類就像重新發明輪子一樣。 開始做聊天服務器的地方是使用 web sockets 協議。 即使在這種情況下,您也可能想要定義一個消息協議(就像我所做的那樣 - 我使用 JSON 和消息類型創建了一個消息協議,其中 websocket 事件 onMessage 中的字符串消息首先被解析為一個對象)

在所有平台上都有支持WS的實現:java、.net、python、ZE1BFD760B621E409CEEZAC等應該是你的起點。

- - 更新 - -

我明白你來自哪里。 為了幫助您了解 Sockets / ServerSockets,這里有一些指針和資源

  1. DatagramSockets(又名 UDP):這是一種不同於常規 TCP 的傳輸協議,由 Shockwave 和 Flash 使用,這是 Flash 出現問題的根本原因。 我強烈建議不要這樣做
  2. 數據和 Object 輸入/輸出流:“數據”流僅限 Java(無法連接到其他平台上構建的技術)。 Object 流是相似的,除了您通過 stream 傳輸實際的整個對象(還有 Java 僅)沒有一個*(幾乎沒有一個)使用這些。
  3. SocketException: 使用 java.net.[Server]Socket(s),你很可能會遇到這個異常。 當您在套接字上等待更多數據(通過 read / readLine 調用)並且套接字關閉時,就會發生這種情況。 我花了很長時間才弄清楚這一點,但這個例外是你的朋友。 當連接關閉時(在客戶端或服務器端),您會得到它,它允許在套接字上等待的線程喚醒。 並且允許你做任何你需要做的清理工作,SocketException 是 IOException 的一個子類。 所以你甚至可能沒有意識到這是什么。 但現在至少我已經警告過你
  4. 流與寫入器和讀取器:寫入器和讀取器用於將原始字節解釋為 Java 字符和字符串。 這是必要的,因為有多種文本格式(即 ascii、windows-xx、utf-8、utf-16)。 Readers and Writers 幫助您以不同的文本格式讀取和寫入文本(以及從圖像格式解釋圖像)。
  5. 緩沖寫入器和流:這些用於低效率的讀取和寫入。 對於寫作,這意味着讓您可以編寫部分消息,並且在您准備好之前不要發送它。 對於閱讀,這意味着例如逐行閱讀流,而不是在一個 go 上閱讀所有內容。
  6. TUS:tjacobs/io - https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/io/這是我多年前放在 SourceForge 上的 Java 庫的舊集合,但這里有很多類與處理 Sockets 有關。 特別是,請參閱 SocketServerEx、DataFetcher、Main/App、Timeout 和 IOUtils。 最重要的是,真正看看 DataFetcher,它是一個用於回調 I/O 監聽的輕量級線程框架。

祝好運並玩得開心點!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM