2

I am sorry, I have searched but seem that all the answers dont fix my problem. I got this error when trying to create a ServerSocket to reply to multiple client message.

My server code:

package Server;

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

public class Server {
    public final static int defaultPort = 7;

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(defaultPort);            
            int i = 0;
            while (true) {
                try {
                    System.out.println("Server is running on port "
                            + defaultPort);
                    Socket s = ss.accept();
                    System.out.println("Client " + i + " connected");
                    RequestProcessing rp = new RequestProcessing(s, i);
                    i++;
                    rp.start();
                } catch (IOException e) {
                    System.out.println("Connection Error: " + e);
                }
            }
        } catch (IOException e) {
            System.err.println("Create Socket Error: " + e);
        } finally {

        }
    }
}

class RequestProcessing extends Thread {
    Socket channel;
    int soHieuClient;

    public RequestProcessing(Socket s, int i) {
        channel = s;
        clientNo = i;
    }

    public void run() {
        try {
            byte[] buffer = new byte[6000];
            DatagramSocket ds = new DatagramSocket(7);          
            while (true) {  
                DatagramPacket incoming = new DatagramPacket(buffer,
                        buffer.length);
                ds.receive(incoming);
                String theString = new String(incoming.getData(), 0,
                        incoming.getLength());
                System.out.println("Client " + clientNo 
                        + " sent: " + theString);
                if ("quit".equals(theString)) {
                    System.out.println("Client " + clientNo 
                            + " disconnected");
                    ds.close();
                    break;
                }
                theString = theString.toUpperCase();
                DatagramPacket outsending = new DatagramPacket(
                        theString.getBytes(), incoming.getLength(),
                        incoming.getAddress(), incoming.getPort());
                System.out.println("Server reply to Client "
                        + clientNo + ": " + theString);
                ds.send(outsending);
            }
        } catch (IOException e) {
            System.err.println(e);
        }

    }
}

and my Client code:

package Client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;

public class Client extends Object {
    public final static int serverPort = 7;

