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
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
相关文章推荐
- Linux下openoffice+swftools安装教程
- Linux错误代码含义/Linux return Error Code
- Linux printk and log level
- linux设备驱动makefile入门解析
- 2016年关于 Linux 发展趋势的八大预测
- Linux Core dump
- Linux学习之查看是否安装软件
- su sudo gksudo-转
- Linux调试 call trace dump_stuck
- linux中终端复用工具screen的介绍
- 搭建linux上的Eclipse+PHP编程环境
- linux定时执行任务
- CentOS 7 静态IP配置
- aliyun Centos7安装vsftpd服务
- CentOS RM安装
- Linux开机启动过程分析
- linux文件系统
- Linux系统启动过程分析
- linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结
- linux文件系统剖析