嵌入式linux網路程式設計,網路資訊檢索函式,域名解析gethostbyname(),網路屬性設定setsockopt(),網路超時優化,心跳檢測
文章目錄
- 1,網路資訊檢索函式
- 2,域名解析
- 2.1,gethostbyname()
- 2.2,gethostbyaddr()
- 2.3 錯誤處理 herror()、hstrerror()
- 2.4 釋放hostent結構體endhostent()
- 2.5 域名解析示例
- 3,網路屬性設定 getsockopt()、setsockopt()
- 4,網路超時優化
- 5,如何在linux中動態檢查到是否有網路以及網路中途的掉線/連線的檢查?
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地址)
注意:
- 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)
- level指定控制套接字的層次.可以取三種值:
1)SOL_SOCKET:通用套接字選項. (應用層)
2)IPPROTO_TCP:TCP選項. 傳輸層)
3)IPPROTO_IP:IP選項. (網路層) - optname指定控制的方式(選項的名稱),我們下面詳細解釋
- optval獲得或者是設定套接字選項.根據選項名稱的資料型別進行轉換
- optlen是optval的資料型別長度
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
4,網路超時優化
-
在網路通訊中,很多操作會使得程序阻塞
-
TCP套接字中的recv/accept/connect
-
UDP套接字中的recvfrom
-
超時檢測的必要性
·避免程序在沒有資料時無限制地阻塞
·當設定的時間到時,程序從原操作返回繼續執行
4.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讀取資料
4.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讀取資料
}
4.3,網路超時檢測(三)
- 設定定時器(timer), 捕捉SIGALRM訊號
- 參考程式碼如下
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中動態檢查到是否有網路以及網路中途的掉線/連線的檢查?
-
應用層
·心跳檢測 -
核心中
·網絡卡驅動中 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);
......
......