Red Giant PluralEyes for Mac雖然只是Shooter Suite其中的一部分,但是卻十分受歡迎,功能也非常強大。PluralEyes Mac版提供了用戶需要的音頻和視頻同步的一切功能,可以自動分析視頻和音頻文件,並同步起來。 詳情:Red Giant PluralEyes ...
1. 底層API
由協議棧底層提供的api,用於涉及底層操作的一些功能實現,這些api介面函數的原型定義分佈於不同的文件,它們被統一include進了onps.h中:
- open_npstack_load:將協議棧載入目標系統,協議棧開始運行
- open_npstack_unload:將協議棧載出目標系統,協議棧結束運行
- route_add:添加一條靜態路由
- route_del:刪除一條靜態路由
- route_del_ext:刪除指定網卡在路由表中的所有路由條目,禁止網卡跨網段通訊
- route_get_default:獲取預設路由
- dhcp_req_addr:向dhcp伺服器請求租用一個動態地址
- ethernet_add:添加ethernet網卡
- ethernet_del:刪除ethernet網卡
- ethernet_put_packet:將收到的ethernet報文推送給協議棧
- netif_is_ready:網卡是否已就緒(進入工作狀態)
- netif_get_by_name:通過網卡名稱查找網卡
- buddy_alloc:申請一塊指定大小的記憶體
- buddy_free:釋放申請的記憶體
- buf_list_get_next_node:取出下一個鏈表節點
- buf_list_get_len:鏈表所有節點攜帶的數據長度之和
- buf_list_merge_packet:合併鏈表節點攜帶的數據將其放入用戶指定的緩衝區
open_npstack_load
功能
協議棧的入口函數,目標系統調用該函數啟動協議棧。換言之,在使用協議棧之前必須首先成功先調用該函數。
原型
BOOL open_npstack_load(EN_ONPSERR *penErr);
入口參數
- penErr:指向錯誤編碼的指針,當函數執行失敗,該參數用於接收實際的錯誤碼
返回值
載入成功,返回TRUE;反之返回FALSE,具體的錯誤信息參見參數penErr返回的錯誤碼。
示例
EN_ONPSERR enErr;
if(open_npstack_load(&enErr)) //* 載入協議棧
{
//* 協議棧載入成功,在這裡添加你的自定義代碼
……
}
else
printf("協議棧載入失敗, %s\r\n", onps_error(enErr)); //* 列印錯誤信息
open_npstack_unload
功能
協議棧的退出函數。一旦調用該函數,協議棧會結束運行並釋放占用的相關係統資源。
原型
void open_npstack_unload(void);
入口參數
無
返回值
無
示例
略
route_add
功能
添加一條靜態路由到路由表。
原型
BOOL route_add(PST_NETIF pstNetif, UINT unDestination, UINT unGateway, UINT unGenmask, EN_ONPSERR *penErr);
入口參數
- pstNetif:指向網卡控制塊ST_NETIF的指針,該指針唯一的標識一塊網卡,其用於指定靜態路由添加到哪個網卡
- unDestination:目標網段地址,如果其值為0則其為預設路由
- unGateway:網關地址
- unGenmask:子網掩碼
- penErr:指向錯誤編碼的指針,當函數執行失敗,該參數用於接收實際的錯誤碼
返回值
添加成功則返回TRUE,否則返回FALSE,具體的錯誤信息參見參數penErr返回的錯誤碼。
示例
EN_ONPSERR enErr;
PST_NETIF pstNetif = netif_get_by_name("eth0");
if(pstNetif && route_add(pstNetif, inet_addr_small("47.92.239.0"), inet_addr_small("192.168.0.1"), inet_addr_small("255.255.255.0"), &enErr))
{
//* 添加成功,在這裡添加你的自定義代碼
……
}
else
printf("靜態路由添加失敗, %s\r\n", onps_error(enErr)); //* 列印錯誤信息
route_del
功能
刪除一條靜態路由。
原型
void route_del(UINT unDestination);
入口參數
- unDestination:指定要刪除的目標網段地址
返回值
無
示例
略
route_del_ext
功能
刪除指定網卡在路由表中的所有路由條目,禁止網卡跨網段通訊。
原型
void route_del_ext(PST_NETIF pstNetif);
入口參數
- pstNetif:指向網卡控制塊ST_NETIF的指針,指定要刪除哪個網卡的所有路由條目
返回值
無
示例
略
route_get_default
功能
獲取預設路由信息。
原型
PST_NETIF route_get_default(void);
入口參數
無
返回值
返回預設路由綁定的網卡控制塊首地址。
示例
略
dhcp_req_addr
功能
啟動dhcp客戶端,向dhcp伺服器請求租用一個動態地址。
原型
BOOL dhcp_req_addr(PST_NETIF pstNetif, EN_ONPSERR *penErr);
入口參數
- pstNetif:指定要進行dhcp請求的網卡
- penErr:指向錯誤編碼的指針,當函數執行失敗,該參數用於接收實際的錯誤碼
返回值
請求成功則返回TRUE,否則返回FALSE,具體的錯誤信息參見參數penErr返回的錯誤碼。
示例
參見上一篇博文《onps棧移植說明(3)——添加網卡》。
ethernet_add
功能
增加新的ethernet網卡到協議棧。
原型
PST_NETIF ethernet_add(const CHAR *pszIfName,
const UCHAR ubaMacAddr[ETH_MAC_ADDR_LEN],
PST_IPV4 pstIPv4,
PFUN_EMAC_SEND pfunEmacSend,
void (*pfunStartTHEmacRecv)(void *pvParam),
PST_NETIF *ppstNetif,
EN_ONPSERR *penErr);
入口參數
- pszIfName:網卡名稱
- ubaMacAddr:網卡 mac 地址
- pstIPv4:指向 ST_IPV4 結構體的指針(include/netif/netif.h),這個結構體保存用戶指定的 ip地址、網關、dns、子網掩碼等配置信息
- pfunEmacSend:函數指針,指向發送函數,函數原型為 INT(* PFUN_EMAC_SEND)(SHORT sBufListHead, UCHAR *pubErr),這個指針指向的其實就是網卡發送函數
- pfunStartTHEmacRecv:指向線程啟動函數的指針,協議棧使用該指針指向的函數啟動協議棧內部工作線程——ethernet網卡接收線程
- ppstNetif:二維指針,協議棧成功註冊網卡後 ethernet_add()函數會返回一個 PST_NETIF 指針給調用者,這個參數指向這個指針,其最終會被協議棧通過 pvParam 參數傳遞給 pfunStartTHEmacRecv 指向的函數
- penErr:指向錯誤編碼的指針,當函數執行失敗,該參數用於接收實際的錯誤碼
返回值
註冊成功,返回一個 PST_NETIF 類型的指針,該指針指向新添加的網卡控制塊,唯一的標識新添加的這塊網卡;註冊失敗則返回 NULL,具體錯誤信息參見 penErr參數攜帶的錯誤碼。
示例
參見上一篇博文《onps棧移植說明(3)——添加網卡》。
ethernet_del
功能
刪除ethernet網卡。
原型
void ethernet_del(PST_NETIF *ppstNetif);
入口參數
- ppstNetif:指向網卡控制塊PST_NETIF指針的指針,其指向ethernet_add()函數返回的PST_NETIF指針的首地址
返回值
無
示例
略
ethernet_put_packet
功能
將收到的ethernet報文推送給協議棧。
原型
void ethernet_put_packet(PST_NETIF pstNetif, PST_SLINKEDLIST_NODE pstNode);
入口參數
- pstNetif:指向網卡控制塊ST_NETIF的指針
- pstNode:指向協議棧ethernet網卡接收鏈表節點的指針
返回值
無
示例
參見上一篇博文《onps棧移植說明(3)——添加網卡》。
netif_is_ready
功能
檢查網卡是否已進入或正處於正常工作狀態。
原型
BOOL netif_is_ready(const CHAR *pszIfName);
入口參數
- pszIfName:指向網卡名稱的指針
返回值
返回TRUE,網卡已就緒;反之則返回FALSE。
示例
略
netif_get_by_name
功能
通過網卡名稱查找網卡。
原型
PST_NETIF netif_get_by_name(const CHAR *pszIfName);
入口參數
- pszIfName:指向網卡名稱的指針
返回值
存在則返回指向網卡控制塊ST_NETIF的指針;否則返回NULL。
示例
略
buddy_alloc
功能
向記憶體管理單元(mmu)申請一塊指定大小的記憶體。
原型
void *buddy_alloc(UINT unSize, EN_ONPSERR *penErr);
入口參數
- unSize:申請分配的記憶體大小,單位:位元組
- penErr:指向錯誤編碼的指針,當函數執行失敗,該參數用於接收實際的錯誤碼
返回值
申請成功返回記憶體首地址;反之則返回NULL,具體錯誤信息參見 penErr參數攜帶的錯誤碼。
示例
參見buf_list_merge_packet函數示例或上一篇博文《onps棧移植說明(3)——添加網卡》。
buddy_free
功能
歸還(釋放)先前通過buddy_alloc()函數申請的記憶體。
原型
BOOL buddy_free(void *pvStart);
入口參數
- pvStart:指向要歸還的記憶體首地址的指針
返回值
成功歸還記憶體返回TRUE;當pvStart指向的並不是buddy_alloc()函數返回的記憶體首地址時則返回FALSE。
示例
參見buf_list_merge_packet函數示例。
buf_list_get_next_node
功能
按鏈接順序從鏈表首部逐個取出鏈表節點。
原型
void *buf_list_get_next_node(SHORT *psNextNode, USHORT *pusDataLen);
入口參數
- psNextNode:指向鏈表下一個節點的指針
- pusDataLen:指向數據長度的指針,出口參數,其用於接收節點攜帶的數據長度
返回值
如果尚未到達鏈表尾部,則返回當前鏈表節點攜帶的數據的首地址;反之則返回NULL。
示例
參見上一篇博文《onps棧移植說明(3)——添加網卡》。
buf_list_get_len
功能
統計鏈表所有節點攜帶的數據長度之和。
原型
UINT buf_list_get_len(SHORT sBufListHead);
入口參數
- sBufListHead:鏈表首地址
返回值
返回鏈表所有節點攜帶的數據長度之和。
示例
參見buf_list_merge_packet函數示例或上一篇博文《onps棧移植說明(3)——添加網卡》。
buf_list_merge_packet
功能
從鏈表首節點開始順序取出數據將其放入用戶指定的緩衝區,把零散的鏈表數據合併成一塊連續數據。
原型
void buf_list_merge_packet(SHORT sBufListHead, UCHAR *pubPacket);
入口參數
- sBufListHead:鏈表首地址
- pubPacket:指向用戶緩衝區的指針,其用於接收合併後的數據以返回給用戶使用
返回值
無
EN_ONPSERR enErr;
UINT unDataLen = buf_list_get_len(sBufListHead /* 鏈表首地址 */);
UCHAR *pubBuf = (UCHAR *)buddy_alloc(unDataLen, &enErr); //* 申請一塊緩衝區用於保存合併後的數據
if(pubBuf)
{
//* 合併,合併後的數據保存在了pubBuf中,數據長度為unDataLen
buf_list_merge_packet(sBufListHead, pubBuf);
//* 在這裡增加你自己的代碼處理合併合併後的數據
……
//* 處理完畢,釋放剛纔申請的記憶體
buddy_free(pubBuf);
}
2. Berkeley sockets
協議棧提供的伯克利套接字(Berkeley sockets)並不是嚴格按照傳統socket標準設計實現的,而是我根據以往socket編程經驗,以方便用戶使用、簡化用戶編碼為設計目標,重新聲明並定義的一組常見socket介面函數。協議棧簡化了傳統BSD socket編程需要的一些繁瑣操作,將一些不必要的操作細節改為底層實現,比如select/poll模型、阻塞及非阻塞讀寫操作等。簡化並不意味著推翻,socket介面函數的基本定義、主要參數、使用方法並沒有改變,你完全可以根據以往經驗快速上手並熟練使用onps棧sockets。這一點相信你已經從前面的測試代碼中得到了佐證。
socket層所有介面函數的實現源碼被封裝在了單獨的一個文件中,參見bsd/socket.c。其對應的頭文件socket.h有這些介面函數的定義和說明。目前協議棧提供的socket介面函數有十幾個,能夠滿足絕大部分應用場景的需求。這些介面函數如下:
- socket:創建一個socket,目前僅支持udp和tcp兩種類型
- close:關閉一個socket,釋放當前占用的協議棧資源
- connect:與目標tcp伺服器建立連接(阻塞型)或綁定一個固定的udp伺服器地址
- connect_nb:與目標tcp伺服器建立連接(非阻塞型)
- is_tcp_connected:獲取當前tcp鏈路的連接狀態
- send:數據發送函數,tcp鏈路下為阻塞型
- send_nb:數據發送函數,非阻塞型
- is_tcp_send_ok:數據是否已成功送達tcp鏈路的對端(收到tcp ack報文)
- sendto:udp數據發送函數,發送數據到指定目標地址
- recv:數據接收函數,udp/tcp鏈路通用
- recvfrom:數據接收函數,用於udp鏈路,接收數據的同時函數會返回數據源的地址信息
- socket_set_rcv_timeout:設定recv()函數接收等待的時長,單位:秒
- bind:綁定一個固定埠、地址
- listen:tcp伺服器進入監聽狀態
- accept:接受一個到達的tcp連接請求
- tcpsrv_recv_poll:tcp伺服器專用函數,等待任意一個或多個tcp客戶端數據到達信號
- socket_get_last_error:獲取socket最近一次發生的錯誤信息
- socket_get_last_error_code:獲取socket最近一次發生的錯誤編碼
socket
功能
創建一個socket,支持udp和tcp兩種類型,即:SOCK_DGRAM和SOCK_STREAM。註意,不使用時一定要調用close()函數關閉,以釋放其占用的協議棧相關資源。
原型
SOCKET socket(INT family, INT type, INT protocol, EN_ONPSERR *penErr);
入口參數
- family:目前僅支持IPv4地址,即AF_INET,其它地址族如AF_INET6之類的不支持
- type:指定socket類型,支持SOCK_STREAM和SOCK_DGRAM兩種類型,前者為tcp,後者為udp
- protocol:未使用,固定為0
- penErr:指向錯誤編碼的指針,當socket()函數執行失敗,該參數用於接收實際的錯誤碼
返回值
執行成功返回socket句柄,失敗返回INVALID_SOCKET,具體的錯誤信息參見penErr參數返回的錯誤碼。
示例
EN_ONPSERR enErr;
//* tcp
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, 0, &enErr);
if(INVALID_SOCKET == hSocket) //* 返回一個無效的socket
printf("%s\r\n", onps_error(enErr)); //*列印錯誤信息
//* udp
SOCKET hSocket = socket(AF_INET, SOCK_DGRAM, 0, &enErr);
……
close
功能
關閉socket,釋放占用的協議棧資源。
原型
void close(SOCKET socket);
入口參數
- socket:要關閉的socket句柄
返回值
無
示例
EN_ONPSERR enErr;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, 0, &enErr);
……
if(INVALID_SOCKET != hSocket)
close(hSocket);
connect
功能
用於tcp類型的socket時,其功能為與目標伺服器建立tcp連接,阻塞型;用於udp類型的socket時,其功能為綁定一個固定的目標通訊地址,udp通訊均與這個固定地址進行。
原型
INT connect(SOCKET socket, const CHAR *srv_ip, USHORT srv_port, INT nConnTimeout);
入口參數
- socket:要進行connect操作的socket句柄
- srv_ip:目標伺服器地址
- srv_port:目標伺服器埠
- nConnTimeout:僅用於tcp通訊,指定連接超時時間(單位:秒),參數值如小於等於0則協議棧會採用預設值,該值由TCP_CONN_TIMEOUT巨集指定(參見sys_config.h);udp通訊未使用這個參數,可以指定任意一個值
返回值
0:連接成功
-1:連接失敗,具體的錯誤信息通過onps_get_last_error()獲得
示例
EN_ONPSERR enErr;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, 0, &enErr);
if(INVALID_SOCKET == hSocket)
{
printf("%s\r\n", onps_error(enErr));
return;
}
if(!connect(hSocket, "47.92.239.107", 6410, 10))
{
//* 連接成功,在這裡添加你的自定義代碼
……
}
else
{
//* 連接失敗,列印錯誤信息
printf("%s\r\n", onps_get_last_error(hSocket, NULL));
}
……
close(hSocket);
connect_nb
功能
僅用於tcp類型的socket,非阻塞型,與目標tcp伺服器建立連接。
原型
INT connect_nb(SOCKET socket, const CHAR *srv_ip, USHORT srv_port);
入口參數
- socket:要進行connect操作的socket句柄
- srv_ip:目標伺服器地址
- srv_port:目標伺服器埠
返回值
0:連接成功
1:連接中
-1:連接失敗,具體的錯誤信息通過onps_get_last_error()獲得
示例
EN_ONPSERR enErr;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, 0, &enErr);
if(INVALID_SOCKET == hSocket)
{
printf("%s\r\n", onps_error(enErr));
return;
}
//* 迴圈等待tcp連接成功
while(1)
{
INT nRtnVal = connect_nb(hSocket, "47.92.239.107", 6410);
if(!nRtnVal)
{
//* 連接成功,在這裡增加你的自定義代碼
……
break; //* 退出迴圈,不再輪詢檢查tcp連接進程
}
else if(nRtnVal < 0)
{
//* 連接失敗,列印錯誤信息並退出迴圈不再輪詢檢查tcp連接進程
printf("%s\r\n", onps_get_last_error(hSocket, NULL));
break;
}
else;
//* 連接中,tcp三次握手操作尚未完成,此時你可以乾點別的事情,或者延時一小段時間後繼續檢查當前連接狀態
……
os_sleep_secs(1);
}
……
close(hSocket);
is_tcp_connected
功能
檢查tcp鏈路是否處於連接狀態。
原型
INT is_tcp_connected(SOCKET socket, EN_ONPSERR *penErr);
入口參數
- socket:socket句柄
- penErr:指向錯誤編碼的指針,函數執行失敗時該參數用於接收實際的錯誤碼
返回值
0:未連接
1:已連接
-1:函數執行失敗,具體的錯誤信息通過參數penErr獲得
示例
EN_ONPSERR enErr;
……
INT nRtnVal = is_tcp_connected(hSocket, &enErr);
if(nRtnVal > 0)
printf("已連接\r\n");
else if(!nRtnVal)
printf("未連接\r\n");
else
printf("檢查失敗,%s\r\n", onps_error(enErr));
……
send
功能
發送數據到目標地址。註意tcp鏈路下為阻塞型,直至收到對端的tcp層ack報文或超時才會返回。udp鏈路下為非阻塞型,且只有在調用connect()函數後才能使用這個函數。
原型
INT send(SOCKET socket, UCHAR *pubData, INT nDataLen, INT nWaitAckTimeout);
入口參數
- socket:socket句柄
- pubData:指向要發送的數據的指針
- nDataLen:要發送的數據的長度,單位:位元組
- nWaitAckTimeout:僅用於tcp鏈路,指定發送超時時間,單位:秒,如參數值不大於0,則協議棧採用系統預設值,該值由TCP_ACK_TIMEOUT巨集指定(參見sys_config.h);udp鏈路未使用,可指定任意值
返回值
發送成功,則返回值等於nDataLen;發送失敗,返回值不等於nDataLen,具體的錯誤信息通過onps_get_last_error()獲得。
示例
/* tcp鏈路下send()函數使用示例 */
EN_ONPSERR enErr;
……
UCHAR ubUserData[128];
INT nSndBytes, nSndNum = 0;
__lblSend:
if(nSndNum > 2)
{
//* 超出重傳次數,不再重傳,可以關閉當前tcp鏈路重連tcp伺服器或者你自己的其它處理方式
……
return;
}
nSndBytes = send(hSocket, ubUserData, sizeof(ubUserData), 3);
if(sizeof(ubUserData) == nSndBytes)
{
//* 發送成功,在這裡添加你自己的處理代碼
……
}
else
{
const CHAR *pszErr = onps_get_last_error(hSocket, &enErr);
if(enErr == ERRTCPACKTIMEOUT) //* 等待tcp層的ack報文超時
{
//* 數據重傳,用戶層實現tcp層重傳機制
nSndNum++;
goto __lblSend;
}
else //* 其它錯誤,意味著底層協議棧捕捉到了記憶體不夠用、網卡故障等類似的嚴重問題
{
//* 沒必要觸發重傳機制了,根據你自己的具體情形增加容錯處理代碼並列印錯誤信息
……
printf("發送失敗,%s\r\n", pszErr);
}
}
……
send_nb
功能
發送數據到目標地址,非阻塞型,其它與send函數完全相同。
原型
INT send_nb(SOCKET socket, UCHAR *pubData, INT nDataLen);
入口參數
- socket:socket句柄
- pubData:指向要發送的數據的指針
- nDataLen:要發送的數據的長度,單位:位元組
返回值
發送成功,則返回值等於nDataLen;返回值為0,上一組數正處於發送中(尚未收到對端的tcp ack報文),需要等待其發送成功後再發送當前數據;發送失敗,返回值小於等於0,具體的錯誤信息通過onps_get_last_error()獲得。
示例
/* tcp鏈路下send_nb()函數使用示例 */
EN_ONPSERR enErr;
……
UCHAR ubUserData[128];
INT nRtnVal;
__lblSend:
nRtnVal = send_nb(hSocket, ubUserData, sizeof(ubUserData));
if(sizeof(ubUserData) == nRtnVal)
{
//* 調用is_tcp_send_ok()函數等待是否已成功送達對端,或者(同時)做點別的事情
……
}
else if(0 == nRtnVal)
{
//* 上一組數據尚未發送完畢,需要等待發送完畢後再發送當前數據,等待期間你可以在這裡做點別的事情
……
goto __lblSend;
}
else
{
//* 發送失敗,協議棧底層捕捉到了一個嚴重的系統錯誤,這裡增加你的容錯代碼並列印錯誤信息,不再繼續發送
……
printf("發送失敗,%s\r\n", onps_get_last_error(hSocket, NULL));
}
……
is_tcp_send_ok
功能
非阻塞型,數據是否已成功送達tcp鏈路的對端(已收到對端回饋的tcp ack報文)。
原型
INT is_tcp_send_ok(SOCKET socket);
入口參數
- socket:socket句柄
返回值
0:發送中
1:發送成功
-1:發送失敗,具體錯誤信息通過onps_get_last_error()函數獲得
示例
EN_ONPSERR enErr;
……
UCHAR ubUserData[128];
INT nRtnVal;
__lblSend:
nRtnVal = send_nb(hSocket, ubUserData, sizeof(ubUserData));
if(sizeof(ubUserData) == nRtnVal)
{
//* 數據已通過網卡成功送出,接下來輪詢等待對端回饋的tcp ack報文,確保數據成功送達對端
while(1)
{
INT nResult = is_tcp_send_ok(hSocket);
if(nResult == 1)
{
//* 發送成功了,退出輪詢等待
break;
}
else if(nResult < 0)
{
//* 協議棧底層捕捉到了一個嚴重的系統錯誤,不再輪詢等待,並列印錯誤信息
……
printf("%s\r\n", onps_get_last_error(hSocket, NULL));
break;
}
//* 發送中,在這裡你可以做點別的事情
……
}
……
}
else if(0 == nRtnVal)
{
//* 上一組數據尚未發送完畢,需要等待發送完畢後再發送當前數據,等待期間你可以在這裡做點別的事情
……
goto __lblSend;
}
else
{
//* 發送失敗,協議棧底層捕捉到了一個嚴重的系統錯誤,這裡列印錯誤信息,不再繼續發送
printf("發送失敗,%s\r\n", onps_get_last_error(hSocket, NULL));
}
……
sendto
功能
非阻塞型,僅用於udp通訊,發送數據到指定的目標地址。
原型
INT sendto(SOCKET socket, const CHAR *dest_ip, USHORT dest_port, UCHAR *pubData, INT nDataLen);
入口參數
- socket:socket句柄
- dest_ip:目標地址
- dest_port:目標埠
- pubData:指向要發送的數據的指針
- nDataLen:要發送的數據的長度,單位:位元組
返回值
發送成功,返回值等於nDataLen,反之則發送失敗,具體的錯誤信息通過onps_get_last_error()獲得。
示例
EN_ONPSERR enErr;
……
UCHAR ubUserData[128];
INT nSndBytes = sendto(hSocket, "47.92.239.107", 6411, ubUserData, sizeof(ubUserData));
if(sizeof(ubUserData) == nSndBytes)
{
//* 發送成功,在這裡增加你自己的業務代碼
……
}
else
{
//* 發送失敗,在這裡增加你自己的容錯代碼並列印錯誤信息
……
printf("發送失敗,%s\r\n", onps_get_last_error(hSocket, NULL));
}
……
recv
功能
讀取鏈路對端發送的數據。其阻塞類型取決於socket_set_rcv_timeout()函數設定的接收等待時長。預設為阻塞型,一直等待直至收到數據或報錯。
原型
INT recv(SOCKET socket, UCHAR *pubDataBuf, INT nDataBufSize);
入口參數
- socket:socket句柄
- pubDataBuf:指向數據接收緩衝區的指針
- nDataBufSize:數據接收緩衝區的大小,單位:位元組
返回值
大於等於0為實際到達的數據長度,單位:位元組;小於0,接收失敗,具體的的錯誤信息通過onps_get_last_error()獲得。
示例
EN_ONPSERR enErr;
……
UCHAR ubRcvBuf[1500];
INT nRcvBytes = recv(hSocket, ubRcvBuf, sizeof(ubRcvBuf));
if(nRcvBytes > 0) //* 收到數據
{
……
}
else
{
if(nRcvBytes < 0) //* 協議棧底層捕捉到了一個嚴重錯誤,在這裡增加你的容錯代碼並列印錯誤信息
{
……
printf("%s\r\n", onps_get_last_error(hSocket, NULL));
}
}
……
socket_set_rcv_timeout
功能
設定recv()函數接收等待的時長。其設定的接收等待時長決定了recv()函數的阻塞類型。
等於0:非阻塞,recv()不等待立即返回
大於0:阻塞,recv()等待指定時長直至數據到達或超時
小於0:阻塞,recv()一直等待直至數據到達或出錯
原型
BOOL socket_set_rcv_timeout(SOCKET socket, CHAR bRcvTimeout, EN_ONPSERR *penErr);
入口參數
- family:目前僅支持IPv4地址,即AF_INET,其它地址族如AF_INET6之類的不支持
- bRcvTimeout:recv()函數的接收等待時長,單位:秒
- penErr:指向錯誤編碼的指針,當socket()函數執行失敗,該參數用於接收實際的錯誤碼
返回值
設置成功返回TRUE,否則返回FALSE,具體的錯誤信息通過參數penErr獲得。
示例
EN_ONPSERR enErr;
……
if(!socket_set_rcv_timeout(hSocket, 1, &enErr))
{
//* 設置失敗,列印錯誤信息,此時系統採用預設值,即recv()函數一直等待直至收到數據或協議棧報錯
printf("%s\r\n", onps_error(enErr));
}
……
recvfrom
功能
接收數據並返回數據源的地址信息,僅用於udp通訊。
原型
INT recvfrom(SOCKET socket, UCHAR *pubDataBuf, INT nDataBufSize, in_addr_t *punFromIP, USHORT *pusFromPort);
入口參數
- family:目前僅支持IPv4地址,即AF_INET,其它地址族如AF_INET6之類的不支持
- pubDataBuf:指向數據接收緩衝區的指針
- nDataBufSize:數據接收緩衝區的大小,單位:位元組
- punFromIP:指向數據源ip地址的指針
- pusFromPort:指向數據源埠的指