服务端代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#define SERV_PORT 16002
#define BUFSIZE 4096
static void sig_child(int signo) {
int pid;
while ((pid = waitpid(-1,NULL,WNOHANG)) > 0) {
printf("child process: %d terminated\n",pid);
}
}
struct group_if {
struct ifreq* gr_if;
unsigned int gr_ifcount;
};
void* Malloc(size_t n) {
void* ptr;
if ((ptr = malloc(n)) == NULL) {
printf("Malloc error: %s\n",strerror(errno));
exit(1);
}else {
return ptr;
}
}
void* Calloc(size_t n,size_t size) {
void* ptr;
if ((ptr = calloc(n,size)) == NULL) {
printf("calloc error: %s\n",strerror(errno));
exit(1);
}else {
return ptr;
}
}
struct group_if get_group_if() {
int sockfd;
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
printf("group_if-get_if-error: %s\n",strerror(errno));
exit(1);
}
char* buf;
size_t lastlen = 0;
size_t newlen = 10 * sizeof(struct ifreq);
struct ifconf ifc;
for (; ;) {
buf = Malloc(newlen);
ifc.ifc_len = newlen;
ifc.ifc_buf = buf;
if (ioctl(sockfd,SIOCGIFCONF,&ifc) < 0) {
if (errno != EINVAL || lastlen != 0) {
printf("ioctl error: %s\n",strerror(errno));
exit(1);
}
}else {
if (lastlen == ifc.ifc_len) {
break;
}
}
lastlen = ifc.ifc_len;
newlen += 10 * sizeof(struct ifreq);
free(buf);
}
struct group_if ret;
size_t count = ifc.ifc_len / sizeof(struct ifreq);
ret.gr_if = Calloc(count,sizeof(struct ifreq));
memcpy(ret.gr_if,buf,ifc.ifc_len);
free(buf);
ret.gr_ifcount = count;
return ret;
}
const char* Inet_ntop(void* ptr) {
static char str[INET_ADDRSTRLEN];
return inet_ntop(AF_INET,ptr,str,INET_ADDRSTRLEN);
}
void free_group_if(struct group_if grif) {
if (grif.gr_if != NULL) {
free(grif.gr_if);
}
}
void server_echo(int sockfd) {
char recv[BUFSIZE];
ssize_t n;
struct sockaddr_in clientaddr;
socklen_t len = sizeof(struct sockaddr_in);
for (; ;) {
if ((n = recvfrom(sockfd,recv,BUFSIZE,0,(struct sockaddr*)&clientaddr,&len)) < 0) {
printf("recvfrom error: %s\n",strerror(errno));
exit(1);
}
printf("from IP: %s\n",Inet_ntop(&clientaddr.sin_addr));
if (sendto(sockfd,recv,n,0,(struct sockaddr*)&clientaddr,len) != n) {
printf("send to client error: %s\n",strerror(errno));
exit(1);
}
}
}
int main(int argc,char ** argv) {
int sockfd;
const int on = 1;
pid_t pid;
struct group_if grif = get_group_if();
struct sockaddr_in* sa,wild;
struct ifreq* dummy = grif.gr_if;
if (signal(SIGCHLD,sig_child) == SIG_ERR) {
printf("signal error: %s\n",strerror(errno));
exit(1);
}
for (size_t i = 1; i <= grif.gr_ifcount; ++i) {
if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
printf("main-socket error: %s\n",strerror(errno));
exit(1);
}
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
printf("setsockopt error: %s\n",strerror(errno));
exit(1);
}
if (ioctl(sockfd,SIOCGIFADDR,dummy) < 0) {
printf("ioctl error: %s\n",strerror(errno));
exit(1);
}
sa = (struct sockaddr_in*) &dummy->ifr_addr;
sa->sin_family = AF_INET;
sa->sin_port = htons(SERV_PORT);
if (bind(sockfd,(struct sockaddr*)sa,sizeof(struct sockaddr_in)) < 0) {
printf("bind error: %s\n",strerror(errno));
exit(1);
}
printf("bound interface: %s ip-address: %s\n",dummy->ifr_name,Inet_ntop(&sa->sin_addr));
if ((pid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (pid == 0){
server_echo(sockfd);
exit(0);
}
if (ioctl(sockfd,SIOCGIFFLAGS,dummy) < 0) {
printf("ioctl-SIOCGIFFLAGS error: %s\n",strerror(errno));
exit(1);
}
if (dummy->ifr_flags & IFF_BROADCAST) {
if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
printf("socket error: %s\n",strerror(errno));
exit(1);
}
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
printf("setsockopt error: %s\n",strerror(errno));
exit(1);
}
if (ioctl(sockfd,SIOCGIFBRDADDR,dummy) < 0) {
printf("ioctl-SIOCGIFBRDADDR error: %s\n",strerror(errno));
exit(1);
}
sa = (struct sockaddr_in*) &dummy->ifr_broadaddr;
sa->sin_family = AF_INET;
sa->sin_port = htons(SERV_PORT);
if (bind(sockfd,(struct sockaddr*)sa,sizeof(struct sockaddr_in)) < 0) {
if (errno == EADDRINUSE) {
printf("EADDRINUSE: %s\n",Inet_ntop(&sa->sin_addr));
close(sockfd);
continue;
}else {
printf("bind error: %s\n",strerror(errno));
exit(1);
}
}
printf("bound interface: %s broadcast-ip-address: %s\n",dummy->ifr_name,Inet_ntop(&sa->sin_addr));
if ((pid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (pid == 0) {
server_echo(sockfd);
exit(0);
}
}
dummy++;
}
free_group_if(grif);
if ((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
printf("sockfd error: %s\n",strerror(errno));
exit(1);
}
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
printf("setsockopt error: %s\n",strerror(errno));
exit(1);
}
wild.sin_addr.s_addr = htonl(INADDR_ANY);
wild.sin_family = AF_INET;
wild.sin_port = htons(SERV_PORT);
if (bind(sockfd,(struct sockaddr*)&wild,sizeof(struct sockaddr_in)) < 0) {
printf("bind wild-address error: %s\n",strerror(errno));
exit(1);
}
printf("bound wild-address %s\n",Inet_ntop(&wild.sin_addr));
if ((pid = fork()) < 0) {
printf("fork error: %s\n",strerror(errno));
exit(1);
}else if (pid == 0) {
server_echo(sockfd);
exit(0);
}else {
for (; ;) {
}
}
return 0;
}
客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#define BUFSIZE 4096
void client_echo(int sockfd,struct sockaddr* to,socklen_t tolen) {
char send[BUFSIZE];
ssize_t n;
struct sockaddr_in clientaddr;
const int on = 1;
socklen_t len = sizeof(struct sockaddr_in);
if (setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)) < 0) {
printf("setsockopt error: %s\n",strerror(errno));
exit(1);
}
while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) {
if (sendto(sockfd,send,n,0,to,tolen) != n) {
printf("sendto error: %s\n",strerror(errno));
exit(1);
}
if (recvfrom(sockfd,send,BUFSIZE,0,(struct sockaddr*)&clientaddr,&len) != n) {
printf("recv from server error: %s\n",strerror(errno));
exit(1);
}
if (write(STDOUT_FILENO,send,n) != n) {
printf("write error: %s\n",strerror(errno));
exit(1);
}
}
}
int main(int argc,char** argv) {
if (argc != 3) {
printf("please add <ip address-host name> <service name or port name>\n");
exit(1);
}
struct addrinfo hints;
bzero(&hints,sizeof(struct addrinfo));
hints.ai_flags = AI_ALL;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
struct addrinfo* results;
int err;
if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) {
printf("getaddrinfo error: %s\n",gai_strerror(err));
exit(1);
}
struct addrinfo* dummy = results;
int sockfd;
for (; dummy != NULL; dummy = dummy->ai_next) {
if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) {
continue;
}else {
break;
}
}
if (dummy == NULL) {
freeaddrinfo(results);
printf("all socket failed\n");
exit(1);
}
client_echo(sockfd,dummy->ai_addr,dummy->ai_addrlen);
freeaddrinfo(results);
}