在写聊天室程序时,遇到一个组播问题,不能在不同主机上进行发送接收消息。。。
深究发现,是本人对sendto与recvfrom的理解太浅薄。
以下代码发送端与接收端可在同一主机,也可在不同主机上运行。
代码直接编译运行即可。
程序为练习程序,比较难堪,勿怪。
确定是在局域网内。。
不能运行可试着关闭防火墙。。。
以下例子,发送端只能发送消息,接收端只能接收消息。
若两台主机都加入组播组的话,那么它们都能收发消息。代码就不写了
发送端:(此主机未加入组播组)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXBUF 30
#define PORT 5000
char multicast_addr[] = "224.0.1.1 ";
int main(int argc, char *argv[]) {
int s;
char name[MAXBUF] = { '\0' };
struct sockaddr_in srv, mcast;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Opening socket ");
return 0;
}
memset(&srv, 0, sizeof(srv));
srv.sin_family = AF_INET;
srv.sin_port = htons(PORT);
srv.sin_addr.s_addr = htonl(INADDR_ANY);
memset(&mcast, 0, sizeof(mcast));
mcast.sin_port = htons(PORT);
mcast.sin_family = AF_INET;
mcast.sin_addr.s_addr = inet_addr(multicast_addr);
int opt = SO_REUSEADDR;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (bind(s, (struct sockaddr*) &srv, sizeof(srv)) < 0) {
perror("bind ");
return 0;
}
/*发送端无需加入组播组,所以以下注释语句可以不要
mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt: IP_ADD_MEMBERSHIP ");
return 0;
}
*/
while (1) {
fgets(name, MAXBUF, stdin);
sendto(s, name, strlen(name), 0, (struct sockaddr*) &mcast, sizeof(mcast));
//此处是mcast!!切记!!
perror("sendto");
}
return 1;
}
接收端:(此主机加入组播组)
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define MAXBUF 30
#define PORT 5000
char multicast_addr[] = "224.0.1.1 ";
int main(int argc, char *argv[]) {
int s, n;
char name[MAXBUF] = { '\0' };
struct sockaddr_in srv;
socklen_t srv_len = sizeof(srv);
struct ip_mreq mreq;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Opening socket ");
return 0;
}
memset(&srv, 0, sizeof(srv));
srv.sin_family = AF_INET;
srv.sin_port = htons(PORT);
srv.sin_addr.s_addr = htonl(INADDR_ANY);
int opt = SO_REUSEADDR;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (bind(s, (struct sockaddr*) &srv, sizeof(srv)) < 0) {
perror("bind ");
return 0;
}
mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt: IP_ADD_MEMBERSHIP ");
return 0;
}
while (1) {
n = recvfrom(s, name, MAXBUF, 0, (struct sockaddr*) &srv, &srv_len);
//此处是srv,切记!!!
perror("recvfrom");
name[n] = '\0';
fputs(name, stdout);
}
return 1;
}