如何限制可以同时连接到服务器的客户端数量

时间:2019-05-06 19:14:45

标签: java controls client-server

我正在设置一个客户端服务器程序。 我需要将可连接到服务器的客户端数量限制为5个。 如果第6个客户端尝试连接到服务器,则他将不得不等待其中一个客户端离开,以便随后自动连接。 等待期间,客户将收到答复:“等待中”。

import java.io.*;

public class ChatMessage implements Serializable {
    protected static final long serialVersionUID = 1112122200L;
    static final int WHOISIN = 0, MESSAGE = 1, LOGOUT = 2;
    private int type;
    private String message;
    ChatMessage(int type, String message) {
        this.type = type;
        this.message = message;
    }
    int getType() {
        return type;
    }
    String getMessage() {
        return message;
    }
    }



import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;

/*
 * The server that can be run both as a console application or a GUI
 */
public class Server {
// a unique ID for each connection
private static int uniqueId;
// an ArrayList to keep the list of the Client
private ArrayList<ClientThread> al;
// if I am in a GUI
private ServerGUI sg;
// to display time
private SimpleDateFormat sdf;
// the port number to listen for connection
private int port;
// the boolean that will be turned of to stop the server
private boolean keepGoing;


/*
 *  server constructor that receive the port to listen to for connection as parameter
 *  in console
 */
public Server(int port) {
    this(port, null);
}

public Server(int port, ServerGUI sg) {
    // GUI or not
    this.sg = sg;
    // the port
    this.port = port;
    // to display hh:mm:ss
    sdf = new SimpleDateFormat("HH:mm:ss");
    // ArrayList for the Client list
    al = new ArrayList<ClientThread>();
}

public void start() {
    keepGoing = true;
    /* create socket server and wait for connection requests */
    try 
    {
        // the socket used by the server
        ServerSocket serverSocket = new ServerSocket(port);

        // infinite loop to wait for connections
        while(keepGoing) 
        {
            // format message saying we are waiting
            display("Server waiting for Clients on port " + port + ".");

            Socket socket = serverSocket.accept();      // accept connection
            // if I was asked to stop
            if(!keepGoing)
                break;
            ClientThread t = new ClientThread(socket);  // make a thread of it
            al.add(t);                                  // save it in the ArrayList
            t.start();
        }
        // I was asked to stop
        try {
            serverSocket.close();
            for(int i = 0; i < al.size(); ++i) {
                ClientThread tc = al.get(i);
                try {
                tc.sInput.close();
                tc.sOutput.close();
                tc.socket.close();
                }
                catch(IOException ioE) {
                    // not much I can do
                }
            }
        }
        catch(Exception e) {
            display("Exception closing the server and clients: " + e);
        }
    }
    // something went bad
    catch (IOException e) {
        String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
        display(msg);
    }
}       
/*
 * For the GUI to stop the server
 */
protected void stop() {
    keepGoing = false;
    // connect to myself as Client to exit statement 
    // Socket socket = serverSocket.accept();
    try {
        new Socket("localhost", port);
    }
    catch(Exception e) {
        // nothing I can really do
    }
}
/*
 * Display an event (not a message) to the console or the GUI
 */
private void display(String msg) {
    String time = sdf.format(new Date()) + " " + msg;
    if(sg == null)
        System.out.println(time);
    else
        sg.appendEvent(time + "\n");
}
/*
 *  to broadcast a message to all Clients
 */
private synchronized void broadcast(String message) {
    // add HH:mm:ss and \n to the message
    String time = sdf.format(new Date());
    String messageLf = time + " " + message + "\n";
    // display message on console or GUI
    if(sg == null)
        System.out.print(messageLf);
    else
        sg.appendRoom(messageLf);     // append in the room window

    // we loop in reverse order in case we would have to remove a Client
    // because it has disconnected
    for(int i = al.size(); --i >= 0;) {
        ClientThread ct = al.get(i);
        // try to write to the Client if it fails remove it from the list
        if(!ct.writeMsg(messageLf)) {
            al.remove(i);
            display("Disconnected Client " + ct.username + " removed from list.");
        }
    }
}

// for a client who logoff using the LOGOUT message
synchronized void remove(int id) {
    // scan the array list until we found the Id
    for(int i = 0; i < al.size(); ++i) {
        ClientThread ct = al.get(i);
        // found it
        if(ct.id == id) {
            al.remove(i);
            return;
        }
    }
}

/*
 *  To run as a console application just open a console window and: 
 * > java Server
 * > java Server portNumber
 * If the port number is not specified 1500 is used
 */ 
public static void main(String[] args) {
    // start server on port 1500 unless a PortNumber is specified 
    int portNumber = 1500;
    switch(args.length) {
        case 1:
            try {
                portNumber = Integer.parseInt(args[0]);
            }
            catch(Exception e) {
                System.out.println("Invalid port number.");
                System.out.println("Usage is: > java Server [portNumber]");
                return;
            }
        case 0:
            break;
        default:
            System.out.println("Usage is: > java Server [portNumber]");
            return;

    }
    // create a server object and start it
    Server server = new Server(portNumber);
    server.start();
    }

/** One instance of this thread will run for each client */
class ClientThread extends Thread {
    // the socket where to listen/talk
    Socket socket;
    ObjectInputStream sInput;
    ObjectOutputStream sOutput;
    // my unique id (easier for deconnection)
    int id;
    // the Username of the Client
    String username;
    // the only type of message a will receive
    ChatMessage cm;
    // the date I connect
    String date;

