非阻塞socket程式設計

2021-07-10 20:44:36 字數 3265 閱讀 4188

阻塞:阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。該程序被標記為睡眠狀態並被排程出去。函式只有在得到結果之後才會返回。當socket工作在阻塞模式的時候, 如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。

非阻塞:非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不會阻塞當前執行緒,而會立刻返回。epoll工作在非阻塞模式時,才會發揮作用。

blocking io: 發起io操作後阻塞當前執行緒直到io結束,標準的同步io,如預設行為的posix read和write。

non-blocking io: 發起io操作後不阻塞,使用者可阻塞等待多個io操作同時結束。non-blocking也是一種同步io:「批量的同步」。如linux下的poll,select, epoll,bsd下的kqueue。

正常情況下,socket工作在阻塞模式下,在呼叫accept,connect,read,write等函式時,都是阻塞方式,直到讀到資料才會返回。但是,如果將socket設定為非阻塞狀態,那麼這麼些函式就會立即返回,不會阻塞當前執行緒。

設定非阻塞socket的方法是:

int setnonblock(int isock)

tcp的socket一旦通過listen()設定為server後,就只能通過accept()函式,被動地接受來自客戶端的connect請求。程序對accept()的呼叫是阻塞的,就是說如果沒有連線請求就會進入睡眠等待,直到有請求連線,接受了請求(或者超過了預定的等待時間)才會返回。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

返回值是乙個新的套接字描述符,它代表的是和客戶端的新的連線,可以把它理解成是乙個客戶端的socket,這個socket包含的是客戶端的ip和port資訊 。失敗返回-1, 錯誤原因存於errno 中。

之後的read和write函式中的fd都是指這個 new_fd。

阻塞模式下呼叫accept()函式,而且沒有新連線時,程序會進入睡眠狀態

非阻塞模式下呼叫accept()函式,而且沒有新連線時,將返回ewouldblock(11)錯誤

可以用以下**來測試:

int setnonblock(int isock)

int main(int argc, char* argv)

; servaddr.sin_family = af_inet;

inet_pton(af_inet, ip_.c_str(), &servaddr.sin_addr);

servaddr.sin_port = htons(port_);

int ret = ::connect(fd_, (struct sockaddr *)&servaddr, sizeof(servaddr));

if(ret == 0)

int error = 0;

socklen_t len = sizeof (error);

if(errno != einprogress)

fd_set wset;//寫集合

fd_zero(&wset);

fd_set(fd_, &wset);

struct timeval tval;

tval.tv_sec = 3;//3s

tval.tv_usec = 0;

if (select(fd_ + 1, null, &wset, null, &tval) == -1) //出錯、超時,連線失敗

if(!fd_isset(fd_, &wset))//不可寫

if (getsockopt(fd_, sol_socket, so_error, &error, &len) == -1)

if(error)

is_connected_ = true;

return 0;

__fail:

close(fd_);

return -1;

}

對於寫操作write,非阻塞socket在傳送緩衝區沒有空間時會直接返回-1,錯誤號ewouldblock或eagain,表示沒有空間可寫資料,如果錯誤號是別的值,則表明傳送失敗。

如果傳送緩衝區中有足夠空間或者是不足以拷貝所有待傳送資料的空間的話,則拷貝前面n個能夠容納的資料,返回實際拷貝的位元組數。

而對於阻塞socket而言,如果傳送緩衝區沒有空間或者空間不足的話,write操作會直接阻塞住,如果有足夠空間,則拷貝所有資料到傳送緩衝區,然後返回。

實現**:

/**

* 返回-1:失敗

* 返回》0: 成功

*/int writenonblock(int fd, const char* send_buf, size_t send_len)

else//遇到eagain直接退出

}sentlen += ret;

}return sentlen;

}

對於阻塞的socket,當socket的接收緩衝區中沒有資料時,read呼叫會一直阻塞住,直到有資料到來才返回。

當socket緩衝區中的資料量小於期望讀取的資料量時,返回實際讀取的位元組數。

當sockt的接收緩衝區中的資料大於期望讀取的位元組數時,讀取期望讀取的位元組數,返回實際讀取的長度。

對於非阻塞socket而言,socket的接收緩衝區中有沒有資料,read呼叫都會立刻返回。

接收緩衝區中有資料時,與阻塞socket有資料的情況是一樣的,如果接收緩衝區中沒有資料,則返回-1,

錯誤號為ewouldblock或eagain,表示該操作本來應該阻塞的,但是由於本socket為非阻塞的socket,

因此立刻返回,遇到這樣的情況,可以在下次接著去嘗試讀取。如果返回值是其它負值,則表明讀取錯誤。

實現**:

/**

* 返回-1:失敗

* 返回》0: 成功

*/int readnonblock(int fd, char* recv_buf, size_t recv_len)

else if(ret > 0)

else if(errno == eintr)

else//遇到eagain直接退出

}return readlen;

}

recvfrom,sendto等函式也是同樣類似的方法。

非阻塞socket程式設計

socket程式設計中可能出現阻塞的呼叫有4個 1.write send sendto sendmsg sendv等,如果某個程序呼叫乙個阻塞的tcp套接字 預設設定 如果傳送緩衝區沒有空間,呼叫程序將會睡眠,直到有空間為止。如果tcp套接字是非阻塞的,且沒有空間可寫,則會返回乙個ewouleblo...

非阻塞socket程式設計

阻塞 阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。該程序被標記為睡眠狀態並被排程出去。函式只有在得到結果之後才會返回。當socket工作在阻塞模式的時候,如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。非阻塞 非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函式不...

socket程式設計 阻塞和非阻塞

阻塞方式下,connect首先傳送syn請求道伺服器,當客戶端收到伺服器返回的syn的確認時,則connect返回.否則的話一直阻塞.非阻塞方式,connect將啟用tcp協議的三次握手,但是connect函式並不等待連線建立好才返回,而是立即返回。返回的錯誤碼為einprogress,表示正在進行...