Here are some trivial examples of working SSM code. They certainly work under LinuxKernel2.6, and have been tested on amd64 in Gentoo and on ia32 DebianLinux. It's possible that SSM is not supported in Linux 2.4. The examples join the SSM group ip-of-sender, 232.1.1.1. In a real application you should randomly select the 232.0.0.0/8 address at runtime to avoid conflicts.
Note that some information is included in #ifndefs since many LinuxDistributions don't install the required header files yet.
I had one major problem while trying to debug this. My mistake was that the reciever wasn't binding to INADDR_ANY for the listening socket, but instead to an IP address on the machine. This caused all the multicast packets to be ignored. Oops.
Another bug was due to the server using the SSM source of the unassigned address. Oops.
-
Sender:
-
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <unistd.h> /* Not everyone has the headers for this so improvise */ #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req { /* Interface index. */ uint32_t gsr_interface; /* Group address. */ struct sockaddr_storage gsr_group; /* Source address. */ struct sockaddr_storage gsr_source; }; #endif int main(int argc, char *argv[]) { struct group_source_req group_source_req; struct sockaddr_in *group; struct sockaddr_in *source; int fd = socket(AF_INET,SOCK_DGRAM,getprotobyname("udp")->p_proto); socklen_t socklen = sizeof(struct sockaddr_storage); struct sockaddr_in bindaddr; u_char loop = 1; /* First bind to the port */ bindaddr.sin_family = AF_INET; bindaddr.sin_port = htons(9990); bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd,(struct sockaddr*)&bindaddr,sizeof(bindaddr)); /* Now set up the SSM request */ group_source_req.gsr_interface = 0; /* "any" interface */ group=(struct sockaddr_in*)&group_source_req.gsr_group; source=(struct sockaddr_in*)&group_source_req.gsr_source; group->sin_family = AF_INET; inet_aton("232.1.1.1",&group->sin_addr); group->sin_port = 0; /* Ignored */ /* Set the source to the name of the socket we created above */ getsockname(fd,(struct sockaddr *)source, &socklen); setsockopt(fd,SOL_IP,MCAST_JOIN_SOURCE_GROUP, &group_source_req, sizeof(group_source_req)); /* Enable reception of our own multicast */ loop = 1; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); /* Set the TTL on packets to 250 */ loop=250; setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &loop, sizeof(loop)); /* Now we care about the port we send to */ group->sin_port = htons(9991); /* Now send packets */ while(1) { sendto(fd,"Hello World",strlen("Hello World"),0, (struct sockaddr*)group,sizeof(struct sockaddr_in)); sleep(1); } return 0; }
Receiver:
-
Pass the IP address of the sender as CommandLine argument: ./ssm-rec ip.address.of.sender
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> /* Not everyone has the headers for this, so improvise */ #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req { /* Interface index. */ uint32_t gsr_interface; /* Group address. */ struct sockaddr_storage gsr_group; /* Source address. */ struct sockaddr_storage gsr_source; }; #endif int main(int argc, char *argv[]) { struct group_source_req group_source_req; struct sockaddr_in *group; struct sockaddr_in *source; int fd = socket(AF_INET,SOCK_DGRAM,getprotobyname("udp")->p_proto); struct sockaddr_in bindaddr; /* Setup the socket to listen on */ bindaddr.sin_family = AF_INET; bindaddr.sin_port = htons(9991); bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(fd,(struct sockaddr*)&bindaddr,sizeof(bindaddr)); /* Set up the connection to the group */ group_source_req.gsr_interface = 0; group=(struct sockaddr_in*)&group_source_req.gsr_group; source=(struct sockaddr_in*)&group_source_req.gsr_source; /* Group is 232.1.1.1 */ group->sin_family = AF_INET; inet_aton("232.1.1.1",&group->sin_addr); group->sin_port = 0; /* Source is 10.1.20.9 */ source->sin_family = AF_INET; inet_aton(argv[1],&source->sin_addr); source->sin_port = 0; setsockopt(fd,SOL_IP,MCAST_JOIN_SOURCE_GROUP, &group_source_req, sizeof(group_source_req)); while(1) { char buffer[65536]; int ret=recv(fd,(char*)buffer,sizeof(buffer),0); write(1,buffer,ret); } return 0; }
Python:
-
#! /usr/bin/python import getopt import socket import sys if not hasattr(socket, 'IP_MULTICAST_TTL'): setattr(socket, 'IP_MULTICAST_TTL', 33) if not hasattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP'): setattr(socket, 'IP_ADD_SOURCE_MEMBERSHIP', 39) if sys.argv[1] == 'send': opts, args = getopt.getopt(sys.argv[2:], 't:s:g:p:') opts = dict(opts) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) if '-t' in opts: s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, chr(int(opts['-t']))) if '-s' in opts: s.bind((opts['-s'], 0)) s.connect((opts['-g'], int(opts['-p']))) print 'READY.' while True: s.send(sys.stdin.readline()) elif sys.argv[1] == 'recv': opts, args = getopt.getopt(sys.argv[2:], 'g:i:s:p:') opts = dict(opts) opts.setdefault('-i', '0.0.0.0') imr = (socket.inet_pton(socket.AF_INET, opts['-g']) + socket.inet_pton(socket.AF_INET, opts['-i']) + socket.inet_pton(socket.AF_INET, opts['-s'])) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) s.setsockopt(socket.SOL_IP, socket.IP_ADD_SOURCE_MEMBERSHIP, imr) s.bind((opts['-g'], int(opts['-p']))) print 'READY.' while True: print repr(s.recvfrom(4096))
本文提供了一组简单的SSM(源特定多播)代码示例,这些示例适用于Linux Kernel 2.6及更高版本,并已在amd64 Gentoo和ia32 Debian Linux上进行了测试。示例包括发送者、接收者以及Python实现,展示了如何设置SSM连接并进行组播数据传输。

3286

被折叠的 条评论
为什么被折叠?



