跟着《UNIX网络编程》书上的例程写了一个UDP广播的例子,接收到的服务器IP随机变化,最终发现recvfrom();最后一个参数在传递之前必须赋值 from_len = sizeof(struct sockaddr);否则接收到的对方地址不全!
下面代码
server.c:
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <time.h>#define IP_FOUND "IP_FOUND"
#define IP_FOUND_ACK "IP_FOUND_ACK"
#define MAST_PORT 8888void main(void *arg)
{
#define BUFFER_LEN 32
int ret = -1;
int sock = -1;
struct sockaddr_in local_addr;
struct sockaddr_in from_addr;
int from_len;
int count = -1;
fd_set readfds;
char buff[BUFFER_LEN] = {0};
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;printf("====>HandleIPFound\n");
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
printf("HandleIPFound: sock init error\n");
return;
}
int reuse = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
return;
}bzero(&local_addr, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(MAST_PORT);ret = bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr));
if(ret != 0)
{
printf("HandleIPFound: bind error\n");
return;
}while(1)
{
FD_ZERO(&readfds);
FD_SET(sock, &readfds);timeout.tv_sec = 2;
timeout.tv_usec = 0;ret = select(sock + 1, &readfds, NULL, NULL, &timeout);
switch (ret)
{
case -1:
break;
case 0:
printf("timeout\n");
break;
default:
if(FD_ISSET(sock, &readfds))
{
from_len = sizeof(from_addr);
count = recvfrom(sock, buff, BUFFER_LEN, 0, (struct
sockaddr *)&from_addr, &from_len);
printf("Recv msg is %s\n", buff);if(strstr(buff, IP_FOUND))
{
memcpy(buff, IP_FOUND_ACK, strlen(IP_FOUND_ACK) + 1);
printf("send msg to client\n");
from_len = sizeof(from_addr);
count = sendto(sock, buff, strlen(buff), 0, (struct sockaddr*)&from_addr, from_len);
}
else
{
printf("not equal with IP_FOUND\n");
}
}
}
}
printf("<===HandleIPFound\n");
return;
}
client.c
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <time.h>
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>#define IP_FOUND "IP_FOUND"
#define IP_FOUND_ACK "IP_FOUND_ACK"
#define IFNAME "eth0"
#define MCAST_PORT 8888void main(void *arg)
{
#define BUFFER_LEN 32
int ret = -1;
int sock = -1;
int so_broadcast = 1;
struct ifreq ifr;
struct sockaddr_in broadcast_addr;
struct sockaddr_in from_addr;
int from_len;
int count = -1;
fd_set readfd;
char buff[BUFFER_LEN] = {0};
struct timeval timeout;
timeout.tv_sec = 20;
timeout.tv_usec = 0;sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
printf("HandleIPFound: socket init error\n");
return;
}
strcpy(ifr.ifr_name, IFNAME);
if(ioctl(sock, SIOCGIFBRDADDR, &ifr) == -1)
perror("ioctl error"), exit(1);
memcpy(&broadcast_addr, &ifr.ifr_broadaddr, sizeof(struct sockaddr_in));
broadcast_addr.sin_port = htons(MCAST_PORT);ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so_broadcast,
sizeof(so_broadcast));int times = 10;
int i = 0;
for(i = 0; i < times; i++)
{
ret = sendto(sock, IP_FOUND, strlen(IP_FOUND), 0, (struct sockaddr*)
&broadcast_addr, sizeof(broadcast_addr));
if(ret == -1)
{
continue;
}FD_ZERO(&readfd);
FD_SET(sock, &readfd);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
ret = select(sock + 1, &readfd, NULL, NULL, &timeout);
switch(ret)
{
case -1:
break;
case 0:
printf("time out\n");
break;
default:
if(FD_ISSET(sock, &readfd))
{
from_len = sizeof(from_addr);
count = recvfrom(sock, buff, BUFFER_LEN, 0, (struct sockaddr*)&from_addr, &from_len);
printf("Client Recv msg is %s\n", buff);
if(strstr(buff, IP_FOUND_ACK))
{
printf("Client found server, IP is %s\n", inet_ntoa(from_addr.sin_addr));
break;
}
}
}
}
return;
}