服务器/多客户端程序不会向所有客户端发送消息

时间:2018-09-22 01:43:53

标签: java multithreading sockets client-server serversocket

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

客户端1:“一个”

从Server ON Client 1的控制台回显:“一个”

客户端1:“两个”

从Server ON Client 1的控制台回显:“两个”

客户1:“三个”

从Server ON Client 1的控制台回显:“三个”

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

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

客户:

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();
    }
}

}

服务器:

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();
    }
}
}

服务器连接:

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();
    }
}

}

1 个答案:

答案 0 :(得分:0)

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

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

新的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();
        }

    }

}

这是重新格式化的客户:

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();
        }
    }

}

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

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();
        }
    }
}

我希望这会有所帮助。