Binding to a specific IP address and port to recei

2019-03-15 12:13发布

问题:

I am trying to receive UDP data that is broadcast to network address 192.168.103.255 port 3000 by PlayCap (http://www.signal11.us/oss/playcap/). I'm having problems binding to this address and port. Here's my Java code:

public static void main(String[] args) {
    try {
        DatagramSocket s = new DatagramSocket();
        InetSocketAddress address = new InetSocketAddress("192.168.103.255", 3000);
        s.bind(address);

        byte buffer[] = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        System.out.println("Waiting...");
        s.receive(packet);
        System.out.println("Received!");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

This returns the error:

java.net.SocketException: already bound
    at java.net.DatagramSocket.bind(Unknown Source)
    at runner.main(runner.java:12)

I have run the command "netstat -a -n", and neither address 192.168.103.255 nor port 3000 are listed anywhere in the output, so I don't think this port is already in use. In fact, I get this error for any address/port combination I try (including my static IP address).

I also wrote some C code to make a socket and bind to this address and port, but it also fails on the bind call. This code, however, will bind to ports on my static IP address (192.168.1.149). Here's that code:

#include <stdio.h>
#include <sys/types.h>
#include <winsock.h>
#include <unistd.h>

#define a1 192
#define a2 168
#define a3 103
#define a4 255
#define PORT 3000

int main() {

    /* Open windows connection */
    WSADATA w;
    if (WSAStartup(0x0101, &w) != 0)
    {
        printf("Could not open Windows connection.\n");
        exit(0);
    }

    /* Clear out server struct */
    SOCKADDR_IN server;
    memset((void *)&server, '\0', sizeof(struct sockaddr_in));

    /* Set family and port */
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
    server.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
    server.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
    server.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;

    /* Open a datagram socket */
    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sd == INVALID_SOCKET)
    {
        printf("Could not create socket.\n");
        WSACleanup();
        exit(0);
    }

    /* Bind address to socket */
    if (bind(sd, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)) == -1)
    {
        printf("Could not bind name to socket.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }

    /* Receive */
    char data[1024];
    printf("Waiting to receive...\n");
    if (recv(sd, (char *)&data, (int)sizeof(data), 0))
    {
        printf("Error receiving data.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }

    printf("Data: %s", data);

    return 0;
}

I'm using a Windows 7 machine. I'm running the Java code in Eclipse. I'm compiling the C code with MinGW using the command:

gcc a.c -lws2_32

("a.c" is the file name).

While the Java code is more important, I would be happy to know where I'm going wrong in either of my code examples. Any suggestions are very much appreciated.

回答1:

Try this for your Java code instead:

public static void main(String[] args) {
    try {
        DatagramSocket s = new DatagramSocket(null);
        InetSocketAddress address = new InetSocketAddress("192.168.103.255", 3000);
        s.bind(address);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Calling the no-arg constructor for a datagram socket will cause it to bind to a random, available port. Once bound, further attempts to (re)bind will throw a socket exception (with the error you were seeing). To 'defer' binding, you instead create the datagram socket in an unbound state (by passing a null in the constructor), then calling bind later on.



回答2:

You don't bind to the broadcast address to receive broadcast packets. Just bind to the port and the address INADDR_ANY (sorry, not sure how to express that in Java) and you will get packets to that port on the broadcast address.



回答3:

It appears that the Datagram constructor takes the port number to bind to. Hope that helped...



标签: java c udp bind