服务器/多客户端程序不会向所有客户端发送消息 [英] Server/Multiclient program wont send message to all clients

查看:97
本文介绍了服务器/多客户端程序不会向所有客户端发送消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个涉及多线程服务器的程序,在该程序中,我希望将客户端发送的消息回显到当前连接到服务器的每个客户端。它并没有完全做到这一点。我将从客户端向服务器发送一条消息,它将回显到同一客户端。不给其他客户。假设,在一个客户的情况下,我依次输入一个,然后依次输入两个和三个。交换将是这样的:



客户端1:一个



从服务器ON客户端1的回声控制台:一个



客户端1:两个



从服务器打开回显客户端1的控制台:客户端1:三个。

从服务器ON回显客户端1:三个



这部分做了应做的事情。但是在Client 2的控制台上绝对没有任何反应。假设上述交换已经发生。客户2的屏幕仍为空白。然后,我将在客户端2中输入一些内容,例如测试。服务器将以一个响应客户端2。假设我在客户端2中再次输入测试。服务器将以两个响​​应。你明白了。我不确定为什么要这么做。我涉及三个文件,即客户端,服务器和一个用于管理它们之间的连接的文件。



编辑:我想知道这个问题!在客户端的第43行,控制台在继续操作之前需要一些用户输入。我想这就是为什么当第一个客户端发送用户输入时,它会得到正确的答复,而第二个客户端却没有:因为第二个客户端未在控制台中输入任何内容,并且它仍在等待输入,以便继续。有关如何解决此问题的任何想法?



客户:

 套餐客户; 

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

