linux c socket之异步IO

来源:互联网 发布:ui需要的软件 编辑:程序博客网 时间:2024/05/20 11:48
/*  * 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 */

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 有护照怎么办旅游签证 机票护照号写错了怎么办 美国护照过期了怎么办 护照过期十年了怎么办 护照期限到期了怎么办 签证超出停留期怎么办 签证快过期了怎么办 去国外旅游签证怎么办 照片回执过期了怎么办 加拿大护照丢了怎么办 头发有颜色怎么办护照 微信怎么办港澳通行证 港澳通行证 团签怎么办 出境章没有盖怎么办 过海关没有盖章怎么办 中国入境没盖章怎么办 护照有效期写错怎么办 回国海关电子盖章怎么办 户籍在学校怎么办护照 割过双眼皮护照怎么办 想换电子护照怎么办 有美签的护照丢失怎么办 护照在国外掉了怎么办 上海动迁房户口怎么办 政府强制拆房怎么办 农村无证宅基地怎么办 身份证没磁怎么办护照 买安置房怎么办产权 安置房房东违约怎么办 安置房产权到期怎么办 安置房怎么办房产证吗 美甲后指甲长了怎么办 在菲律宾怎么办持枪证? 绝地求生打不准怎么办 身份证号码变更后社保怎么办 社保与身份不符怎么办 年龄改了学籍怎么办 结婚证信息错误怎么办 六级身份证过期怎么办 身份号泄露了怎么办 身体证信息泄露怎么办