我的情况如下: 我有一台运行UDP多播服务器的Windows机器正在广播数据包。我编写了一个窗口客户端,能够在连接到网络的单独Windows机器上捕获这些数据包而不会出现问题。我在Windows机器上遇到了一些防火墙问题,但是解决了这个问题。
现在,我有一个ubuntu 12.04版本的客户端;但是,我的程序没有找到这些数据包。我浏览了其他堆栈溢出帖子和一些谷歌线程提供的所有建议:
对于第四步,这是通过wlan0建立的无线连接,所以我在wlan0上添加路由。同样,wlan0' rp_filter = 0。
现在,代码。从打印语句和错误检查。我看到我成功绑定,加入多播组,创建缓冲区等...然后它只是阻塞recvfrom()函数调用。
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <fstream>
#pragma warning( disable : 4996 )
#define MAX_PACKETSIZE 100000 // max size of packet (actual packet size is dynamic)
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address);
void Unpack(char* pData);
#define MULTICAST_ADDRESS "239.255.42.99" // IANA, local network
#define PORT_COMMAND 1510
#define PORT_DATA 1511
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
typedef int SOCKET;
SOCKET DataSocket;
int main(int argc, char* argv[])
{
int retval;
char szMyIPAddress[128] = "";
in_addr MyAddress, MultiCastAddress;
int optval = 0x100000;
int optval_size = 4;
// client address
if(argc>1)
{
strcpy(szMyIPAddress, argv[1]); // specified on command line
IPAddress_StringToAddr(szMyIPAddress, &MyAddress);
}
else
{ printf("usage: ./client [local_ip_address]\n"); return 0; }
MultiCastAddress.s_addr = inet_addr(MULTICAST_ADDRESS);
printf("Client: %s\n", szMyIPAddress);
printf("Multicast Group: %s\n", MULTICAST_ADDRESS);
// create a "Data" socket
printf("Create Socket.\n");
DataSocket = socket(AF_INET, SOCK_DGRAM, 0);
// allow multiple clients on same machine to use address/port
int value = 1;
printf("Set SO_REUSEADDR sockopt.\n");
retval = setsockopt(DataSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value));
if (retval == SOCKET_ERROR)
{
close(DataSocket);
return -1;
}
//bind
struct sockaddr_in MySocketAddr;
memset(&MySocketAddr, 0, sizeof(MySocketAddr));
MySocketAddr.sin_family = AF_INET;
MySocketAddr.sin_port = htons(PORT_DATA);
MySocketAddr.sin_addr = MyAddress;
printf("Bind Socket.\n");
if (bind(DataSocket, (struct sockaddr *)&MySocketAddr, sizeof(struct sockaddr)) == SOCKET_ERROR)
{
printf("[PacketClient] bind failed.\n");
return 0;
}
// join multicast group
struct ip_mreq Mreq;
Mreq.imr_multiaddr = MultiCastAddress;
Mreq.imr_interface = MyAddress;
printf("Join multicast group.\n");
retval = setsockopt(DataSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&Mreq, sizeof(Mreq));
if (retval == SOCKET_ERROR)
{
printf("[PacketClient] join failed.\n");
return -1;
}
// create a 1MB buffer
printf("Create 1MB Buffer.\n");
setsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, 4);
getsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, (socklen_t*)&optval_size);
if (optval != 0x100000)
{
printf("[PacketClient] ReceiveBuffer size = %d\n", optval);
}
//listening
printf("Listening...\n");
char szData[20000];
int addr_len = sizeof(struct sockaddr);
sockaddr_in TheirAddress;
while (1)
{
// Block until we receive a datagram from the network (from anyone including ourselves)
int nDataBytesReceived = recvfrom(DataSocket, szData, sizeof(szData), 0, (sockaddr *)&TheirAddress, (socklen_t*)&addr_len);
Unpack(szData);
}
return 0;
}
// convert ipp address string to addr
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address)
{
int retVal;
struct sockaddr_in saGNI;
char hostName[256];
char servInfo[256];
u_short port;
port = 0;
// Set up sockaddr_in structure which is passed to the getnameinfo function
saGNI.sin_family = AF_INET;
saGNI.sin_addr.s_addr = inet_addr(szNameOrAddress);
saGNI.sin_port = htons(port);
// getnameinfo
if ((retVal = getnameinfo((sockaddr *)&saGNI, sizeof(sockaddr), hostName, 256, servInfo, 256, NI_NUMERICSERV)) != 0)
{
printf("[PacketClient] GetHostByAddr failed.\n");
return false;
}
Address->s_addr = saGNI.sin_addr.s_addr;
return true;
}
void Unpack(char* pData)
{
printf("Begin Packet\n-------\n");
}
任何建议都表示赞赏。以下是我在尝试解决此问题时用作参考的问题:UDP socket (multicast) not receiving data (Ubuntu)
答案 0 :(得分:0)
我在这里粘贴我的答案,而不是在评论中写下来。
据我所知,你们两边都有Windows机器,成功播放udp数据包,现在你想用ubuntu机器替换它们。并且机器正在接收数据包,但不会通知您的客户端。
也许这会有所帮助
SOL_SOCKET用于套接字层,IPPROTO_IP用于IP层等...对于多播编程,级别始终为IPPROTO_IP
以下是简化的RIPv2协议的工作代码,可以毫无问题地发送和重新发送多播流量。
int setup_sender_connection(struct in_addr interface_addr){
//create socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock<0){
die("Creating Socket");
}
//set outgoing interface
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr))<0){
die("Setting outgoing interface");
}
//disable loopback
u_char loop = 0;
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))<0){
die("Disabling loopback");
}
//allow reusing of port
int reuse = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0){
die("Allowing reuse");
}
//bind to this port
struct sockaddr_in saddr;
bzero(&saddr, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(520);
saddr.sin_addr = interface_addr;
if(bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))<0){
die("Binding");
}
return sock;
}
void join_group(int sock, struct in_addr interface_addr){
//join gorup
struct ip_mreq mreq;
bzero(&mreq, sizeof(struct ip_mreq));
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP); /* IP multicast address of group */
mreq.imr_interface = interface_addr; /* local IP address of interface */
if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))<0){
die("Joining group");
}
}
void die(char *error){
perror(error);
exit(1);
}