    public static void main(String[] args) {
        try {

            DatagramSocket ds = new DatagramSocket();
            InetAddress server = InetAddress.getByName("192.168.109.128");
            Socket s = new Socket("192.168.109.128", 7);            
            String theString = "";
            do {
                System.out.print("Enter message: ");
                InputStreamReader isr = new InputStreamReader(System.in);
                BufferedReader br = new BufferedReader(isr);
                theString = br.readLine();
                byte[] data = theString.getBytes();
                DatagramPacket dp = new DatagramPacket(data, data.length,
                        server, serverPort);

                ds.send(dp);
                System.out.println("Sent to server server: " + theString);

                byte[] buffer = new byte[6000];

                DatagramPacket incoming = new DatagramPacket(buffer,
                        buffer.length);
                ds.receive(incoming);
                System.out.print("Server reply: ");
                System.out.println(new String(incoming.getData(), 0, incoming
                        .getLength()));

            } while (!"quit".equals(theString));
            s.close();
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}

With the first Client connect, it works smoothly. But from the second Client, it throws java.net.BindException: Address already in use: Cannot bind. Second Client can also send and receive message, but the Client No is still 0.

Server is running on port 7
Client 0 connected
Server is running on port 7
Client 0 sent: msg 0
Server reply to Client 0: MSG 0
Client 1 connected
Server is running on port 7
java.net.BindException: Address already in use: Cannot bind
Client 0 sent: msg 1 <<-- this one is sent from client 1 but Client No is 0
Server reply to Client 0: MSG 1
1
  • Your code doesn't make sense. You don't need the TCP part at all, or the multiple UDP sockets at the server. Commented Oct 8, 2016 at 1:10

3 Answers 3

2

So, in RequestProcessing.run you decide to ignore the socket received at constructor and open a DatagramSocket on the same port as the one you are listening. What did you expect it will happen?

class RequestProcessing extends Thread {
    Socket channel;
    int soHieuClient;

    public RequestProcessing(Socket s, int i) {
        // *****************
        // The processor should be using this socket to communicate
        // with a connected client *using TCP Streams*
        channel = s;
        clientNo = i;
    }

    public void run() {
       try {
           byte[] buffer = new byte[6000];
           // *****************************
           // But, instead of using the this.channel, your code
           // decides to ignore the TCP socket,
           // then open another UDP *"server-side like"* socket.
           // First time it's OK, but the second thread attempting
           // to open another DatagramSocket on the same port will fail.
           // It's like attempting to open two TCP ServerSockets on the
           // same port
           DatagramSocket ds = new DatagramSocket(7);  

[Extra]

You will need to decide what protocol you'll be using: if you use a ServerSocket/Socket pair, then probably you want TCP communications, so no DatagramSockets.

If you want UDP communication, the ServerSocket/Socket has little to do with your approach and you'll need to use DatagramSocket. Construct it:

  1. with a port on the serverside - and do it only once.
  2. without any port for the client side then qualify each and every DatagramPackets with the server address and port.

See a tutorial on Oracle site on Datagram client/server configurations.

Sign up to request clarification or add additional context in comments.

1 Comment

TCP ports are separate from UDP ports. His problem lies in the fact that he keeps trying to bind to UDP port 7 on every client connection.
1

Everytime you receive a new client TCP connection on your main server socket, you spin up another instance of a RequestProcessing class. The first time you start the RequestProcessing instance thread, it successfully binds to UDP port 7. But then the second client connects and you try to spin up another instance of RequestProcessing while another one already exists. That's not going to work.

You should probably amend you protocol such that the RequestProcessing class picks a new port each time and signals back through to the TCP socket which port was chosen.

But if it was me, I would do this. Have a single RequestProcessing instance for all clients. Given that your UDP echo socket is just sending back a response to the address from which the packet arrived from, you only need one instance of this class.

Comments

0

A TCP solution:

An utility class (I'm too lazy to write the same code in multiple places):

  public class SocketRW {
    Socket socket;
    BufferedReader in;
    PrintWriter    out;

    public SocketRW(Socket socket)
    throws IOException 
    {
      super();
      this.socket = socket;
      if(null!=socket) {
        this.in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.out=new PrintWriter(socket.getOutputStream());
      }
    }

    public String readLine()
    throws IOException {
      return this.in.readLine();
    }

    public void println(String str) {
      this.out.println(str);
    }

    public Socket getSocket() {
      return socket;
    }

    public BufferedReader getIn() {
      return in;
    }

    public PrintWriter getOut() {
      return out;
    }
  }

Server code - no more datagrams, just using Input/Output streams from the sockets, wrapped as Reader/Writer using the utility

  public class TCPServer
  implements Runnable // in case you want to run the server on a separate thread
  {
    ServerSocket listenOnThis;

    public TCPServer(int port)
    throws IOException {
      this.listenOnThis=new ServerSocket(port);
    }

    @Override
    public void run() {
      int client=0;
      while(true) {
        try {
          Socket clientConn=this.listenOnThis.accept();
          RequestProcessing processor=new RequestProcessing(clientConn, client++);
          processor.start();
        } catch (IOException e) {
          break;
        }

      }
    }

    static public void main(String args[]) {
      // port to be provided as the first CLI option
      TCPServer server=new TCPServer(Integer.valueOf(args[0]));
      server.run(); // or spawn it on another thread
    }
  }

  class RequestProcessing extends Thread {
    Socket channel;
    int clientNo;

    public RequestProcessing(Socket s, int i) {
      channel = s;
      clientNo = i;
    }

    public void run() {
      try {
        SocketRW utility=new SocketRW(this.channel);          
        while (true) { 
          String theString=utility.readLine().trim();
          System.out.println("Client " + clientNo 
              + " sent: " + theString);
          if ("quit".equals(theString)) {
            System.out.println("Client " + clientNo 
                + " disconnected");
            this.channel.close();
            break;
          }
          theString = theString.toUpperCase();
          utility.println(theString);
        }
      } catch (IOException e) {
        System.err.println(e);
      }
    }
  }

Client code - no more datagram sockets, using the same IO streams of the socket.

  class TCPClient
  implements Runnable // just in case you want to run multithreaded clients
  {
    Socket socket;

    public TCPClient(InetAddress serverAddr, int port)
     throws IOException {
      this.socket=new Socket(serverAddr, port);
    }

    public void run() {
      String theString="";
      InputStreamReader isr = new InputStreamReader(System.in);
      try {
        SocketRW utility=new SocketRW(this.socket);
        BufferedReader br = new BufferedReader(isr);
        do {
          System.out.print("Enter message: ");
          theString = br.readLine().trim();
          utility.println(theString);
          System.out.println("Sent to server server: " + theString);

          String received=utility.readLine();
          System.out.println("Server reply: "+received);

        } while (!"quit".equals(theString));
      }
      catch(IOException e) {
        e.printStackTrace();
      }
    }

    static public void main(String[] args) {
      int port=Integer.valueOf(args[0]); // will throw if its no OK.

      TCPClient client=new TCPClient(
          InetAddress.getByName("192.168.109.128"),
          port
      );

      client.run();
    }
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.