您的位置:首页 > 运维架构 > Linux

linux c socket之异步IO

2016-01-09 19:19 447 查看
[cpp] view
plaincopy

/*

* 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;

}

[cpp] view
plaincopy

/*

* 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);



}

[cpp] view
plaincopy

/*

* 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: