專案總結三 解決TCP UDP通訊函式阻塞

2021-10-24 01:51:12 字數 3365 閱讀 7689

需要解決問題:

主備執行緒身份判斷udp:recvfrom函式設定阻塞,影響程式執行下面的**

tcp:connect連線到伺服器時間過長,影響介面操作

原因:socket在預設情況下是阻塞狀態的,這就使得傳送以及接收操作處於阻塞的狀態,即呼叫不會立即返回,而是進入睡眠等待    操作完成。

解決方法:

設定socket套接字非阻塞,下面進行詳解(在查詢資料中也學到了許多)。

設定udp傳送以及接收操作非阻塞,主要用到了setsockopt這個函式:

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

引數:  

sock:將要被設定或者獲取選項的套接字。

level:選項所在的協議層。

optname:需要訪問的選項名。

optval:對於getsockopt(),指向返回選項值的緩衝。對於setsockopt(),指向包含新選項值的緩衝。

optlen:對於getsockopt(),作為入口引數時,選項值的最大長度。作為出口引數時,選項值的實際長度。對setsockopt(),現選項的長度。

**如下:

#include #include #include #include using namespace std;

int main()

socket sock;

int port = 4528;

sockaddr_in servaddr, cliaddr;

//建立套接字

sock = socket(af_inet, sock_dgram, 0);

if (sock == -1)

// 設定超時

struct timeval timeout;

timeout.tv_sec = 0;//秒

timeout.tv_usec = 100;//微秒

if (setsockopt(sock, sol_socket, so_rcvtimeo, (char*)&timeout, sizeof(timeout)) == -1)

servaddr.sin_family = af_inet;

inet_pton(af_inet, "192.167.0.1", &servaddr.sin_addr.s_un.s_addr);//ip位址

servaddr.sin_port = htons(port);

if (bind(sock, (sockaddr*)&servaddr, sizeof(sockaddr)) == -1)

int len = sizeof(sockaddr);

for (; ; ) ;

int n = recvfrom(sock, mesg, 1024, 0, (sockaddr*)&cliaddr, &len);

perror("recvfrom fail: ");

} return 0;

}

經bug發現:setsockopt函式設定非阻塞只對秒級以上有效,上面**中100微妙沒有作用

當用tcp通訊時,tcp客戶端要與服務端通訊,必須先建立連線,即呼叫connect函式完成三次握手,而預設情況下connect是阻塞方式的,也就是說呼叫connect函式會發生阻塞,超時時間可能在10s至幾分鐘之間。這就會導致很長時間的等待,而我的tcp函式在介面程式中呼叫,導致介面進入假死的狀態,無法響應。

為避免等待長時間的connect,使用非阻塞connect方式來處理,集體步驟大致為:

建立socket,返回套介面描述符

呼叫ioctlsocket把套介面描述符設定成非阻塞

呼叫connect開始建立連線

判斷連線是否成功建立     a: 如果connect返回0,表示連線成功(伺服器和客戶端在同一臺機器上時就有可能發生這種情況)                

b: 呼叫select來等待連線建立成功完成    

繼續判斷select返回值

a:如果select返回0,則表示建立連線超時;

b: 如果select返回大於0的值,則需要檢查套介面描述符是否可讀或可寫;如果套介面描述符可讀或可寫,則我們可以通過呼叫getsockopt來得到套介面上待處理的錯誤(so_error),如果連線建立成功,這個錯誤值將是0,如果建立連線時遇到錯誤,則這個值是連線錯誤所對應的errno值(比如:econnrefused,etimedout等).        

ioctlsocket函式說明

函式原型:

int ioctlsocket( socket s, long cmd, u_long far *argp );

引數:s:乙個標識套介面的描述字。 

cmd:對套介面s的操作命令。 

argp:指向cmd命令所帶引數的指標

使用:u_long mode = 0;

ioctlsocket(s,fionbio,&mode);

//控制為阻塞方式。

u_long mode = 1;

ioctlsocket(s,fionbio,&mode);

//控制為非阻塞方式。 

**如下 :

#include #include #include #include using namespace std;

bool sendoperrecordtohisdb();

int main()

bool sendoperrecordtohisdb()

int ret = connect(sock, (struct sockaddr*)&inetaddr, sizeof(inetaddr));

//因為是非阻塞的,這個時候錯誤碼應該是wsaewouldblock,linux下是einprogress

if (ret < 0 && wsagetlasterror() != wsaewouldblock)

//返回值大於等於0

fd_set writeset;

fd_zero(&writeset);

fd_set(sock, &writeset);

timeval tv;

tv.tv_sec = timeout;

tv.tv_usec = 0;

ret = select(sock + 1, null, &writeset, null, &tv);

if (ret > 0)

if (ret == 0)

closesocket(sock);

return true;

}

通訊總結之三 XMPP

之前的伺服器與客戶端的通訊過程中,雙方都是直接傳送資訊內容,並預設以回車符結尾,這樣的通訊方式 也可以算作一種協議 所包含的資訊過於簡單與貧乏。沒有包含資訊的型別 登入 驗證 私聊等 的資訊,也不能包含發信人,收信人的資訊,這只能在簡單群聊伺服器中使用。如果在比如qq 等這些較為複雜的聊天環境下就顯...

miniftp專案總結(三)

struct stat 結構體 dirent struct dirent const char statbuf get perms struct stat sbuf if mode s irusr if mode s iwusr if mode s ixusr if mode s irgrp if ...

通訊錄專案有關總結

功能模組 聯絡人 聯絡歷史 撥打 簡訊聊天 1.聯絡人管理涉及的表 contacts 聯絡人表 一條記錄記錄乙個聯絡人資訊 與 raw contacts 是一對多的關係 raw contacts 聯絡人的賬戶資訊乙個 raw contacts 有多種型別的資料對應多種 data 表 data 聯絡人...