公共类Client {

//客户端的套接字
套接字袜子;
//读取输入数据的流
DataInputStream din;
//发送输出数据的流
DataOutputStream dout;

public static void main(String [] args){
//创建新客户端
new Client();
}

public Client(){
try {
//激活套接字到主机和端口
sock = new Socket( localhost ,4444);
//打开输入和输出流
din = new DataInputStream(sock.getInputStream());
dout = new DataOutputStream(sock.getOutputStream());

//开始监听用户输入
listenIn();
} catch(UnknownHostException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
}

public void listenIn(){
//监视用户输入的控制台
Scanner userIn = new Scanner(System.in) ;

while(true){
//虽然没有什么内容可从控制台读取
while(!userIn.hasNextLine()){
try {
//确保通过侦听输入
不会不断使用资源Thread.sleep(1);
} catch(InterruptedException e){
e.printStackTrace();
}
}

//从用户输入中获取行
字符串输入= userIn.nextLine();

//如果用户退出客户端,则中断循环并退出程序
if(input.toLowerCase()。equals( quit)){
break;
}

try {
//将用户输入输出到服务器
dout.writeUTF(input);
//从数据输出流的缓冲区空间中清除所有数据
dout.flush();

//虽然没有什么内容可以从输入流中读取,但是可以节省资源
while(din.available()== 0){
try {
Thread。睡眠(1);
} catch(InterruptedException e){
e.printStackTrace();
}
}

//有输入数据时,将其打印到控制台
字符串reply = din.readUTF();
System.out.println(reply);
} catch(IOException e){
e.printStackTrace();
休息时间;
}
}

//关闭所有I / O流和套接字,因此不会发生内存泄漏
try {
din.close ();
dout.close();
sock.close();
} catch(IOException e){
e.printStackTrace();
}
}

}

服务器:

 打包服务器; 

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

公共类服务器{

//服务器的套接字
ServerSocket sSock;
ArrayList< ServerConnection>连接=新的ArrayList< ServerConnection>();
boolean run = true;

public static void main(String [] args){
//创建新服务器
new Server();
}

public Server(){
try {
//将服务器套接字初始化为正确的端口
sSock = new ServerSocket(4444);
//套接字应该打开
while(run){
//将客户端套接字初始化为正确的端口
Socket sock = sSock.accept();
//在客户端套接字和服务器之间创建一个新的服务器连接对象
ServerConnection sConn = new ServerConnection(sock,this);
//启动线程
sConn.start();
//将连接添加到数组列表
connections.add(sConn);
}
} catch(IOException e){
e.printStackTrace();
}
}
}

服务器连接:

 打包服务器; 

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

公共类ServerConnection扩展了线程{

套接字袜子;
服务器服务器;
DataInputStream in;
DataOutputStream输出;
boolean run = true;

//创建服务器连接,并使用super通过线程的构造函数运行它。
public ServerConnection(套接字,服务器服务器){
super( ServerConnectionThread);
this.sock =套接字;
this.server =服务器;
}

public void sendOne(String text){
try {
//将文本写入输出流
out.writeUTF(text) ;
//从流的缓冲区空间中清除剩余数据
out.flush();
} catch(IOException e){
e.printStackTrace();
}
}

//向每个客户端发送一个字符串
public void sendAll(String text){
/ *遍历所有服务器服务器
中的连接,并将文本发送给每个客户端* /
for(int i = 0; i< server.connections.size(); i ++){
ServerConnection sc = server .connections.get(i);
sc.sendOne(文本);
}
}

public void run(){
try {
//将输入流设置为来自套接字
的输入in = new DataInputStream(sock.getInputStream());
//设置输出流以写出到套接字
out = new DataOutputStream(sock.getOutputStream());

//虽然循环应该正在运行(由布尔值确定)
while(run){
//虽然没有传入数据,但是将线程休眠节省资源
while(in.available()== 0){
try {
Thread.sleep(1);
} catch(InterruptedException e){
e.printStackTrace();
}
}
//将传入的数据存储在字符串中
String textIn = in.readUTF();
//将其发送给所有客户端
sendAll(textIn);
}

//关闭数据流和套接字以防止内存泄漏
in.close();
out.close();
sock.close();
} catch(IOException e){
e.printStackTrace();
}
}

}


解决方案

就像在服务器端所做的那样,您可以使用单独的线程来处理客户端中的传入数据。这样,在控制台中等待用户输入将不会阻止传入的数据流。



这里是您如何实现此目的的想法。



新的ClientConnection:

 包客户端; 

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

公共类ClientConnection扩展了线程{

DataInputStream din = null;

public ClientConnection(Socket socket)抛出IOException {
this.setName( Client-Thread);
this.din = new DataInputStream(socket.getInputStream());
}

public void run(){

boolean run = true;

而(运行){

//虽然输入流中没有内容可读取,但可以节省资源
试试{

/ /当有输入数据时,将其打印到控制台
字符串答复= din.readUTF();
System.out.println(reply);

运行= this.isAlive();

} catch(SocketException e){
System.out.println( Disconnected);
run = false;
} catch(IOException e){
e.printStackTrace();
}



}

试试{
din.close();
} catch(IOException e){
e.printStackTrace();
}

}

}

这是重新格式化的客户端:

 打包客户端; 

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

公共类客户端{

//客户端的套接字
套接字袜子;

//发送输出数据的流
DataOutputStream dout;

public static void main(String [] args){
//创建新客户端
new Client();
}

public Client(){
try {
//激活主机和端口的套接字
sock = new Socket( localhost ,4444);
//打开输入和输出流
dout = new DataOutputStream(sock.getOutputStream());

//监听传入消息
ClientConnection client = new ClientConnection(sock);
client.start();

//开始监听用户输入
listenIn();


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

public void listenIn(){
//监视用户输入的控制台
Scanner userIn = new Scanner(System.in) ;

while(true){
//虽然没有任何内容可从控制台读取
while(!userIn.hasNextLine()){
try {
//通过侦听输入
来确保资源不会经常被使用Thread.sleep(1);
} catch(InterruptedException e){
e.printStackTrace();
}
}

//从用户输入中获取行
字符串输入= userIn.nextLine();

//如果用户退出客户端,则中断循环并退出程序
if(input.toLowerCase()。equals( quit)){
break;
}

try {
//将用户输入输出到服务器
dout.writeUTF(input);
//从数据输出流的缓冲区空间中清除所有数据
dout.flush();
} catch(IOException e){
e.printStackTrace();
休息时间;
}
}

//关闭所有I / O流和套接字,因此不会发生内存泄漏
try {
dout.close ();
sock.close();
} catch(IOException e){
e.printStackTrace();
}
}

}

服务器端,您也可以考虑从连接列表中删除断开连接的客户端:

 公共类ServerConnection扩展线程{
...
public void run(){
try {
...
} catch(SocketException e){
System.out.println( Client断开连接);
server.connections.remove(this);
} catch(IOException e){
e.printStackTrace();
}
}
}

我希望这会有所帮助。


I'm working on a program involving a multithreaded server, in which I want messages sent by clients to be echoed back to every client currently connected to the server. It doesn't exactly do this. I will send a message from a client to the server, and it will echo back to that same client. Not to the other client. Let's say, with one client I sequentially type "One" then "Two" then "Three". The exchange will be something like this:

Client 1: "One"

Echo from Server ON Client 1's console: "One"

Client 1: "Two"

Echo from Server ON Client 1's console: "Two"

Client 1: "Three"

Echo from Server ON Client 1's console: "Three"

This part does what it should. But absolutely nothing happens on Client 2's console. Let's say the exchange above has already happened. Client 2's screen will still be blank. I will then type something in Client 2, let's say "Test". The server will respond to Client 2 with "One". Let's say I type "Test" again in Client 2. The server will respond with "Two". You get the idea. I'm not sure why it's doing this. I have three files involved, The Client, The Server, and one meant to manage connections between them.

EDIT: I THINK I KNOW THE PROBLEM! On line 43 in client, the console expects some user input before it will proceed. Which I THINK is why when the first client sends user input, it gets a correct reply, but the second one doesn't: because the second client didn't enter anything in the console, and it's still waiting for some input in order to proceed. Any ideas on how to work around this?

Client:

package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

//The socket for the client
Socket sock;
//The stream to read incoming data
DataInputStream din;
//The stream to send outgoing data
DataOutputStream dout;

public static void main(String[] args) {
    //Create a new client
    new Client();
}

public Client() {
    try {
        //Activate the socket to the host and port
        sock = new Socket("localhost", 4444);
        //Open the input and output streams 
        din = new DataInputStream(sock.getInputStream());
        dout = new DataOutputStream(sock.getOutputStream());

        //Start listening for user input
        listenIn();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void listenIn() {
    //Monitors the console for user input
    Scanner userIn = new Scanner(System.in);

    while(true) {
        //While there is nothing left to read from the console
        while(!userIn.hasNextLine()) {
            try {
                //Ensures resources aren't constantly being used by listening for input
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //Get line from user input
        String input = userIn.nextLine();

        //if user exits the client, break the loop and exit the program
        if(input.toLowerCase().equals("quit")) {
            break;
        }

        try {
            //outputs user input to Server
            dout.writeUTF(input);
            //Flushes all data out of the data output stream's buffer space
            dout.flush();

            //While there's nothing to read from the input stream, save resources
            while(din.available() == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //When there's incoming data, print it to the console
            String reply = din.readUTF();
            System.out.println(reply);
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }
    }

    //Close all the I/O streams and sockets, so there aren't memory leaks
    try {
        din.close();
        dout.close();
        sock.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

Server:

package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {

//The server's socket
ServerSocket sSock;
ArrayList<ServerConnection> connections = new ArrayList<ServerConnection>();
boolean run = true;

public static void main(String[] args) {
    //Create a new server
    new Server();
}

public Server() {
    try {
        //Initialize the server socket to the correct port
        sSock = new ServerSocket(4444);
        //While the socket should be open
        while(run) {
            //Initialize the client socket to the correct port
            Socket sock = sSock.accept();
            //Create a new server connection object between the client socket and the server
            ServerConnection sConn = new ServerConnection(sock, this);
            //Start the thread
            sConn.start();
            //Add the connection to the arraylist
            connections.add(sConn);
        }  
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}

Server Connection:

package server;

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

public class ServerConnection extends Thread{

Socket sock;
Server server;
DataInputStream in;
DataOutputStream out;
boolean run = true;

//Create the server connection and use super to run it with Thread's constructor
public ServerConnection(Socket socket, Server server) {
    super("ServerConnectionThread");
    this.sock = socket;
    this.server = server;
}

public void sendOne(String text) {
    try {
        //Write the text to the output stream
        out.writeUTF(text);
        //Flush the remaining data out of the stream's buffer space
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//Send a string to every client
public void sendAll(String text) {
    /*Iterate through all of the server connections in the server
    and send the text to every client*/
    for(int i = 0; i < server.connections.size(); i++) {
        ServerConnection sc = server.connections.get(i);
        sc.sendOne(text);
    }
}

public void run() {
    try {
        //Set the input stream to the input from the socket
        in = new DataInputStream(sock.getInputStream());
        //Set the output stream to write out to the socket
        out = new DataOutputStream(sock.getOutputStream());

        //While the loop should be running (as determined by a boolean value)
        while(run) {
            //While there is no incoming data, sleep the thread to save resources
            while(in.available() == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //Store the incoming data in a string
            String textIn = in.readUTF();
            //Send it to all clients
            sendAll(textIn);
        }

        //Close datastreams and socket to prevent memory leaks
        in.close();
        out.close();
        sock.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

解决方案

Like you have done in the server side, you may use a separate thread to take care of incoming data in the client side. That way, the waiting for the user input in the console will not block the incoming data flow.

Here is an idea of how you could implement this.

New ClientConnection:

package client;

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

public class ClientConnection extends Thread {

    DataInputStream din = null;

    public ClientConnection(Socket socket) throws IOException {
        this.setName("Client-Thread");
        this.din = new DataInputStream(socket.getInputStream());
    }

    public void run() {

        boolean run = true;

        while (run) {

            // While there's nothing to read from the input stream, save resources
            try {

                // When there's incoming data, print it to the console
                String reply = din.readUTF();
                System.out.println(reply);

                run = this.isAlive();

            } catch (SocketException e) {
                System.out.println("Disconnected");
                run = false;
            } catch (IOException e) {
                e.printStackTrace();
            }



        }

        try {
            din.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

And here is the reformulated Client:

package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {

    // The socket for the client
    Socket sock;

    // The stream to send outgoing data
    DataOutputStream dout;

    public static void main(String[] args) {
        // Create a new client
        new Client();
    }

    public Client() {
        try {
            // Activate the socket to the host and port
            sock = new Socket("localhost", 4444);
            // Open the input and output streams
            dout = new DataOutputStream(sock.getOutputStream());

            //Listening for incoming messages
            ClientConnection client = new ClientConnection(sock);
            client.start();

            // Start listening for user input
            listenIn();


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

    public void listenIn() {
        // Monitors the console for user input
        Scanner userIn = new Scanner(System.in);

        while (true) {
            // While there is nothing left to read from the console
            while (!userIn.hasNextLine()) {
                try {
                    // Ensures resources aren't constantly being used by listening for input
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // Get line from user input
            String input = userIn.nextLine();

            // if user exits the client, break the loop and exit the program
            if (input.toLowerCase().equals("quit")) {
                break;
            }

            try {
                // outputs user input to Server
                dout.writeUTF(input);
                // Flushes all data out of the data output stream's buffer space
                dout.flush();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }

        // Close all the I/O streams and sockets, so there aren't memory leaks
        try {
            dout.close();
            sock.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

On the server side, you may also consider removing the disconnected clients from the list of connections:

public class ServerConnection extends Thread {
    ...    
    public void run() {
        try {
            ...
        } catch (SocketException e) {
            System.out.println("Client disconnected");
            server.connections.remove(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I hope this helps.

这篇关于服务器/多客户端程序不会向所有客户端发送消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