獲取網路包到達網絡卡的時間

2021-06-21 10:40:09 字數 2892 閱讀 7861

為啥要獲取資料報到達網絡卡的時間?

在回答這個問題之前,我們先看一下網絡卡訊息佇列。如下圖所示,對端傳送的網路資料報被網絡卡裝置接收到之後,會存放到網絡卡訊息佇列中,由應用程式呼叫recv系列函式從網絡卡佇列中獲取網路訊息。

現在假設:訊息處理服務處理網路訊息包的平均時間為1s,請求方等待回包的時間為1s,網絡卡訊息佇列的長度為10,在應用程式正常處理的情況下,所有的請求均能夠在規定的時間內接收到回包。但是訊息處理服務(即recv呼叫者)在處理某個資料報時發生異常,導致處理耗時3s,這時網絡卡訊息佇列中儲存了2個資料報。此時訊息處理服務恢復正常,再次從網絡卡訊息佇列中獲取到的資料報已將是3s之前的請求包,而且請求方已經等待超時,繼續處理這個請求已經沒有任何的實際意義,正確的處理方式為:從網絡卡訊息佇列獲取訊息時,同時獲取訊息到達網絡卡的時間,檢查訊息是否超時,超時的訊息直接丟棄或者記錄日誌等操作,然後繼續處理訊息佇列中剩餘的訊息。

下面介紹幾種獲取網路包到達網絡卡時間的方法:

方法一:搭建介面機

搭建介面機呼叫recv系列函式,從網絡卡訊息佇列中獲取訊息,打上時間戳再存放到訊息佇列中,由訊息處理服務來從應用訊息佇列中取出訊息進行處理。整體架構圖如下:

因為介面機的服務功能比較簡單,從網絡卡中獲取時間的時間,就可以當作網路包到達網絡卡的時間。

其實,介面服務與邏輯服務的架構比較常見,但是採用這種方法來解決獲取時間的問題,顯然成本比較高,非常不合適。

方法二:ioctl獲取網絡卡時間

ioctl可以根據socket控制代碼來查詢這個控制代碼獲取傳遞給使用者的最後乙個包到達網絡卡的時間,即獲取最後一次呼叫recv系列函式獲取到的資料報到達網絡卡的時間戳。現在存在乙個場景,如何獲取這個控制代碼接收到的每個資料的網絡卡時間?每次呼叫recv系列函式之後, 均需要再呼叫一次ioctl。

在呼叫ioctl的過程中,第一次呼叫ioctl返回的是gettimeofday的時間,後續獲取到的時間是正常的資料報到達網絡卡的時。

示例**:

server**(c):

#include #include #include #include #include #include #include #include #include #include #define port 31500

int main()

bzero ( &addr, sizeof(addr) );

addr.sin_family=af_inet;

addr.sin_port=htons(port);

addr.sin_addr.s_addr=htonl(inaddr_any) ;

if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr))<0)

struct timeval tv, tvnow,tvres;

while(1)

return 0;

}

client**(python):

import socket

address = ('127.0.0.1',31500)

s = socket.socket(socket.af_inet,socket.sock_dgram)

while true:

msg = raw_input()

if not msg:

break

s.sendto(msg,address)

s.close()

使用該策略的缺點在於:為獲取到時間戳需要產生額外的一次系統呼叫:ioctl,降低了系統的效能。方法三相對更加高效簡單,在獲取到網路資料報的同時獲取到網路資料報到達網絡卡的時間。

方法三:recvmsg獲取網絡卡時間

使用recvmsg函式,調整所需要獲取的控制訊息,即可獲取到網路包到達網絡卡的時間戳

server**(c):

#include #include #include #include #include #include #include #include #include #include #define servport 31500

int main(int argc, char **argv)

bzero(&srvaddr, sizeof(srvaddr) );

srvaddr.sin_family = af_inet;

srvaddr.sin_port = htons(servport);

srvaddr.sin_addr.s_addr = htonl(inaddr_any);

bind(sockfd, (struct sockaddr*)&srvaddr,sizeof(srvaddr));

while(1)

struct timeval tv, tvnow,tvres;

if(cmsg->cmsg_level ==sol_socket&&

cmsg->cmsg_type ==scm_timestamp &&

cmsg->cmsg_len ==cmsg_len(sizeof(tv))

) memcpy(&tv,cmsg_data(cmsg),sizeof(tv));

gettimeofday(&tvnow, null);

uint64_t ddwnow = tvnow.tv_sec*1000000 + tvnow.tv_usec;

uint64_t ddwtv = tv.tv_sec*1000000 + tv.tv_usec;

printf("now:%lu tv:%lu dff:%lu\n",ddwnow,ddwtv,(ddwnow - ddwtv)/1000000);

sleep(10);} }

獲取網路時間

region 獲取網路時間 獲取中國國家授時中心網路伺服器時間發布的當前時間 public static datetime getchinesedatetime 年 d月 d日 string pathr hrs s s d string patmn min s s d string patsc se...

8266獲取網路時間

8266獲取網路時間 今天第一次用阿里的部落格寫點東西感受一下.sntp.sync ntp1.aliyun.com function print sync succeeded end,function index print failed index end 用的sntp 然後列印時間 time r...

qt獲取網路時間

獲取網路時間,目的就是獲取最新的時間,而不是電腦的本機時間,這種情況一般應用在程式到時間過期,禁止使用情況下。qt5.7 win8 pro檔案中新增network庫 qstring aaa 19 12 15 qstring bbb qtcpsocket socket new qtcpsocket s...