在 LAN 中广播 UDP 消息以检测 IP 摄像机

nbu*_*urk 2 networking ios

我正在尝试为我的 iPhone 构建一个小程序,它允许检测本地网络上的设备(尤其是 IP 摄像机)。我知道其中一些支持协议,例如 UPnP,我也一直在研究它,但我现在想完全自己实现 iPhone 和相机之间的通信,而不依赖于库。

我的方法是将广播消息发送到本地网络并解析收到的响应。例如,为了检测本地网络上的 UPnP 设备,广播的消息需要具有以下内容:

M-SEARCH * HTTP/1.1\r\nHOST:255.255.255.255:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:1\r\n\r\n
Run Code Online (Sandbox Code Playgroud)

我对 C 语言的网络编程有点熟悉,所以我想用 C 语言编写通信代码,并稍后集成到我的 Objective-C 中。

我目前正在做以下事情:

// Create socket
int sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

// Enable broadcast messaging
int broadcastEnable = 1;
int ret = setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));

// Configure the port and ip we want to send to
struct sockaddr_in broadcastAddr; // Make an endpoint
memset(&broadcastAddr, 0, sizeof broadcastAddr);
broadcastAddr.sin_family = AF_INET;
inet_pton(AF_INET, "255.255.255.255", &broadcastAddr.sin_addr); // Set the broadcast IP address
broadcastAddr.sin_port = htons(1900); // Set port 1900

// Create the broadcast UPnP request
char *request = "M-SEARCH * HTTP/1.1\r\nHOST:255.255.255.255:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:1\r\n\r\n";

// start the broadcast
success = sendto(sd, request, strlen(request), 0, (struct sockaddr*)&broadcastAddr, sizeof broadcastAddr);
Run Code Online (Sandbox Code Playgroud)

现在,我被困在这一点上,因为我不知道如何处理任何答案。来自 UPnP 设备的回复会来自同一个套接字吗?我相信它应该能够通过recvfrom() 的recv() 接收传入的回复,但我不确定如何准确地实现它们。我必须创建一个新的套接字还是可以只使用现有的套接字?套接字必须使用bind() 绑定吗?

Tay*_*yab 5

首先,您正在尝试发送 SSDP 数据包以进行服务发现。因此,您应该将此数据包发送到多播地址 239.255.255.250,而不是 255.255.255.255。

除此之外,您可以在同一套接字上接收对发现请求的响应。只需调用该套接字上的recv() 函数即可。

此外,我希望您使用的是 Mac OS X(因为您正在为 iOS 进行开发),因此您已经安装了 Python。只需打开终端并输入python并复制粘贴以下 python 代码,

import sys
import socket

SSDP_ADDR = "239.255.255.250";
SSDP_PORT = 1900;
SSDP_MX = 1;
SSDP_ST = "ssdp:all";

ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
                "HOST: %s:%d\r\n" % (SSDP_ADDR, SSDP_PORT) + \
                "MAN: \"ssdp:discover\"\r\n" + \
                "MX: %d\r\n" % (SSDP_MX, ) + \
                "ST: %s\r\n" % (SSDP_ST, ) + "\r\n";

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT))
print sock.recv(1000)
Run Code Online (Sandbox Code Playgroud)

此代码将发送一个发现数据包,并打印从网络收到的第一个响应。我只是分享这段代码,因为即使你不了解 python,你也可以轻松测试它并理解代码。当然,这可以很容易地翻译成 C 语言。

我希望它有帮助。