Search code examples
javaportdatagram

"address already in use cannot bind" when creating a Java DatagramSocket object.


I'm passing an integer to DatagramSocket's constructor though MyDatagramSocket, but I get the error: "address already in use: Cannot bind". I'm running the client from NetBeans and the Server from a terminal. I've tried several different ports, restarted Netbeans - shut down the terminal, and even tried restarting the computer.

I try to find the port with netstat, but i don't even find it there. Here is my code:

Client.java

package datagramcounterserver;
import java.io.*;

public class Client {
    public static void main(String[] args) {
        InputStreamReader is = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(is); 
        try {
            System.out.println("Welcome to the Daytime client. \n" + "What is the name of the server host?"); 
            String hostName = br.readLine(); 
            if (hostName.length() == 0) 
                hostName = "localhost"; 
            System.out.println("What is the port number of the server host?"); 
            String portNum = br.readLine(); 
            if (portNum.length() == 0) {
                portNum = "223";
            }
            System.out.println("Counter receiver from the server: " + Helper.getCounter(hostName, portNum));
        }
        catch(Exception ex) {
            ex.printStackTrace(); 
        }
    }
}

Helper.java

package datagramcounterserver;
import java.net.*; 
import java.net.InetAddress;

public class Helper {
    public static int getCounter(String hostName, String portNum) {
        int counter = 0; 
        String message = "1"; 
        try {
            InetAddress serverHost = InetAddress.getByName(hostName);
            int serverPort = Integer.parseInt(portNum);
            MyDatagramSocket mySocket = new MyDatagramSocket(serverPort);
            mySocket.sendMessage(serverHost, serverPort, " ");
            message = mySocket.receiveMessage(); 
            System.out.println("Message received: " + message);
            counter = Integer.parseInt(message.trim());
            mySocket.close();
        }
        catch (Exception ex) {
            ex.printStackTrace(); 
        }
        return counter;
    }
}

MyDatagramSocket.java

package datagramcounterserver;

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

public class MyDatagramSocket extends DatagramSocket {
    final int MAX_LEN = 10;
    MyDatagramSocket(int portNo) throws SocketException {
        super(portNo); 
    }

    public void sendMessage(InetAddress receiverHost, int receiverPort, String message) throws IOException {
        byte[] sendBuffer = message.getBytes();
        DatagramPacket datagram = new DatagramPacket(sendBuffer, sendBuffer.length, receiverHost, receiverPort);
        this.send(datagram);
    }

    public String receiveMessage() throws IOException {
        byte[] receiveBuffer = new byte[MAX_LEN]; 
        DatagramPacket datagram = new DatagramPacket(receiveBuffer, MAX_LEN); 
        this.receive(datagram); 
        String message = new String(receiveBuffer); 
        return message; 
    }
}

MyServerDatagraphSocket.java

package datagramcounterserver;
import java.net.*;
import java.io.*; 

public class MyServerDatagramSocket extends DatagramSocket {
    static final int MAX_LEN = 100; 
    MyServerDatagramSocket(int portNo) throws SocketException {
        super(portNo); 
    }
    public void sendMessage(InetAddress receiverHost, int receiverPort, String message) throws IOException {
        byte[] sendBuffer = message.getBytes(); 
        DatagramPacket datagram = new DatagramPacket(sendBuffer, sendBuffer.length, receiverHost, receiverPort); 
        this.send(datagram); 
    }
    public String receiveMessage() throws IOException {
        byte[] receiveBuffer = new byte[MAX_LEN];
        DatagramPacket datagram = new DatagramPacket(receiveBuffer, MAX_LEN); 
        this.receive(datagram); 
        String message = new String(receiveBuffer);
        return message; 
    }
    public DatagramMessage receiveMessageAndSender() throws IOException {
        byte[] receiveBuffer = new byte[MAX_LEN];
        DatagramPacket datagram = new DatagramPacket(receiveBuffer, MAX_LEN);
        this.receive(datagram); 

        DatagramMessage returnVal = new DatagramMessage(); 
        returnVal.putVal(new String(receiveBuffer), datagram.getAddress(), datagram.getPort());
        return returnVal; 
    }
}

Server.java

package datagramcounterserver;
import java.io.*; 

public class Server {

    static int counter = 0; 
    public static void main(String[] args) {
        int serverPort = 223;
        if (args.length == 1)
            serverPort = Integer.parseInt(args[0]);
        try {
            MyServerDatagramSocket mySocket = new MyServerDatagramSocket(serverPort);
            System.out.println("Counter server ready.");
            while (true) {
                DatagramMessage request = mySocket.receiveMessageAndSender();
                System.out.println("Request received");
                increment(); 
                System.out.println("counter sent "+ counter);
                mySocket.sendMessage(request.getAddress(), request.getPort(), String.valueOf(counter)); 
            }
        }
        catch (Exception ex) {
                ex.printStackTrace(); 
        }
    }

    static private synchronized void increment() {
        counter++; 
    }

}

Solution

  • Both your server and your client are binding to the port, and the second one to launch fails to bind. The DatagramSocket constructor that takes a single int parameter is the equivalent of creating a DatagramSocket and calling socket.bind(port).

    While this is the behaviour you want on your server, on the client you do not want to bind to the port - you want to connect to the server. This is done instead by using the connect() method. You probably want to change your MyDatagramSocket class' constructor to something like this:

    MyDatagramSocket(String address, int portNo) throws SocketException {
        super(); 
        connect(InetAddress.getByName(address), portNo);
    }