0

I'm new in Java Sockets, I have seen so many examples but I can't understand how to pass an argument from server to client and vice versa. My destination is to pass an Object that's why I'm using Object I/O Stream.

I have to classes Server and Player.

public class Server extends Thread{
public static final int TEST = 165;

ServerSocket serverSocket;
InetAddress address;

Player playerWhite;

public Server() {               
    start();
}

@Override
public void run() {
    try
    {
        address = InetAddress.getLocalHost();
        serverSocket = new ServerSocket(6000);
        playerWhite = new Player();

        System.out.println("server waits for players");
        playerWhite.socket = serverSocket.accept();
        playerWhite.start();
        sendTestMessage(playerWhite);

    } 
    catch (IOException ex) 
    {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }               
}

public void sendTestMessage(Player player) throws IOException
{
    ObjectOutputStream testToClient = new ObjectOutputStream(player.socket.getOutputStream());        
    testToClient.write(TEST); 
    testToClient.flush();        
}

And the Player class:

public class Player extends Thread {   
Socket socket;

Player() throws IOException
{
    socket = new Socket(InetAddress.getLocalHost(), 6000);
}

@Override
public void run() {
    try {            
        listenTestStream();
    } 
    catch (IOException | ClassNotFoundException ex) 
    {
     Logger.getLogger(CheckerPlayer.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public void listenTestStream() throws IOException, ClassNotFoundException
{
    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    int message = ois.readInt();

    //To test
    System.out.println("Server listened: " + message);
}

I execute it as create a Server object in the other class.

When I have testing this application I saw that sometimes client is faster than Server. Is it possible to make him "wait" for server response? Thanks for your response.

EDIT 1: PROBLEM SOLUTION:

From outside we should create:

Player player = new Player(); // (class player extends from Thread) player.start();

and delete the Player variable - is not necessary, we need only Socket so: Server:

Socket playerWhiteSocket

public void run() {
try
{
    serverSocket = new ServerSocket(PORT);
    playerWhiteSocket = serverSocket.accept();
    sendMessage(playerWhiteSocket, "Hello");
} 
catch(IOException | ClassNotFoundException ex)
{}

public void sendMessage(Socket socket, String message) throws IOException
{
    ObjectOutputStream testToClient = new ObjectOutputStream(socket.getOutputStream());        
    testToClient.writeObject(message);
    testToClient.flush();        
}

In Player class we need get method:

public String receiveMessage() throws IOException, ClassNotFoundException
{
    //socket is a variable get from Player class socket = new Socket("severHost", PORT);
    ObjectInputStream messageFromServer = new ObjectInputStream(socket.getInputStream()); 
    String message = (String) messageFromServer.readObject();
    return message;
}   
rudald
  • 364
  • 5
  • 18
  • You use `write` which writes a byte and should be received via `read()`. But you do `readInt()`. Try `writeInt` instead of `write`. Also, why do you wanna send objects? Seems like a waste of bandwidth. Just send the data thats required. Waiting for data while reading from an input stream shouls be automatic. – Vince Dec 02 '15 at 23:54
  • I want to send a "Move" class object and I'm trying to do it first with int, but your response didn't solve the problem. – rudald Dec 03 '15 at 00:10
  • Generally you should avoid extending the Thread class in java multithreading: http://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread – avgvstvs Dec 15 '15 at 13:31

3 Answers3

1

I would recomment doing this public void start(){

try {
        ServerSocket = new ServerSocket(this.port,10,this.localAddress);

        // set timeout if you want
        //this.clientServerSocket.setSoTimeout(timeout);
        // infinity loop 
        while(true)
        {
            //wait for a client connection
            Socket socket = ServerSocket.accept();
            // start thread for every new client
            Thread t = new Thread(new AcceptClients(this.socket));
            t.start();
            System.out.println(L"new client connected");
            // call garbage collector and hope for the best
            System.gc();
        }
    } catch (IOException e) {
        System.out.println("IO Error");
        e.printStackTrace();
    }
}

and then in another class

public class AcceptClients implements Runnable{

// socket
private Socket socket;

public AcceptClients (Socket socket){
    this.socket = socket;
}
@Override
public void run() {
    // what happens if a client connect
}

}

I always use this and it works fine

jor
  • 158
  • 1
  • 13
1

Suggested changes.

  1. Create ServerSocket only once. If you have done it, you won't get "Address already in use" error

  2. After creating Server Socket, you thread should be in while (true) loop to accept connection from client.

  3. Once you create a client socket, pass that socket to thread.

  4. Now Player is used to send communication from server to client socket. So You need one more class like PlayerClient which create a socket to Server IP and Port. Now PlayerClient should create one more thread to handle IO operations like you have done from server. In this case, creating a socket is not in while loop from client side. It create a socket to server once. Now you can run this PlayerClient program from multiple machines.

  5. If you are just sending just primitive type, use DataOutputStream & DataInputStream instead of ObjectStreams

This code will become like this

try
    {
        address = InetAddress.getLocalHost();
        serverSocket = new ServerSocket(6000);
        System.out.println("server waits for players");

        while ( true){ 
             Socket socket = serverSocket.accept();
             Player playerWhite = new Player(socket);
             sendTestMessage(socket);// Move this method to Player thread and change the signature of this method accordingly to accept a socket
        }

    } 
    catch (IOException ex) 
    {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }    

Player.java

Player(Socket socket) throws IOException
{
    this.socket = socket;
    start();
}

Have a look at this chat example for better understanding.

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
0

Yep it is.

It should work if you put it in a endlees loop like that:

    try
{
    while(true){
        address = InetAddress.getLocalHost();
        serverSocket = new ServerSocket(6000);
        playerWhite = new Player();

        System.out.println("server waits for players");
        playerWhite.socket = serverSocket.accept();
        playerWhite.start();
        sendTestMessage(playerWhite);
    }

} 
catch (IOException ex) 
{
    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}  

But I would not recommend to put this in a thread. Instead I would put the connection of a new client in a thread, so multiple clients can connect to the server

jor
  • 158
  • 1
  • 13
  • I put "while" after the serverSocket because was exception of "Address already in use". I have other exception with "end of file exception" - in line ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); It seems that in this socket is null inside and the argument is not passing – rudald Dec 03 '15 at 00:14