1. 程式人生 > >嵌入式linux網路程式設計,網路資訊檢索函式,域名解析gethostbyname(),網路屬性設定setsockopt(),網路超時優化,心跳檢測

嵌入式linux網路程式設計,網路資訊檢索函式,域名解析gethostbyname(),網路屬性設定setsockopt(),網路超時優化,心跳檢測

文章目錄

1,網路資訊檢索函式

gethostname() 獲得主機名
getpeername() 獲得與套介面相連的遠端協議地址
getsockname() 獲得本地套介面協議地址
gethostbyname() 根據主機名取得主機資訊 (域名解析:把域名轉換成IP地址相關資訊)
·endhostent()

gethostbyaddr() 根據主機地址取得主機資訊
getprotobyname() 根據協議名取得主機協議資訊
getprotobynumber() 根據協議號取得主機協議資訊
getservbyname() 根據服務名取得相關服務資訊
getservbyport() 根據埠號取得相關服務資訊

2,域名解析

2.1,gethostbyname()

#include <netdb.h>
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 <sys/socket.h> /* 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 */
[email protected]:~$ 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 <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);
......
......