Sockets 侦听UDP多播消息的UDP单播回复

Sockets 侦听UDP多播消息的UDP单播回复,sockets,udp,multicast,upnp,Sockets,Udp,Multicast,Upnp,我试图在linux上实现一个非常简单的upnp控制器,这样我就可以控制一个需要专有软件的设备 文档说我需要向特定地址和端口发送特定形式的UDP多播请求(请参阅下面代码中的“M-SEARCH”字符串),设备将通过UDP单播响应我从中发送的地址和端口 我做不到。tcpdump显示UDP多播请求指向正确的地址和端口,格式看起来正确,但我看不到回复 我从环回接口发送并监听(设备在同一台机器上) 另一个upnp控制器(即不是我的)在环回接口上正常工作 有人能告诉我我做错了什么吗 代码如下: #inclu

我试图在linux上实现一个非常简单的upnp控制器,这样我就可以控制一个需要专有软件的设备

文档说我需要向特定地址和端口发送特定形式的UDP多播请求(请参阅下面代码中的“M-SEARCH”字符串),设备将通过UDP单播响应我从中发送的地址和端口

我做不到。tcpdump显示UDP多播请求指向正确的地址和端口,格式看起来正确,但我看不到回复

我从环回接口发送并监听(设备在同一台机器上)

另一个upnp控制器(即不是我的)在环回接口上正常工作

有人能告诉我我做错了什么吗

代码如下:

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/udp.h>
 #include <unistd.h>
 #include <fcntl.h>

 #define MAXBUFSIZE 65536

int main(int argc, char ** argv ) {

unsigned char loop;
loop = 0;
unsigned char ttl;
ttl = 4;
int bcast;
bcast = 1;

int sock;

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
    perror("socket");
    exit(EXIT_FAILURE);
}

struct sockaddr_in destadd;
memset(&destadd, 0, sizeof(destadd));
destadd.sin_family = AF_INET;
destadd.sin_port = htons((uint16_t)1900);
if (inet_pton(AF_INET, "239.255.255.250", &destadd.sin_addr) < 1) {
    perror("inet_pton dest");
    exit(EXIT_FAILURE);
}

struct sockaddr_in interface_addr;
memset(&interface_addr, 0, sizeof(interface_addr));
interface_addr.sin_family = AF_INET;
interface_addr.sin_port = htons(0);
if (inet_pton(AF_INET, "127.0.0.1", &interface_addr.sin_addr) < 1) {
    perror("inet_pton interface");
    exit(EXIT_FAILURE);
}

if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0){
    perror("setsockopt loop");
    exit(EXIT_FAILURE);
}

if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0){
    perror("setsockopt ttl");
    exit(EXIT_FAILURE);
}

if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
               (struct in_addr *)&interface_addr.sin_addr,
               sizeof(interface_addr.sin_addr)) < 0) {
    perror("setsockopt if");
    exit(EXIT_FAILURE);
}

if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0) {
    perror("setsockopt bcast");
    exit(EXIT_FAILURE);
}

struct ip_mreqn imr;
memset(&imr, 0, sizeof(imr));
if (inet_pton(AF_INET, "239.255.255.250", &imr.imr_multiaddr.s_addr) < 1) {
    perror("inet_pton");
    exit(EXIT_FAILURE);
}
inet_pton(AF_INET, "127.0.0.1", (struct in_addr *)&imr.imr_address);
imr.imr_ifindex = 0;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
               (void *)&imr, sizeof(imr)) < 0) {
    perror("setsockopt addmem");
    exit(EXIT_FAILURE);
}

if (bind(sock, (struct sockaddr *)&interface_addr,
    sizeof(struct sockaddr_in)) < 0) {
    perror("bind");
    exit(EXIT_FAILURE);
}

char buffer[1024];

strcpy(buffer, "M-SEARCH * HTTP/1.1\r\n"
                   "Host: 239.255.255.250:1900\r\n"
                   "Man: \"ssdp:discover\"\r\n"
                   "ST: upnp:rootdevice\r\n"
                   "MX: 3\r\n"
                   "User-Agent: Test/1.0\r\n"
                   "\r\n");

