我正在做一个小的客户端/服务器应用程序。目前它运行良好,但我需要添加一个“选项”。
服务器类如下所示:
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)发送内容。
我的问题是:既然所有的客户端都在不同的线程中通过这个Client2连接到服务器,那么Client1如何找到/拥有/检索clientSocket的套接字呢?
我读过this,它建议创建一个包含每个连接客户端的outputStream的dataoutputstream列表。这似乎是个好主意,但我更喜欢对套接字做同样的事情(因为我不确定现在是需要"data“输出流还是另一个输出流,而且在任何情况下,使用套接字都会更清楚)。
另外,Client2在服务器上做他自己的事情,包括交换数据,所以他将使用他的输出/输入流。我得确保这不会搞混。
例如,假设Client2向服务器发送一些内容并等待响应。然后,Client1向Client2发送一些内容;Client2接收Client1发送内容,而不是服务器响应;因为他不应该接收该内容,这导致了致命错误。
我读过一些关于同步线程的文章,它似乎就是我所需要的,但是我是java的新手,这有点难吗?
我认为如果我声明client2套接字为同步的,那么线程将等到clientSocket空闲时才使用它;而且由于客户机不应该断开连接(如果他断开,套接字就关闭了,所以我们不能向他发送任何东西),(client1的)线程将不能使用Client2的套接字。
现在,如果我同步DataOutputStream,有时client2和服务器之间的通信涉及许多不同的输出流,因此DataOutputStream可以自由使用,但Client2仍将等待来自服务器的输入,而不是来自Client1的输入,因此不是相同的输入。
也许我可以直接同步完整的OutputStream。或者我说的话根本没有任何意义。帮助?
发布于 2018-08-07 17:34:54
好吧,既然我把它贴出来了,我想我也能说出来。
所以,这不是一个完美的解决方案(在我看来),我还没有完全结束它,但到目前为止它似乎是有效的。
对于第一个问题(如何检索另一个客户端套接字),我在服务器端创建了一个静态哈希表,客户端名称作为键,套接字作为值。每当客户端连接时,他会被添加到这个表中;当他断开连接时,他会被删除(我没有尝试断开连接部分)
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.现在,在客户端,我必须一直监听来自此套接字的任何输入(以防另一个客户端希望通过服务器与我通信),但不能在我与服务器进行操作时进行监听。
为此,我在客户端创建了另一个线程。当客户端连接时,它会启动创建第二个套接字的线程,并等待来自服务器的输入。但是,当客户端启动任何涉及与服务器通信的函数时,此线程会暂停,然后在函数结束时取消暂停。以下是线程类:
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“消息,当我取消暂停时,我也没有收到另一个”等待TCHAT请求“的消息,但它似乎是有效的(因为如果没有pause,其他客户端函数将无法工作,并且在这里它们工作得很好,客户端即使在上传或其他东西之后也能正确地接收到来自服务器的消息。)
基本上,当我想使用客户端函数时,我只是这样做:
TCHAT.pause();
upload(file); //or any function involving client/server communication
TCHAT.unpause();希望它能帮助某些人,但仍然很高兴让它工作:)
https://stackoverflow.com/questions/51650024
复制相似问题