onps棧使用說明(1)——API介面手冊

来源:https://www.cnblogs.com/neo-T/archive/2022/11/09/onps-4.html
-Advertisement-
Play Games

Red Giant PluralEyes for Mac雖然只是Shooter Suite其中的一部分,但是卻十分受歡迎,功能也非常強大。PluralEyes Mac版提供了用戶需要的音頻和視頻同步的一切功能,可以自動分析視頻和音頻文件,並同步起來。 詳情:Red Giant PluralEyes ...


1. 底層API

       由協議棧底層提供的api,用於涉及底層操作的一些功能實現,這些api介面函數的原型定義分佈於不同的文件,它們被統一include進了onps.h中:

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:指向數據源埠的指
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果在代碼中寫死了(hardcode)文件名,每次要加解密文件都要去改python源代碼,顯然有些太笨了。為此,可以使用命令行參數來在不改動源代碼的情況下,對命令行參數所指定的文件進行加/解密操作。也可以指定加解密後輸出的文件名稱,以方便使用。 ...
  • 簡介: 門面模式又稱之為外觀模式,屬於結構型的設計模式。 用於為子系統中的一組介面提供一致的調用方案。門面模式定義了一個高層介面,引入門面角色之後,只需要直接與門面角色交互,降低了系統的耦合度。 適用場景: 最經典的Laravel的Facade,當使用一些庫的時候,不需要瞭解底層系統如何實現,只需要 ...
  • 一、基礎命令 在我們使用深度學習時,肯定會用到繪圖命令,繪製loss與val_loss等等,以此查看模型的效果。 plt.plot(x,y,lw=,ls=,c=, alpha=, label=) x:x坐標的數據 y:y坐標的數據 lw:指定線條寬度 ls:指定線條樣式,ls='-'為實線,ls=' ...
  • 哈嘍兄弟們,今天咱們來複習一下Python基礎中的列表操作,不知道各位還記得多少呢? 遍歷整個列表加粗樣式 遍歷列表的所有元素,對每一個元素進行相同的操作,是我們常常所需要的。在python中可使用for()迴圈。 假如我們需要將一個列表中的手機品牌一一列印,我們可以分別獲取手機品牌的名字。如果數據 ...
  • 一、基本介紹 參考:https://www.hangge.com/blog/cache/detail_2844.html 1、為什麼搭建私服 如果沒有私服,需要的構件都需要通過maven的中央倉庫或者第三方的maven倉庫下載到本地,而一個團隊的所有人都重覆的從maven倉庫下載構件加大了倉庫的負載 ...
  • 1. 什麼是死鎖 在多線程環境中,多個進程可以競爭有限數量的資源。當一個進程申請資源時,如果這時沒有可用資源,那麼這個進程進入等待狀態。有時,如果所申請的資源被其他等待進程占有,那麼該等待進程有可能再也無法改變狀態。這種情況稱為死鎖 在Java中使用多線程,就會有可能導致死鎖問題。死鎖會讓程式一直卡 ...
  • 前言 之前想用Markdown來寫框架文檔,找來找去發現還是Jekyll的多,但又感覺不是很合我的需求 於是打算自己簡單弄一個展示Markdown文檔的網站工具,要支持多版本、多語言、導航、頁內導航等,並且支持Github Pages免費站點 組件選擇 我自己呢比較喜歡C#,恰好現在ASP.Net ...
  • 一:背景 1.講故事 這篇文章起源於昨天的一位朋友發給我的dump文件,說它的程式出現了卡死,看了下程式的主線程棧,居然又碰到了 OnUserPreferenceChanged 導致的掛死問題,真的是經典中的經典,線程棧如下: 0:000:x86> !clrstack OS Thread Id: 0 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...