if (sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&destadd,
       sizeof(destadd)) < 0) {
    perror("sendto");
    exit(EXIT_FAILURE);
}

if (recvfrom(sock, &buffer, sizeof(buffer)-1, 0, NULL, NULL) < 0) {
    perror("recvfrom");
    exit(EXIT_FAILURE);
}


if (close(sock) < 0) {
    perror("close");
    exit(EXIT_FAILURE);
}

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义MAXBUFSIZE 65536
int main(int argc,字符**argv){
无符号字符循环;
循环=0;
无符号字符ttl;
ttl=4;
int-bcast;
bcast=1;
int袜子;
sock=插座(AF_INET,sock DGRAM,0);
if(sock<0){
佩罗(“插座”);
退出(退出失败);
}
destadd中的结构sockaddr_;
memset(&destadd,0,sizeof(destadd));
destadd.sin_family=AF_INET;
destadd.sin_port=htons(uint16_t)1900);
if(inet\u pton(AF\u inet,“239.255.255.250”&destadd.sin\u addr)<1){
perror(“inet_pton dest”);
退出(退出失败);
}
接口地址中的结构sockaddr\u;
memset(&interface_addr,0,sizeof(interface_addr));
接口地址sin系列=AF\U INET;
接口地址sin端口=htons(0);
if(inet\u pton(AF\u inet,“127.0.0.1”&接口地址sin\u addr)<1){
perror(“inet_pton接口”);
退出(退出失败);
}
if(setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&LOOP,sizeof(LOOP))<0){
perror(“setsockopt循环”);
退出(退出失败);
}
if(setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&TTL,sizeof(TTL))<0){
perror(“setsockopt ttl”);
退出(退出失败);
}
if(设置sockopt(sock,IPPROTO_IP,IP_MULTICAST_if,
(地址中的结构*)和接口地址,
sizeof(接口地址sin地址)小于0{
perror(“setsockopt if”);
退出(退出失败);
}
if(setsockopt(sock、SOL_SOCKET、SO_BROADCAST和bcast、sizeof(bcast))<0){
perror(“setsockopt bcast”);
退出(退出失败);
}
结构ip_mreqn imr;
memset(&imr,0,sizeof(imr));
if(inet\u pton(AF\u inet,“239.255.255.250”,&imr.imr\u multiaddr.s\u addr)<1){
perror(“inet_pton”);
退出(退出失败);
}
inet地址(AF inet,“127.0.0.1”,(地址中的结构*)和imr.imr\u地址);
imr.imr_iIndex=0;
如果(设置SOCKOPT)(sock、IPPROTO、IP添加成员资格,
(无效*)&imr,sizeof(imr))<0){
perror(“setsockopt addmem”);
退出(退出失败);
}
如果(绑定(sock,(结构sockaddr*)和接口地址,
sizeof(结构sockaddr_in))<0){
佩罗(“绑定”);
退出(退出失败);
}
字符缓冲区[1024];
strcpy(缓冲区,“M-SEARCH*HTTP/1.1\r\n”
“主机:239.255.255.250:1900\r\n”
“男子:\“ssdp:发现\”\r\n”
“ST:upnp:rootdevice\r\n”
“MX:3\r\n”
“用户代理:测试/1.0\r\n”
“\r\n”);
if(sendto(sock、buffer、strlen(buffer)、0、(struct sockaddr*)和destadd,
sizeof(destadd))<0){
perror(“sendto”);
退出(退出失败);
}
if(recvfrom(sock,&buffer,sizeof(buffer)-1,0,NULL,NULL)<0){
perror(“recvfrom”);
退出(退出失败);
}
如果(关闭(袜子)<0){
perror(“关闭”);
退出(退出失败);
}
}

最后为我工作的代码如下

方法概述:

  • 创建UDP套接字
  • 启用IF_多播_循环(允许与同一主机上的客户端通信)
  • 设置IF\u多播\u TTL
  • 绑定到INADDR_ANY和端口8201(任意选择端口号)
  • 发送多播消息至239.255.255.250:1900
  • 使用相同的套接字接收回复
我们开始:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char ** argv ) {

unsigned char loop;
loop = 1; // Needs to be on to get replies from clients on the same host
unsigned char ttl;
ttl = 4;
int bcast;
bcast = 1;

int sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
    perror("socket");
    exit(EXIT_FAILURE);
}

