嵌入式linux网络编程,网络信息检索函数,域名解析gethostbyname(),网络属性设置se

2019-07-12 21:47发布

文章目录

1,网络信息检索函数

gethostname() 获得主机名
getpeername() 获得与套接口相连的远程协议地址
getsockname() 获得本地套接口协议地址
gethostbyname() 根据主机名取得主机信息 (域名解析:把域名转换成IP地址相关信息)
·endhostent() gethostbyaddr() 根据主机地址取得主机信息
getprotobyname() 根据协议名取得主机协议信息
getprotobynumber() 根据协议号取得主机协议信息
getservbyname() 根据服务名取得相关服务信息
getservbyport() 根据端口号取得相关服务信息

2,域名解析

2.1,gethostbyname()

#include
extern int h_errno;//出错号
struct hostent *gethostbyname(const char *name);
  • name 指向主机名的指针(域名或 IP地址)
注意:
  1. IPv4中使用gethostbyname()函数完成主机名到地址解析,这个函数仅仅支持IPv4,且不允许调用者指定所需地址类型的任何信息,返回的结构只包含了用于存储IPv4地址的空间。IPv6中引入了getaddrinfo()的新API,它是协议无关的,即可用于IPv4,也可用于IPv6.

2.2,gethostbyaddr()

#include /* for AF_INET */
struct hostent *gethostbyaddr(const void *addr,socklen_t len, int type);
  • addr 指向网络字节顺序地址的指针
返回值
The gethostbyname() and gethostbyaddr() functions return the hostent structure or a NULL pointer if an error occurs. On error, the h_errno variable holds an error number. When non-NULL, the return value may point at static data, see the notes below. struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses地址列表,指向主机的多个网络地址(网络字节序32位整数). */ } #define h_addr h_addr_list[0] /* for backward compatibility */ linux@linux:~$ ping www.baidu.com PING www.a.shifen.com (58.217.200.15) 56(84) bytes of data. //www.a.shifen.com就是h_addr_list列表中的一个 64 bytes from 58.217.200.15: icmp_seq=1 ttl=55 time=21.1 ms 64 bytes from 58.217.200.15: icmp_seq=2 ttl=55 time=18.8 ms 64 bytes from 58.217.200.15: icmp_seq=3 ttl=55 time=10.1 ms ^C --- www.a.shifen.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2005ms rtt min/avg/max/mdev = 10.123/16.686/21.130/4.739 ms

2.3 错误处理 herror()、hstrerror()

extern int h_errno;//出错号
void herror(const char *s);/打印错误信息
const char *hstrerror(int err);//打印错误信息

2.4 释放hostent结构体endhostent()

void endhostent(void);//释放hostent结构体

2.5 域名解析示例

······ ······ 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; } ······ ······

3,网络属性设置 getsockopt()、setsockopt()

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)
  1. level指定控制套接字的层次.可以取三种值:
    1)SOL_SOCKET:通用套接字选项. (应用层)
    2)IPPROTO_TCP:TCP选项. 传输层)
    3)IPPROTO_IP:IP选项. (网络层)
  2. optname指定控制的方式(选项的名称),我们下面详细解释
  3. optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换
  4. optlen是optval的数据类型长度
在这里插入图片描述 struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ };

4,网络超时优化

  1. 在网络通信中,很多操作会使得进程阻塞
  2. TCP套接字中的recv/accept/connect
  3. UDP套接字中的recvfrom
  4. 超时检测的必要性 ·避免进程在没有数据时无限制地阻塞
    ·当设定的时间到时,进程从原操作返回继续运行

4.1,网络超时检测(一)

  1. 设置socket的属性 SO_RCVTIMEO
  2. 参考代码如下
struct timeval tv; tv.tv_sec = 5; // 设置5秒时间 tv.tv_usec = 0; setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)); // 设置接收超时 recv()recvfrom() // 从socket读取数据

4.2,网络超时检测(二)

  1. 用select检测socket是否’ready’
  2. 参考代码如下
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读取数据 }

4.3,网络超时检测(三)

  1. 设置定时器(timer), 捕捉SIGALRM信号
  2. 参考代码如下
void handler(int signo) { return; } struct sigaction act; sigaction(SIGALRM, NULL, &act); act.sa_handler = handler; act.sa_flags &= ~SA_RESTART;//清除快速重启位(如果不去掉,时间到了,recv()又会马上重新读数据) sigaction(SIGALRM, &act, NULL); alarm(5);// 通过定时器alarm()设置5秒超时 if (recv(,,,) < 0) ……//5秒后还没收到数据,就会被信号SIGALRM打断

5,如何在linux中动态检查到是否有网络以及网络中途的掉线/连接的检查?

  1. 应用层
    ·心跳检测
  2. 内核中
    ·网卡驱动中 2.6内核里面,使能1s的周期性检查定时器
    ·网卡硬件或者我们通过GPIO,插拔网线时候产生中断,处理相应中断 //立即检测到

5.2 心跳检测 — 方法一

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

5.2 心跳检测 — 方法二

改变套接字的属性来实现 #include //包含了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); ...... ......