    // Constructore
    ClientThread(Socket socket) {
        // a unique id
        id = ++uniqueId;
        this.socket = socket;
        /* Creating both Data Stream */
        System.out.println("Thread trying to create Object Input/Output Streams");
        try
        {
            // create output first
            sOutput = new ObjectOutputStream(socket.getOutputStream());
            sInput  = new ObjectInputStream(socket.getInputStream());
            // read the username
            username = (String) sInput.readObject();
            display(username + " just connected.");
        }
        catch (IOException e) {
            display("Exception creating new Input/output Streams: " + e);
            return;
        }
        // have to catch ClassNotFoundException
        // but I read a String, I am sure it will work
        catch (ClassNotFoundException e) {
        }
        date = new Date().toString() + "\n";
    }

    // what will run forever
    public void run() {
        // to loop until LOGOUT
        boolean keepGoing = true;
        while(keepGoing) {
            // read a String (which is an object)
            try {
                cm = (ChatMessage) sInput.readObject();
            }
            catch (IOException e) {
                display(username + " Exception reading Streams: " + e);
                break;              
            }
            catch(ClassNotFoundException e2) {
                break;
            }
            // the messaage part of the ChatMessage
            String message = cm.getMessage();

            // Switch on the type of message receive
            switch(cm.getType()) {

            case ChatMessage.MESSAGE:
                broadcast(username + ": " + message);
                break;
            case ChatMessage.LOGOUT:
                display(username + " disconnected with a LOGOUT message.");
                keepGoing = false;
                break;
            case ChatMessage.WHOISIN:
                writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
                // scan al the users connected
                for(int i = 0; i < al.size(); ++i) {
                    ClientThread ct = al.get(i);
                    writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
                }
                break;
            }
        }
        // remove myself from the arrayList containing the list of the
        // connected Clients
        remove(id);
        close();
    }

    // try to close everything
    private void close() {
        // try to close the connection
        try {
            if(sOutput != null) sOutput.close();
        }
        catch(Exception e) {}
        try {
            if(sInput != null) sInput.close();
        }
        catch(Exception e) {};
        try {
            if(socket != null) socket.close();
        }
        catch (Exception e) {}
    }

    /*
     * Write a String to the Client output stream
     */
    private boolean writeMsg(String msg) {
        // if Client is still connected send the message to it
        if(!socket.isConnected()) {
            close();
            return false;
        }
        // write the message to the stream
        try {
            sOutput.writeObject(msg);
        }
        // if an error occurs, do not abort just inform the user
        catch(IOException e) {
            display("Error sending message to " + username);
            display(e.toString());
        }
        return true;
    }
}
}



import java.net.*;
import java.io.*;
import java.util.*;

/*
 * The Client that can be run both as a console or a GUI
 */