// Multicast message will be sent to 239.255.255.250:1900
struct sockaddr_in destadd;
memset(&destadd, 0, sizeof(destadd));
destadd.sin_family = AF_INET;
destadd.sin_port = htons((uint16_t)1900);
if (inet_pton(AF_INET, "239.255.255.250", &destadd.sin_addr) < 1) {
    perror("inet_pton dest");
    exit(EXIT_FAILURE);
}

// Listen on all interfaces on port 8201 
struct sockaddr_in interface_addr;
memset(&interface_addr, 0, sizeof(interface_addr));
interface_addr.sin_family = AF_INET;
interface_addr.sin_port = htons(8201);
interface_addr.sin_addr.s_addr = htonl(INADDR_ANY);

// Got to have this to get replies from clients on same machine
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0){
    perror("setsockopt loop");
    exit(EXIT_FAILURE);
}

if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0){
    perror("setsockopt ttl");
    exit(EXIT_FAILURE);
}

// Bind to port 8201 on all interfaces
if (bind(sock, (struct sockaddr *)&interface_addr,
    sizeof(struct sockaddr_in)) < 0) {
    perror("bind");
    exit(EXIT_FAILURE);
}

char buffer[1024];

strcpy(buffer, "M-SEARCH * HTTP/1.1\r\n"
               "Host: 239.255.255.250:1900\r\n"
               "Man: \"ssdp:discover\"\r\n"
               "ST: upnp:rootdevice\r\n"
               "MX: 3\r\n"
               "User-Agent: Test/1.0\r\n"
               "\r\n");

if (sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&destadd,
       sizeof(destadd)) < 0) {
    perror("sendto");
    exit(EXIT_FAILURE);
}

if (recvfrom(sock, &buffer, sizeof(buffer)-1, 0, NULL, NULL) < 0) {
    perror("recvfrom");
    exit(EXIT_FAILURE);
}


printf("%s\n", buffer);

if (close(sock) < 0) {
    perror("close");
    exit(EXIT_FAILURE);
}
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
无符号字符循环;
loop=1;//需要启用才能从同一主机上的客户端获取答复
无符号字符ttl;
ttl=4;
int-bcast;
bcast=1;
int袜子;
sock=插座(AF_INET,sock DGRAM,0);
if(sock<0){
佩罗(“插座”);
退出(退出失败);
}
//多播消息将发送到239.255.255.250:1900
destadd中的结构sockaddr_;
memset(&destadd,0,sizeof(destadd));
destadd.sin_family=AF_INET;
destadd.sin_port=htons(uint16_t)1900);
if(inet\u pton(AF\u inet,“239.255.255.250”&destadd.sin\u addr)<1){
perror(“inet_pton dest”);
退出(退出失败);
}
//侦听端口8201上的所有接口
接口地址中的结构sockaddr\u;
memset(&interface_addr,0,sizeof(interface_addr));
接口地址sin系列=AF\U INET;
接口地址sin端口=htons(8201);
接口地址sin地址s地址=htonl(INADDR\U ANY);
//必须有这个才能从同一台机器上的客户端获得回复
if(setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&LOOP,sizeof(LOOP))<0){
perror(“setsockopt循环”);
退出(退出失败);
}
if(setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,&TTL,sizeof(TTL))<0){
perror(“setsockopt ttl”);
退出(退出失败);
}
//绑定到所有接口上的端口8201
如果(绑定(sock,(结构sockaddr*)和接口地址,
sizeof(结构sockaddr_in))<0){
佩罗(“绑定”);
退出(退出失败);
}
字符缓冲区[1024];
strcpy(缓冲区,“M-SEARCH*HTTP/1.1\r\n”
“主机:239.255.255.250:1900\r\n”
“男子:\“ssdp:发现\”\r\n”
“ST:upnp:rootdevice\r\n”
“MX:3\r\n”
“用户代理:测试/1.0\r\n”
“\r\n”);
if(sendto(sock、buffer、strlen(buffer)、0、(struct sockaddr*)和destadd,
sizeof(destadd))<0){
perror(“sendto”);
退出(退出)