问题 绑定到特定的IP地址和端口以接收UDP数据


我试图接收由PlayCap广播到网络地址192.168.103.255端口3000的UDP数据(http://www.signal11.us/oss/playcap/)。我遇到了绑定到此地址和端口的问题。这是我的Java代码:

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();
    }
}

这会返回错误:

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

我已经运行了命令“netstat -a -n”,输出中的任何地方都没有列出地址192.168.103.255和端口3000,所以我认为这个端口不在使用中。事实上,我尝试的任何地址/端口组合(包括我的静态IP地址)都会出现此错误。

我还写了一些C代码来创建一个套接字并绑定到这个地址和端口,但它也在bind调用上失败了。但是,此代码将绑定到我的静态IP地址(192.168.1.149)上的端口。这是代码:

#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;
}

我正在使用Windows 7机器。我在Eclipse中运行Java代码。我正在使用命令使用MinGW编译C代码:

gcc a.c -lws2_32

(“a.c”是文件名)。

虽然Java代码更重要,但我很高兴知道在我的任何一个代码示例中我出错了。任何建议都非常感谢。


12670
2017-11-26 04:08


起源

Win32错误是什么?为何静态IP? - Kirill Kobelev
为什么你说“广播”然后静态IP? - Kirill Kobelev


答案:


请尝试使用此代码来代替Java代码:

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();
    }
}

为数据报套接字调用no-arg构造函数将使其绑定到随机可用端口。一旦绑定,进一步尝试(重新)绑定将抛出一个套接字异常(你看到的错误)。要“延迟”绑定,您可以在未绑定状态下创建数据报套接字(通过在构造函数中传递null),然后调用 bind 稍后的。


13
2017-11-26 04:16



得到此错误:java.net.BindException:无法分配请求的地址:无法在java.net.AbstractStackPlan上运行java.net.DualStackPlainDataSocket上的java.net.DualStackPlainDataSocket上的java.net.DualStackPlainDataSocket上的java.net.DualStackPlainDatagramSocketImpl.bind0(未知来源)来自runner.main的java.net.DatagramSocket.bind(未知来源)的未知来源(runner.java:11) - ajlitzau13
@ ajlitzau13:我的回答解释道 为什么 那是。 - Ben Jackson
尝试绑定到您的默认界面,以消除IPv6问题(删除Internet地址,只需使用该端口)。 - Perception
@BenJackson - 你的答案没有提供OP遇到的错误的解释,抱歉。 - Perception
@Perception:如果我将3000传递给DatagramSocket构造函数并在此之后消除两行,它确实绑定到0.0.0.0:3000(用netstat验证),但是当我用PlayCap回放数据时,没有收到任何内容(我编辑过)我的原始Java代码,用于在绑定后接收一些数据。) - ajlitzau13


您不绑定到广播地址以接收广播数据包。只需绑定到端口和地址 INADDR_ANY (对不起,不确定如何在Java中表达)并且您将在广播地址上获得到该端口的数据包。


3
2017-11-26 04:10



在哪里听?接近-1 ... - Kirill Kobelev
@KirillKobelev:我认为“监听端口/地址”被理解为绑定到特定地址,但我澄清了措辞。 - Ben Jackson
现在这听起来更好。 - Kirill Kobelev
我用“server.sin_addr.s_addr = htonl(INADDR_ANY);”替换了分配服务器地址的4行。我还在两个代码中添加了部分以接收一些数据(编辑我的OP)。现在,我的C代码成功绑定0.0.0.0:3000(通过netstat验证),但是当我运行PlayCap播放数据时,没有收到任何内容。我收到的代码看起来不错吗? - ajlitzau13
为了将来参考,最终解决了我的问题的是将我的静态IP地址设置为192.168.103.xxx范围内的某些内容。由于数据正在广播到192.168.103.255,除非我的IP在此范围内,否则我无法接收。谢谢你的帮助。 - ajlitzau13


出现了 Datagram构造函数接受要绑定的端口号。希望有帮助......


0
2017-11-26 04:24