Linux网络编程基础-08_网络超时

网络信息检索函数

gethostname() 获得主机名
getpeername() 获得与套接口相连的远程协议地址
getsockname() 获得本地套接口协议地址
gethostbyname() 根据主机名取得主机信息 endhostent()

gethostbyaddr() 根据主机地址取得主机信息
getprotobyname() 根据协议名取得主机协议信息
getprotobynumber() 根据协议号取得主机协议信息
getservbyname() 根据服务名取得相关服务信息
getservbyport() 根据端口号取得相关服务信息

域名解析示例

······
······
	struct hostent *hs;
	if((hs = gethostbyname(argv[1])) == NULL)
	{
		herror("gethostbyname");
		exit(-1);
	}

	/* 1 创建socket fd */
	if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	/* 2 连接服务器 */
	/* 2.1 填充struct sockaddr_in结构体变量*/
	bzero(&sin,sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);//转为网络字节序端口号
#if 1
	sin.sin_addr.s_addr = *(uint32_t *)hs->h_addr;//从hostent结构体中获取IP地址
	endhostent();//释放hostent结构体空间
	hs = NULL;
#else
	if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr.s_addr) < 0)
	{
		perror("inet_pton");
		goto _error1;
	}
#endif
	/* 2.2 连接服务器*/
	if(connect(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("connect");
		goto _error1;
	}
······
······

网络属性设置

  • getsockopt和setsockopt

  • int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen)

  • int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t *optlen)

  • level指定控制套接字的层次.可以取三种值: 1)SOL_SOCKET:通用套接字选项.
    2)IPPROTO_IP:IP选项.
    3)IPPROTO_TCP:TCP选项. optname指定控制的方式(选项的名称),我们下面详细解释

  • optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换 
    Linux网络编程基础-08_网络超时

网络超时

  • 在网络通信中,很多操作会使得进程阻塞

  • TCP套接字中的recv/accept/connect

  • UDP套接字中的recvfrom

  • 超时检测的必要性
    避免进程在没有数据时无限制地阻塞
    当设定的时间到时,进程从原操作返回继续运行

超时检测方法(1)

设置socket的属性 SO_RCVTIMEO

参考代码如下

struct timeval  tv;

tv.tv_sec = 5;   //  设置5秒时间
tv.tv_usec = 0;

setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,  &tv,  sizeof(tv));   //  设置接收超时
recv() / recvfrom()    //   从socket读取数据

超时检测方法(2)

用select检测socket是否’ready’

参考代码如下

struct fd_set rdfs;
struct timeval  tv = {5 , 0};   // 设置5秒时间

FD_ZERO(&rdfs);
FD_SET(sockfd, &rdfs);

if (select(sockfd+1, &rdfs, NULL, NULL, &tv) > 0)   // socket就绪
{
     recv() /  recvfrom()    //  从socket读取数据
}

超时检测方法(3)

设置定时器(timer), 捕捉SIGALRM信号

参考代码如下

void  handler(int signo)     {   return;  }

struct sigaction  act;
sigaction(SIGALRM, NULL, &act);
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;
sigaction(SIGALRM, &act, NULL);
alarm(5);
if (recv(,,,) < 0) ……

如何在linux中动态检查到是否有网络以及网络中途的掉线/连接的检查?
提示:
1.应用层

  • 心跳检测
    2.内核中

  • 网卡驱动中 2.6内核里面,使能1s的周期性检查定时器

  • 网卡硬件或者我们通过GPIO,插拔网线时候产生中断,处理相应中断 //立即检测到

心跳检测

方法(1):

数据交互双方隔一段时间,一方发送一点数据到对方,对方给出特定的应答。如超过设定次数大小的时间内还是没有应答,这时候认为异常

方法(2):

改变套接字的属性来实现

#include <netinet/tcp.h>//包含了SOL_TCP等宏的定义
void setKeepAlive(int sockfd,int attr_on,socklen_t idle_time,socklen_t interval,socklen_t cnt)
{
	setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(const char *)&attr_on,sizeof(attr_on));
	setsockopt(sockfd,SOL_TCP,TCP_KEEPIDLE,(const char *)&idle_time,sizeof(idle_time));
	setsockopt(sockfd,SOL_TCP,TCP_KEEPINTVL,(const char *)&interval,sizeof(interval));
	setsockopt(sockfd,SOL_TCP,TCP_KEEPCNT,(const char *)&cnt,sizeof(cnt));
}
......
......
/*心跳检测(自动检测套接字连接是否已断开)*/
int keepAlive = 1;//设定keepAlive
int keepIdle = 5;//开始首次keepAlive探测前的TCP空闲时间
int keepInterval = 5;//两次keepAlive探测间的时间间隔
int keepCount = 3;//判定断开前的keepAlive探测次数

setKeepAlive(newfd,keepAlive,keepIdle,keepInterval,keepCount);
......