/* * File: UDPEchoClient-TimeOut.c * Author: 云守护 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include "DieWithMessage.h"//超时设置static const unsigned int TIMEOUT_SEC=3;//重连次数static const unsigned int MAXTRIES=5;//已经尝试次数unsigned int tries=0;//闹铃到来处理函数,超时时间到void CatchAlarm(int ignored);int main(int argc, char** argv) { if(argc<3||argc>4) DieWithUserMessage("param","<Server Address/Name> <Echo Word> [<Server port/service>]\n"); char *server=argv[1]; char* echoString=argv[2]; size_t echoStringLen=strlen(echoString); if(echoStringLen>1024*8) DieWithUserMessage(echoString,"too long"); char * service=(argc==4)?argv[3]:"echo"; //配置地址信息 struct addrinfo addr_criteria; memset(&addr_criteria,0,sizeof(addr_criteria)); addr_criteria.ai_family=AF_UNSPEC; addr_criteria.ai_socktype=SOCK_DGRAM; addr_criteria.ai_protocol=IPPROTO_UDP; struct addrinfo *server_addr; //自动获取地址信息 int ret=getaddrinfo(server,service,&addr_criteria,&server_addr); if(ret!=0) DieWithUserMessage("getaddrinfo() failed!",gai_strerror(ret)); //建立socket int sock=socket(server_addr->ai_family,server_addr->ai_socktype,server_addr->ai_protocol); if(sock<0) DieWithSystemMessage("socket failed!"); //信号处理者 struct sigaction handler; //设置SIGALRM信号到来处理函数 handler.sa_handler=CatchAlarm; //填充信号掩码 if(sigfillset(&handler.sa_mask)<0) DieWithSystemMessage("sigfillset() failed!"); //信号标志归零 handler.sa_flags=0; //注册信号量 if(sigaction(SIGALRM,&handler,0)<0) DieWithSystemMessage("sigaction() failed for SIGALRM"); //开始发送数据 ssize_t numBytes=sendto(sock,echoString,echoStringLen,0,server_addr->ai_addr,server_addr->ai_addrlen); if(numBytes<0) DieWithSystemMessage("send() failed!"); else if(numBytes!=echoStringLen) { DieWithUserMessage("sendto() error","sent unexpected number of bytes"); } //然后接收数据,都是循环接收的 struct sockaddr_storage fromaddr; socklen_t fromaddrLen=sizeof(fromaddr); //设置定时器,超时设置 alarm(TIMEOUT_SEC); char buffer[BUFSIZ+1]; //接收数据 while((numBytes=recvfrom(sock,buffer,BUFSIZ,0,(struct sockaddr*)&fromaddr,&fromaddrLen))<0) { if(errno=EINTR)//闹铃响了,即超时了。执行了CatchAlarm { if(tries<MAXTRIES) { //小于重试次数,继续重新发送数据 numBytes=sendto(sock,echoString,echoStringLen,0,(struct sockaddr*)server_addr->ai_addr,server_addr->ai_addrlen); if(numBytes<0) DieWithSystemMessage("sendto() failed!"); else if(numBytes!=echoStringLen) { DieWithUserMessage("sendto() error","sent unexpected number of bytes"); } }else{ DieWithUserMessage("No Response","Unable to communitcate with server"); } }else{ DieWithSystemMessage("recvfrom() failed!"); } } //闹铃归零 alarm(0); buffer[echoStringLen]='\0'; printf("Received: %s \n",buffer); close(sock); return (EXIT_SUCCESS);}//闹铃响了,执行该函数void CatchAlarm(int ignored){ tries+=1;}
/* * File: UDPEchoServer-SIGIO.c * Author: 云守护 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/file.h>#include <signal.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include "DieWithMessage.h"//用户空闲时任务void UseIdleTime();//异步IO处理者void SIGIOHandler(int signalType);int server_sock;#define MAXSTRINGLENGTH 1024*8//打印客户端地址消息void PrintSocketAddress(const struct sockaddr *address, FILE *stream) { // Test for address and stream if (address == NULL || stream == NULL) return; void *numericAddress; // Pointer to binary address // Buffer to contain result (IPv6 sufficient to hold IPv4) char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; // Port to print // Set pointer to address based on address family switch (address->sa_family) { case AF_INET: numericAddress = &((struct sockaddr_in *) address)->sin_addr; port = ntohs(((struct sockaddr_in *) address)->sin_port); break; case AF_INET6: numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr; port = ntohs(((struct sockaddr_in6 *) address)->sin6_port); break; default: fputs("[unknown type]", stream); // Unhandled type return; } // Convert binary to printable address if (inet_ntop(address->sa_family, numericAddress, addrBuffer, sizeof(addrBuffer)) == NULL) fputs("[invalid address]", stream); // Unable to convert else { fprintf(stream, "%s", addrBuffer); if (port != 0) // Zero not valid in any socket addr fprintf(stream, "-%u", port); }}int main(int argc, char** argv) { if(argc!=2) DieWithUserMessage("param","<server port/service>"); char *service=argv[1]; //配置地址信息 struct addrinfo addr_criteria; memset(&addr_criteria,0,sizeof(addr_criteria)); addr_criteria.ai_family=AF_UNSPEC; //地址族 addr_criteria.ai_flags=AI_PASSIVE; addr_criteria.ai_socktype=SOCK_DGRAM; //流 addr_criteria.ai_protocol=IPPROTO_UDP;//UDP struct addrinfo *server_addr; //自动获取,消除IP4和IP6的依赖 getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 depen‐ dencies. int retVal=getaddrinfo(NULL,service,&addr_criteria,&server_addr); if(retVal!=0) DieWithUserMessage("getaddrinfo() failed!",gai_strerror(retVal)); //建立socket server_sock=socket(server_addr->ai_family,server_addr->ai_socktype,server_addr->ai_protocol); if(server_sock<0) DieWithSystemMessage("socket() failed!"); //绑定端口 if(bind(server_sock,server_addr->ai_addr,server_addr->ai_addrlen)<0) { DieWithSystemMessage("bind() failed!"); } freeaddrinfo(server_addr); printf("server success %s\n",service); //操作信号,设置异步IO struct sigaction handler; //设置异步到来时的处理函数 handler.sa_handler=SIGIOHandler; //填充信号掩码 if(sigfillset(&handler.sa_mask)<0) DieWithSystemMessage("sigfillset() failed!"); //标志设置0,即无标志 handler.sa_flags=0; //注册SIGIO信号 if(sigaction(SIGIO,&handler,0)<0) DieWithSystemMessage("sigaction() failed for SIGIO"); //设置server_sock接收SIGIO信号信息 if(fcntl(server_sock,F_SETOWN,getpid())<0) DieWithSystemMessage("fcntl failed!"); //使用非阻塞IO和SIGIO信号发送 if(fcntl(server_sock,F_SETFL,O_NONBLOCK|FASYNC)<0) DieWithSystemMessage("Unable to put client sock into non-blocking/async mode"); for(;;) { //死循环,等待异步IO的到来。就不用使用多线程了。 UseIdleTime(); } return (EXIT_SUCCESS);}void UseIdleTime(){ puts("."); sleep(3);//3s}//异步IO处理函数void SIGIOHandler(int signalType){ ssize_t numBytesRcvd; do{ //只要有输入 struct sockaddr_storage client_addr; size_t client_Len=sizeof(client_addr); char buffer[MAXSTRINGLENGTH]; //接收数据 numBytesRcvd=recvfrom(server_sock,buffer,MAXSTRINGLENGTH,0,(struct sockaddr*)&client_addr,&client_Len); if(numBytesRcvd<0) { if(errno!=EWOULDBLOCK) { //判断recvfrom函数是否阻塞 DieWithSystemMessage("recvfrom failed!"); } }else{ fprintf(stdout,"handling client "); //打印地址消息 PrintSocketAddress((struct sockaddr*)&client_addr,stdout); fputc('\n',stdout); //把数据发送回去 ssize_t numByteSent=sendto(server_sock,buffer,numBytesRcvd,0,(struct sockaddr*)&client_addr,sizeof(client_addr)); if(numByteSent<0) DieWithSystemMessage("sendto() failed!"); else if(numByteSent!=numBytesRcvd) { DieWithUserMessage("sendto()","sent unexpected number of bytes"); } } //循环接收数据 }while(numBytesRcvd>=0); }
/* * File: DieWithMessage.h * Author: root * * Created on 2013年11月13日, 下午3:52 */#ifndef DIEWITHMESSAGE_H#defineDIEWITHMESSAGE_H#ifdef__cplusplusextern "C" {#endif#include <stdio.h>#include <stdlib.h> void DieWithUserMessage(const char *msg,const char * detail) { fputs(msg,stderr); fputs(":",stderr); fputs(detail,stderr); fputs("\n",stderr); exit(1); } void DieWithSystemMessage(const char* msg) { perror(msg); exit(1); }#ifdef__cplusplus}#endif#endif/* DIEWITHMESSAGE_H */