- /*
- * 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
- #define DIEWITHMESSAGE_H
- #ifdef __cplusplus
- extern "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 */
FROM;http://blog.csdn.net/earbao/article/details/16337639