I have a problem.

In my code i have an array of players, everyone with his "in" and "out" to the server.

From Server to Clients i can communicate well and without any problem and every client shows in his GUI the change sent by Server.

The problem is the communication from Clients to Server. As Server, I want to recieve petitions from every player to do some work. The problem is that i dont know from which index i recieve the petition and I cant check every players[index].in.readUTF() cause it blocks the program.

Some help? in.avaiable() doesnt work for me.

To show it clearer:

When a player logs into the Server i do this in the Server Side.

socket = serverSocket.accept();
out = new DataOutputStream(menuPrincipal.socket.getOutputStream());
in = new DataInputStream(menuPrincipal.socket.getInputStream());
players[i] = new player(i,out,in);

Then i have a thread in Server side waiting from messages.

The problem is that i dont know from which index of players array (from which player) will come the message. I cant check an index of players that is not sending anything to Server cause it will block the program.

So thats how it works:

From Server to Client I just do:

  1. player[i].out.writeUTF(message) from Server side
  2. Client just does in.readUTF() and all works fine

From Client to Server I do:

  1. out.writeUTF(message) from Client
  2. But then on the Server side i have to choose one player[i].in to read which i dont know which player is.
有帮助吗?

解决方案

So you say you've managed to send data from the Server to the Client, and it works fine. The same principle applies when sending data from client to server.

Have a Listening thread, on the server side. Inside the packet, you can include the name, or the IP address, of the user sending the data. IE:

Data Recieved by Server: 'message, hello chris, sender, reciever'

Your server can then split up the packet into it's meaningful sections using a string tokenizer.

Action: 'message'
Message: 'hello chris'
Sender: 'sender'
Reciever: 'reciever'.

Then you have all the data necessary to continue.

This implementation means that all the data you need is contained within the packet that you have received, and you don't have to check where it came from. The extra few bytes of data won't slow you down as much as having to perform a search every time you receive a packet.

Edit In response to OP Edit

Alternatively, instead of implementing an Array, you can implement a HashMap<String,Player>. That way, all you need to do is grab the username from the packet sent, using my description above, and pass it to the hashmap. The hashmap can return the User object that represents the client, and there is no need, again, for an index lookup.

You can find the documentation on the Java Hashmap here.

Finally, I noticed you've got a player class. The Java convention is that all classes start with an upper case letter. That is:

player should be Player.

Final edit in response to your comment

Your problem is an issue of bad design, I'm afraid. The clients should all be communicating to the server via the same channel, in this context. That way all the server has to do is listen out for any messages, parse them, and move them on. Adjust your implementation so that your client's all talk to the server via the same stream, and that will eliminate your issue.

其他提示

Ok first let me give you a small background on how sockets work, before giving you the solution and it is vital to understand what is going on.

Socket Explanation (Reference)

A socket is a software endpoint that establishes bidirectional communication between a server program and one or more client programs. Note the word bidirectional. This means that for each connection between a client and a server, you have two streams: an input stream and an output stream. These can be accessed by both socket objects that one sets up on the server side and client side.

enter image description here

Your Problem

From Server to Client I just do player[i].out.writeUTF(message) and Client then just checks his "in", doing in.readUTF() and all works fine. From Client to Server i do out.writeUTF(message) from Client but then, on the Server side i have to choose one player[i].in to read which i dont know which player is.

Therefore, if I understood correctly, you have a difficulty in how to determine which client sent you a message. This is easy to solve if you use multithreading correctly, as each client will be handled on a separate thread.

A vital step is how clients are handled initially. Consider the following code. In order to keep it short, I did not focus greatly on conventions.

ArrayList<ClientWorker> clientWorkers = new ArrayList<ClientWorker>();
int idCounter = 0;

    public void listenSocket(){
      try{
        int port = 9090
        server = new ServerSocket();
      } catch (IOException e) {
        System.exit(-1);
      }
      while(true){
        ClientWorker w;
        try{
    //server.accept returns a client connection
          clientWorker = new ClientWorker(server.accept(), idCounter, );
          idCounter++;
          clientWorkers.add(clientWorker); 
          Thread t = new Thread(clientWorker);
          t.start();
        } catch (IOException e) {
          System.exit(-1);
        }
      }
    }

Ok so through that code, we are handling new clients and assigning them with a unique key. Instead of array, I am using arraylists so that it can increase and descrease in size according to the number of users connected to the server. Once a client is received, I create a clientWorker instance. Furthermore, a unique key is assigned for each connected user, which can be used to fetch its object from the arraylist (if required).

The ClientWorker class looks something like this:

    class ClientWorker implements Runnable {
      private Socket client;
      public int id

    //Constructor
      ClientWorker(Socket client, int id) {
        this.client = client;
        this.id = id;
      }

      public void run(){
        String line;
        BufferedReader in = null;
        PrintWriter out = null;
        try{
          in = new BufferedReader(new InputStreamReader(client.getInputStream()));
          out = new PrintWriter(client.getOutputStream(), true);
        } catch (IOException e) {
          System.out.println("in or out failed");
          System.exit(-1);
        }

        while(true){
          try{
//ANY DATA I GET FROM THIS STREAM IS FROM THIS PARTICULAR CLIENT ONLY!
            line = in.readLine();
            System.out.println("RECEIVED FROM CLIENT "+ id +" " + line);
           }catch (IOException e) {
            System.exit(-1);
           }
        }
      }
    }

This thread calls the run() method. Since each client has a separate thread, the data handled from a particular thread is sent from that particular client and not someone else. Therefore, one can distinguish each client's data easily.

Sorry its a long answer. It took sometime so that I reach my point.

References

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top