public class Client  {

// for I/O
private ObjectInputStream sInput;       // to read from the socket
private ObjectOutputStream sOutput;     // to write on the socket
private Socket socket;

// if I use a GUI or not
private ClientGUI cg;

// the server, the port and the username
private String server, username;
private int port;

/*
 *  Constructor called by console mode
 *  server: the server address
 *  port: the port number
 *  username: the username
 */
Client(String server, int port, String username) {
    // which calls the common constructor with the GUI set to null
    this(server, port, username, null);
}

/*
 * Constructor call when used from a GUI
 * in console mode the ClienGUI parameter is null
 */
Client(String server, int port, String username, ClientGUI cg) {
    this.server = server;
    this.port = port;
    this.username = username;
    // save if we are in GUI mode or not
    this.cg = cg;
}

/*
 * To start the dialog
 */
public boolean start() {
    // try to connect to the server
    try {
        socket = new Socket(server, port);
    } 
    // if it failed not much I can so
    catch(Exception ec) {
        display("Error connectiong to server:" + ec);
        return false;
    }

    String msg = "Connection accepted " + socket.getInetAddress() + ":" + socket.getPort();
    display(msg);

    /* Creating both Data Stream */
    try
    {
        sInput  = new ObjectInputStream(socket.getInputStream());
        sOutput = new ObjectOutputStream(socket.getOutputStream());
    }
    catch (IOException eIO) {
        display("Exception creating new Input/output Streams: " + eIO);
        return false;
    }

    // creates the Thread to listen from the server 
    new ListenFromServer().start();
    // Send our username to the server this is the only message that we
    // will send as a String. All other messages will be ChatMessage objects
    try
    {
        sOutput.writeObject(username);
    }
    catch (IOException eIO) {
        display("Exception doing login : " + eIO);
        disconnect();
        return false;
    }
    // success we inform the caller that it worked
    return true;
}

/*
 * To send a message to the console or the GUI
 */
private void display(String msg) {
    if(cg == null)
        System.out.println(msg);      // println in console mode
    else
        cg.append(msg + "\n");      // append to the ClientGUI JTextArea (or whatever)
}

/*
 * To send a message to the server
 */
void sendMessage(ChatMessage msg) {
    try {
        sOutput.writeObject(msg);
    }
    catch(IOException e) {
        display("Exception writing to server: " + e);
    }
}

/*
 * When something goes wrong
 * Close the Input/Output streams and disconnect not much to do in the catch clause
 */
private void disconnect() {
    try { 
        if(sInput != null) sInput.close();
    }
    catch(Exception e) {} // not much else I can do
    try {
        if(sOutput != null) sOutput.close();
    }
    catch(Exception e) {} // not much else I can do
    try{
        if(socket != null) socket.close();
    }
    catch(Exception e) {} // not much else I can do

    // inform the GUI
    if(cg != null)
        cg.connectionFailed();

}
/*
 * To start the Client in console mode use one of the following command
 * > java Client
 * > java Client username
 * > java Client username portNumber
 * > java Client username portNumber serverAddress
 * at the console prompt
 * If the portNumber is not specified 1500 is used
 * If the serverAddress is not specified "localHost" is used
 * If the username is not specified "Anonymous" is used
 * > java Client 
 * is equivalent to
 * > java Client Anonymous 1500 localhost 
 * are eqquivalent
 * 
 * In console mode, if an error occurs the program simply stops
 * when a GUI id used, the GUI is informed of the disconnection
 */
public static void main(String[] args) {
    // default values
    int portNumber = 1500;
    String serverAddress = "localhost";
    String userName = "Anonymous";

    // depending of the number of arguments provided we fall through
    switch(args.length) {
        // > javac Client username portNumber serverAddr
        case 3:
            serverAddress = args[2];
        // > javac Client username portNumber
        case 2:
            try {
                portNumber = Integer.parseInt(args[1]);
            }
            catch(Exception e) {
                System.out.println("Invalid port number.");
                System.out.println("Usage is: > java Client [username] [portNumber] [serverAddress]");
                return;
            }
        // > javac Client username
        case 1: 
            userName = args[0];
        // > java Client
        case 0:
            break;
        // invalid number of arguments
        default:
            System.out.println("Usage is: > java Client [username] [portNumber] {serverAddress]");
        return;
    }
    // create the Client object
    Client client = new Client(serverAddress, portNumber, userName);
    // test if we can start the connection to the Server
    // if it failed nothing we can do
    if(!client.start())
        return;

    // wait for messages from user
    Scanner scan = new Scanner(System.in);
    // loop forever for message from the user
    while(true) {
        System.out.print("> ");
        // read message from user
        String msg = scan.nextLine();
        // logout if message is LOGOUT
        if(msg.equalsIgnoreCase("LOGOUT")) {
            client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, ""));
            // break to do the disconnect
            break;
        }
        // message WhoIsIn
        else if(msg.equalsIgnoreCase("WHOISIN")) {
            client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));               
        }
        else {              // default to ordinary message
            client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, msg));
        }
    }
    // done disconnect
    client.disconnect();    
}

/*
 * a class that waits for the message from the server and append them to the JTextArea
 * if we have a GUI or simply System.out.println() it in console mode
 */
class ListenFromServer extends Thread {

    public void run() {
        while(true) {
            try {
                String msg = (String) sInput.readObject();
                // if console mode print the message and add back the prompt
                if(cg == null) {
                    System.out.println(msg);
                    System.out.print("> ");
                }
                else {
                    cg.append(msg);
                }
            }
            catch(IOException e) {
                display("Server has close the connection: " + e);
                if(cg != null) 
                    cg.connectionFailed();
                break;
            }
            // can't happen with a String object but need the catch anyhow
            catch(ClassNotFoundException e2) {
            }
        }
    }
}
}

0 个答案:

没有答案