服务器代码:
#define EXAMPLE_PORT 6000
#define EXAMPLE_GROUP "239.0.0.1"
int main(int argc, char **argv) {
struct sockaddr_in addr;
int sock;
ssize_t cnt;
struct ip_mreq mreq;
char message[50];
socklen_t addrlen;
/* set up socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return(1);
}
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(EXAMPLE_PORT);
addrlen = sizeof(addr);
/* send */
addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP);
while (1) {
time_t t = time(0);
sprintf(message, "time is %-24.24s", ctime(&t));
printf("sending: %s\n", message);
cnt = sendto(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, addrlen);
if (cnt < 0) {
perror("sendto");
return (1);
}
sleep(5);
}
return 0;
}
客户端代码:
#define EXAMPLE_PORT 6000
#define EXAMPLE_GROUP "239.0.0.1"
int main(int argc, char **argv) {
if (argc < 2)
return 1;
const char *ip_addr = argv[1];
struct sockaddr_in addr;
int sock;
socklen_t addrlen;
ssize_t cnt;
struct ip_mreq mreq;
char message[50];
/* set up socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return(1);
}
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip_addr); // *
addr.sin_port = htons(EXAMPLE_PORT);
addrlen = sizeof(addr);
/* receive */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind");
return (1);
}
mreq.imr_multiaddr.s_addr = inet_addr(EXAMPLE_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
perror("setsockopt mreq");
return (1);
}
while (1) {
cnt = recvfrom(sock, message, sizeof(message), 0,
(struct sockaddr *) &addr, &addrlen);
if (cnt < 0) {
perror("recvfrom");
return (1);
} else if (cnt == 0) {
break;
}
printf("%s: message = \"%s\"\n", inet_ntoa(addr.sin_addr), message);
}
return 0;
}
问:我可以在同一台机器上运行多个客户端吗?现在我不能这样做,因为第二个客户端的启动以错误结束address already in use。
(*) 之前想用特定接口的IP地址绑定socket,是这样的:
addr.sin_addr.s_addr = htonl(INADDR_ANY);
默认情况下,操作系统不允许您为不同的应用程序使用相同的端口地址。但有时它是非常非常必要的。例如,如果我们的这个应用程序已经崩溃并且我们重新启动它,那么我们不需要写“使用中的地址” - 我们已经知道这一点(操作系统不会立即释放套接字以便旧数据包不会到达新申请)。
好的,你如何“修复”它?
其实也有SO_REUSEPORT,但是文章https://lwn.net/Articles/542629/指出SO_REUSEADDR包括SO_REUSEPORT