当前位置: 首页 > 知识库问答 >
问题:

Java客户机-服务器-具有同步线程的客户机

靳举
2023-03-14

我在做一个客户端/服务器应用程序。目前它的功能很好,但我需要添加一个“选项”。

server类如下所示:

public class Server {

    public static void main(String[] zero) throws IOException {

        ServerSocket serverSocket  ;
        Socket clientSocket ;

        DataBase DB = new DataBase();
        System.out.println("ouverture du server");
        serverSocket = new ServerSocket(2000);

        DB.printAll(); //just to see the DB.


        while(true) { 
            try {

                clientSocket = serverSocket.accept(); 
                Thread t = new Thread(new Connect(clientSocket, DB));
                t.start();

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

因此许多客户端都能够连接到服务器。我的观点是:我希望一个连接的客户机(比如说,Client1)能够向他选择的另一个连接的客户机(Client2)发送一些东西。

我的问题是:Client1如何找到/拥有/检索Client2的套接字,因为所有的Client1都通过这个clientSocket在不同的线程中连接到服务器?

我读过这篇文章,其中建议创建一个包含每个连接客户端的outputStream的dataoutputstream列表。这似乎是一个好主意,但我更希望对套接字也这样做(因为我现在不确定是需要“数据”输出流还是其他输出流,无论如何,对我来说,使用套接字会更清楚)。

另外,Client2在服务器上做他自己的事情,其中包括exchange数据,所以他将使用他的输出/输入流。我得确保这件事不会搞混。

例如,假设Client2向服务器发送一些东西并等待响应。然后Client1向Client2发送一些东西;Client2接收Client1发送的内容,而不是服务器响应;由于他不应该接收到,这导致了致命错误。

我读过一些关于同步线程的文章,这似乎是我所需要的,但我对Java是个新手,这有点困难?

我认为如果我将Client2套接字声明为synchronized,那么线程将等到clientSocket空闲后再使用它;由于客户机不应该断开连接(如果他断开了,那么套接字就关闭了,所以我们不能给他发送任何东西),所以(client1的)线程将不能使用Client2的套接字。

现在,如果我同步DataOutputStream,有时client2和server之间的通信涉及到许多不同的outputstream,因此DataOutputStream可以自由使用,但client2仍将等待来自服务器的输入,而不是来自Client1,因此不是相同的输入。

也许我可以直接同步完整的OutputStream。或者我说的一点道理都没有。救命?

共有1个答案

钮巴英
2023-03-14

好吧,既然我把它贴出来了,我想我也可以把它贴出来了。

所以,这不是一个完美的解决方案(在我看来),我还没有完全完成它,但它似乎工作到目前为止。

对于第一个问题(如何检索另一个客户机套接字),我在服务器端创建了一个静态哈希表,以客户机名作为键,套接字作为值。每当客户端连接时,就会将其添加到此表中;当他断开连接时,他被删除了(我没有尝试断开连接部分)

private static Hashtable<String,Socket> connectedClients= new Hashtable<String, Socket>();
public static void setConnectedClient(String username, Socket clientSocket) {
    connectedClients.put(username, clientSocket);
}

public static void disconnectClient(String user) {
    connectedClients.remove(user);
}

所以无论我在服务器端的程序中,我都可以检索一个客户端套接字(知道他的用户名)。

对于第二个问题(如何避免与其他客户机和服务器的工作混淆),我创建了第二个套接字。这意味着,在客户端有两个套接字:一个用于与服务器通信,另一个用于与另一个端口上的客户端(来自服务器)通信。这意味着我在服务器端也有另一个服务器套接字用于另一个端口。因此,当客户端连接到服务器时,第二个套接字将在客户端和服务器端创建。

        Socket TCHATSocket = Server.getServerSocket().accept(); //create a new socket specifically for TCHAT
        Server.setConnectedClient(user, TCHATSocket); //register the client ID & TchatSocket in the list of connected clients.

现在,在客户端,我必须监听来自这个套接字的任何输入(以防另一个客户端希望通过服务器与我通信),但当我在服务器上做事情时就不是这样了。

为此,我在客户端创建了另一个线程。当客户端连接时,它启动线程,创建第二个套接字并等待来自服务器的输入。但是,当客户端启动任何涉及到与服务器通信的函数时,该线程会暂停,然后在函数结束时取消暂停。下面是thread类:

package client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class TCHAT extends Thread{
    private InputStream in;
    private OutputStream out;
    private Socket pakeSocket;
    private String message;
    private volatile boolean pause = false;

    public void pause() {
        pause = true;
    }

    public void unPause() {
        pause = false;
        synchronized(this) {
            notify();
        }

    }

    public TCHAT() {
        try {
            tchatSocket = new Socket(InetAddress.getLocalHost(),2004);
            in = tchatSocket.getInputStream();
            out = tchatSocket.getOutputStream();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void run(){
        while(!tchatSocket.isClosed()) {

            if(pause) {
                System.out.println("TCHAT paused");
                synchronized (this) {
                    try {
                        wait();// wait until someone calls notify() (by calling the method unPause)
                    }catch (InterruptedException e) {           
                        e.printStackTrace();            
                    }
                }
            }

            else {
                System.out.println("Waiting for TCHAT demand");
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(in));
                    message = br.readLine();
                    System.out.println(message);
                    //Find a way to blok the while after receiving the message:
                    tchatSocket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }


        }
    }

}

正如您所看到的,它并没有真正终止:现在我只是从服务器获得一个消息,然后关闭套接字;但我猜在关闭它之前你可以做任何你想做的事。另外,由于某些原因,当我调用pause()时,我从来没有得到“TCHAT paused”消息,当我取消暂停时,我也没有得到另一个“waiting for TCHAT demand”消息,但它似乎可以工作(因为没有暂停,其他客户端函数将无法工作,而在这里它们工作得很好,客户端甚至在上传或其他消息之后也能正确地接收到来自服务器的消息。)

基本上,当我想使用客户端函数时,我只需要:

TCHAT.pause();
upload(file); //or any function involving client/server communication
TCHAT.unpause();

希望它能帮助某人,但还是很乐意让它工作:)

 类似资料:
  • 我想在一些计算机之间建立点对点连接,这样用户就可以在没有外部服务器的情况下聊天和交换文件。我最初的想法如下: 我在服务器上制作了一个中央服务器插座,所有应用程序都可以连接到该插座。此ServerSocket跟踪已连接的套接字(客户端),并将新连接的客户端的IP和端口提供给所有其他客户端。每个客户端都会创建一个新的ServerSocket,所有客户端都可以连接到它。 换句话说:每个客户端都有一个Se

  • 我是编码和Java的新手,我已经创建了一个简单的客户端-服务器程序,客户端可以请求一个文件。它的内容将显示在浏览器页面中,还有一些细节,如数据类型和长度。我现在有一个问题,我不确定如何在浏览器中显示正确连接的服务器响应,如“HTTP/1.1 200 OK”和关闭的连接,如“Connection: close”。我有一个处理响应的方法,如下所示: 对我如何做到这一点有什么建议吗?非常感谢。

  • 我写了一个小的测试程序来创建 自定义自签名CA证书#1 创建由该CA根证书#1颁发的服务器证书#2 创建具有证书#2的服务器 创建一个RootCA指向证书1的客户端 客户端尝试连接到服务器,但出现错误: 得到“https://localhost:2000:x509:由未知颁发机构签署的证书(可能是因为尝试验证候选颁发机构证书“测试ca”时“x509:Ed25519验证失败”) 我知道这方面的例子有

  • 问题内容: 我正在寻找一些通用策略,用于将中央服务器上的数据与并不总是在线的客户端应用程序进行同步。 在我的特定情况下,我有一个带sqlite数据库的android手机应用程序和一个带MySQL数据库的PHP Web应用程序。 用户将能够在电话应用程序和Web应用程序上添加和编辑信息。我需要确保即使手机无法立即与服务器通信,在一个地方所做的更改也会在所有地方反映出来。 我不关心如何将数据从手机传输

  • 我在Java开发了一个客户端-服务器游戏(称为“Set”)。 在调试过程中遇到了一个非常尴尬的问题: 如果在同一台机器上同时运行客户端和服务器(客户端连接到localhost),这个游戏工作得很棒(如果我运行服务器和大量客户端的话也是如此)。 但是,如果我在两台不同的机器上运行客户端和服务器,那么客户端和服务器都挂起了Inputstream readLine方法。 我会提到我正在使用writeBy

  • 问题内容: 我正在尝试使用我一直在努力的客户端/服务器程序实现多线程。我需要允许多个客户端同时连接到服务器。我目前有4类:客户端,服务器,协议和用于处理线程的工作器。以下代码是我对这些类的拥有的代码: SocketServer类: SocketClient类别: 协议类别: ClientWorker类: 当我运行服务器和客户端时,一切正常。然后,当我尝试运行另一个客户端时,它只是挂在那儿,没有提示