问题描述
我想在本地广播消息到许多应用程序.为此,我认为UDP插座是最好的IPC,如果我佩戴的话,请纠正我.
为此,我正在使用以下代码:
广播:
/* ** broadcaster.c -- a datagram "client" that can broadcast */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define SERVERPORT 4950 // the port users will be connecting to int main(int argc, char *argv[]) { int sockfd; struct sockaddr_in their_addr; // connector's address information struct hostent *he; int numbytes; int broadcast = 1; //char broadcast = '1'; // if that doesn't work, try this if (argc != 3) { fprintf(stderr,"usage: broadcaster hostname message\n"); exit(1); } if ((he=gethostbyname(argv[1])) == NULL) { // get the host info perror("gethostbyname"); exit(1); } if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1); } // this call is what allows broadcast packets to be sent: if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1) { perror("setsockopt (SO_BROADCAST)"); exit(1); } their_addr.sin_family = AF_UNIX; // host byte order their_addr.sin_port = htons(SERVERPORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof their_addr)) == -1) { perror("sendto"); exit(1); } printf("sent %d bytes to %s\n", numbytes, inet_ntoa(their_addr.sin_addr)); close(sockfd); return 0; }
和听:
/* ** listener.c -- a datagram sockets "server" demo */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define MYPORT "4950" // the port users will be connecting to #define MAXBUFLEN 100 // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(void) { int sockfd; struct addrinfo hints, *servinfo, *p; int rv; int numbytes; struct sockaddr_storage their_addr; char buf[MAXBUFLEN]; socklen_t addr_len; char s[INET6_ADDRSTRLEN]; int optval = 1; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4 hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("listener: socket"); continue; } if(setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, &optval, sizeof optval) != 0) { perror("listener: setsockopt"); continue; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("listener: bind"); continue; } break; } if (p == NULL) { fprintf(stderr, "listener: failed to bind socket\n"); return 2; } freeaddrinfo(servinfo); printf("listener: waiting to recvfrom...\n"); addr_len = sizeof their_addr; if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) { perror("recvfrom"); exit(1); } printf("listener: got packet from %s\n", inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s)); printf("listener: packet is %d bytes long\n", numbytes); buf[numbytes] = '\0'; printf("listener: packet contains \"%s\"\n", buf); close(sockfd); return 0; }
问题在于我必须像这样的192.168.1.255这样的IP,但是在实际情况下,可能没有ETH0接口,只会有环回.那我该如何实现?
推荐答案
服务器不应绑定到您从getaddrinfo获得的地址,而应绑定到127.255.255.255(对于环回接口).
有关广播服务器/客户端的现成示例,请参见 http:///www.ccplusplus.com/2011/09/udp-broadcast-client-server-example.html
其他推荐答案
Unix域插座不支持多/广播.
您可以在本地接口127.0.0.1.
上广播其他推荐答案
虽然原始问题没有明确说明,但我相信原始的Asker想要"广播"到在同一操作系统实例上运行的多个应用程序(相同的计算机到旧计时器).
在听众示例中使用" so_reuseaddr"和Yuvi的后续评论,最终提出了使用IP Multicast的建议.
应澄清原始问题.
我相信,使用SO_REUSEADDR时,单个UDP端口上具有多重界限的数据包分布在操作系统之间有所不同. 我在最近的Windows上的经验是,一个单一的"活页夹"专门赋予所有数据包,直到她释放绑定为止,此时,选择了另一个粘合剂并呈现了所有粘合剂,直到她释放出来,等等...
这显然与最近的Linux内核不同,如以下链接中所述: 该页面似乎声称Linux将在多个Binders之间接收数据包.
最终结果,如果您希望像原始海报一样使用单个send-datagram发送到多个,并且您尝试使用IP Unicast而不是IP Multicast,那么您可能会感到失望. (我的经验以及上面的链接显示您可以多绑住,但这并不意味着收到的数据报的多递送,既不在Linux或Windows上)
)原始海报应该尝试使用多播.