需要解決問題:
主備執行緒身份判斷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函式說明呼叫ioctlsocket把套介面描述符設定成非阻塞
呼叫connect開始建立連線
判斷連線是否成功建立 a: 如果connect返回0,表示連線成功(伺服器和客戶端在同一臺機器上時就有可能發生這種情況)
b: 呼叫select來等待連線建立成功完成
繼續判斷select返回值
a:如果select返回0,則表示建立連線超時;
b: 如果select返回大於0的值,則需要檢查套介面描述符是否可讀或可寫;如果套介面描述符可讀或可寫,則我們可以通過呼叫getsockopt來得到套介面上待處理的錯誤(so_error),如果連線建立成功,這個錯誤值將是0,如果建立連線時遇到錯誤,則這個值是連線錯誤所對應的errno值(比如:econnrefused,etimedout等).
函式原型:**如下 :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 聯絡人...