Сокеты Java: несколько потоков клиентов на одном и том же порту на одном компьютере?
Я новичок в программировании Socket на Java и пытался понять, не подходит ли этот код ниже. Мой вопрос:
Могу ли я иметь несколько клиентов в каждом потоке, пытающихся подключиться к экземпляру сервера в той же программе, и ожидать, что сервер будет читать и записывать данные с изоляцией между клиентами?
public class Client extends Thread
{
...
void run()
{
Socket socket = new Socket("localhost", 1234);
doIO(socket);
}
}
public class Server extends Thread
{
...
void run()
{
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
Теперь можно ли несколько экземпляров клиента на разных потоках пытаться подключиться к одному и тому же порту текущего компьютера?
Например,
Server s = new Server("localhost", 1234);
s.start();
Client[] c = new Client[10];
for (int i = 0; i < c.length; ++i)
{
c.start();
}
Ответы
Ответ 1
Да, однако только один клиент сможет подключиться к исполнению потока, как написано.
Вы можете просто запустить ваш сервер run() внутри цикла while, чтобы позволить нескольким клиентам подключаться.
В зависимости от исполнителя они будут выполняться последовательно или параллельно.
public class Server extends Thread
{
...
void run()
{
while(true){
// serverSocket on "localhost", 1234
Socket clientSock = serverSocket.accept();
executor.execute(new ClientWorker(clientSock));
}
}
}
Ответ 2
Пока у вас есть только один объект, пытающийся связать порт для прослушивания, тогда нет проблем с подключением нескольких клиентов.
Ответ 3
В этом примере ваш Server
принимает и обрабатывает одно клиентское соединение за раз. У вас может быть столько Client
, сколько вы хотите подключиться, но будет обработано только по одному.
Неясно, является ли ваша логика исполнителя многопоточной, поскольку вы не обеспечивали ее реализацию. Если исполнитель делегирует threadpool или что-то подобное, вам нужно убедиться, что ваш ClientWorker
является потокобезопасным, так как вы будете иметь несколько экземпляров, выполняемых параллельно.
Я, конечно, предполагаю, что ваш Client
тоже потокобезопасен, так как ваш вопрос касается только Server
.
Ответ 4
Да, неважно, являются ли ваши клиенты локальными или удаленными. В вашем примере важно то, что ClientWorker является потокобезопасным, так как ваш сервер будет иметь несколько экземпляров этого класса (по одному для каждого клиентского соединения).
Ответ 5
Итак. Для начала:
Вы можете принимать больше клиентов с одним сервером, потому что вы принимаете только один из методов run
. Вы должны просто позвонить accept()
второй раз.
Затем вы в своем цикле for: сначала вы должны создавать каждый раз новый объект Client
. Затем вы можете вызвать c[i].start();
, а не c.start()
.
Теперь у меня есть несколько клиентов экземпляры разных потоков для подключения к одному и тому же порту текущая машина?
Да, вы можете. Просто создайте новые темы и запустите их. Это должно работать отлично.
ожидать, что сервер будет читать и писать данные с изоляцией между клиентами
Вы можете использовать свой опыт основных методов ввода-вывода, таких как file-io:
OutputStream os = socket.getOutputStream();
PrintStream pw = new PrintStream(os, true); // Or PrintWriter, I don't know what the best one is.
pw.println("Hello, other side of the connection!");
А для чтения используйте BufferedReader.
Ответ 6
Вы можете попробовать что-то в этих строках
public class MultiThreadServer extends Application {
// Text area for displaying contents
private TextArea ta = new TextArea();
// Number a client
private int clientNo = 0;
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a scene and place it in the stage
Scene scene = new Scene(new ScrollPane(ta), 450, 200);
primaryStage.setTitle("MultiThreadServer"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
new Thread( () -> {
try {
// Create a server socket
ServerSocket serverSocket = new ServerSocket(8000);
ta.appendText("MultiThreadServer started at "
+ new Date() + '\n');
while (true) {
// Listen for a new connection request
Socket socket = serverSocket.accept();
// Increment clientNo
clientNo++;
Platform.runLater( () -> {
// Display the client number
ta.appendText("Starting thread for client " + clientNo +
" at " + new Date() + '\n');
// Find the client host name, and IP address
InetAddress inetAddress = socket.getInetAddress();
ta.appendText("Client " + clientNo + " host name is "
+ inetAddress.getHostName() + "\n");
ta.appendText("Client " + clientNo + " IP Address is "
+ inetAddress.getHostAddress() + "\n");
});
// Create and start a new thread for the connection
new Thread(new HandleAClient(socket)).start();
}
}
catch(IOException ex) {
System.err.println(ex);
}
}).start();
}
// Define the thread class for handling new connection
class HandleAClient implements Runnable {
private Socket socket; // A connected socket
/** Construct a thread */
public HandleAClient(Socket socket) {
this.socket = socket;
}
/** Run a thread */
public void run() {
try {
// Create data input and output streams
DataInputStream inputFromClient = new DataInputStream(
socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(
socket.getOutputStream());
// Continuously serve the client
while (true) {
// Receive radius from the client
double radius = inputFromClient.readDouble();
// Compute area
double area = radius * radius * Math.PI;
// Send area back to the client
outputToClient.writeDouble(area);
Platform.runLater(() -> {
ta.appendText("radius received from client: " +
radius + '\n');
ta.appendText("Area found: " + area + '\n');
});
}
}
catch(IOException e) {
ex.printStackTrace();
}
}
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}