當前位置:首頁 » 操作系統 » linux設置socket超時

linux設置socket超時

發布時間: 2023-03-29 18:34:34

linux socket 連接超時 怎麼解決

今天發現自己的系統存在很嚴重缺陷,當前台關閉的時候後台就無法正常工作,原因很好定位,後台的socket連接超時時間過長,系統默認時間好像是75秒,於是找資料,根據下邊文章中的內容解決了,把超時時間設為5秒後,感覺好多了。看來還有好多東西需要慢慢挖掘阿!

如何設置socket的Connect超時(linux)
[From]http://dev.cbw.com/c/c/200510195601_4292587.shtml
1.首先將標志位設為Non-blocking模式,准備在非阻塞模式下調用connect函數
2.調用connect,正常情況下,因為TCP三次握手需要一些時間;而非阻塞調用只要不能立即完成就會返回錯誤,所以這里會返回EINPROGRESS,表示在建立連接但還沒有完成。
3.在讀套介面描述符集(fd_set rset)和寫套介面描述符集(fd_set wset)中將當前套介面置位(用FD_ZERO()、FD_SET()宏),並設置好超時時間(struct timeval *timeout)
4.調用select( socket, &rset, &wset, NULL, timeout )
返回0表示connect超時
如果你設置的超時時間大於75秒就沒有必要這樣做了,因為內核中對connect有超時限制就是75秒。

[From]http://www.ycgczj.com.cn/34733.html
網路編程中socket的分量我想大家都很清楚了,socket也就是套介面,在套介面編程中,提到超時的概念,我們一下子就能想到3個:發送超時,接收超時,以及select超時(註: select函數並不是只用於套介面的,但是套介面編程中用的比較多),在connect到目標主機的時候,這個超時是不由我們來設置的。不過正常情況下這個超時都很長,並且connect又是一個阻塞方法,一個主機不能連接,等著connect返回還能忍受,你的程序要是要試圖連接多個主機,恐怕遇到多個不能連接的主機的時候,會塞得你受不了的。我也廢話少說,先說說我的方法,如果你覺得你已掌握這種方法,你就不用再看下去了,如果你還不了解,我願意與你分享。本文是已在Linux下的程序為例子,不過拿到Windows中方法也是一樣,無非是換幾個函數名字罷了。
Linux中要給connect設置超時,應該是有兩種方法的。一種是該系統的一些參數,這個方法我不講,因為我講不清楚:P,它也不是編程實現的。另外一種方法就是變相的實現connect的超時,我要講的就是這個方法,原理上是這樣的:
1.建立socket
2.將該socket設置為非阻塞模式
3.調用connect()
4.使用select()檢查該socket描述符是否可寫(注意,是可寫)
5.根據select()返回的結果判斷connect()結果
6.將socket設置為阻塞模式(如果你的程序不需要用阻塞模式的,這步就省了,不過一般情況下都是用阻塞模式的,這樣也容易管理)
如果你對網路編程很熟悉的話,其實我一說出這個過程你就知道怎麼寫你的程序了,下面給出我寫的一段程序,僅供參考。
/******************************
* Time out for connect()
* Write by Kerl W
******************************/
#include <sys/socket.h>
#include <sys/types.h>
#define TIME_OUT_TIME 20 //connect超時時間20秒
int main(int argc , char **argv)
{
………………
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) exit(1);
struct sockaddr_in serv_addr;
………//以伺服器地址填充結構serv_addr
int error=-1, len;
len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctl(sockfd, FIONBIO, &ul); //設置為非阻塞模式
bool ret = false;
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
tm.tv_set = TIME_OUT_TIME;
tm.tv_uset = 0;
FD_ZERO(&set);
FD_SET(sockfd, &set);
if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if(error == 0) ret = true;
else ret = false;
} else ret = false;
}
else ret = true;
ul = 0;
ioctl(sockfd, FIONBIO, &ul); //設置為阻塞模式
if(!ret)
{
close( sockfd );
fprintf(stderr , "Cannot Connect the server!n");
return;
}
fprintf( stderr , "Connected!n");
//下面還可以進行發包收包操作
……………
}
以上代碼片段,僅供參考,也是為初學者提供一些提示,主要用到的幾個函數,select, ioctl, getsockopt都可以找到相關資料,具體用法我這里就不贅述了,你只需要在linux中輕輕的敲一個man <函數名>就能夠看到它的用法。
此外我需要說明的幾點是,雖然我們用ioctl把套介面設置為非阻塞模式,不過select本身是阻塞的,阻塞的時間就是其超時的時間由調用select 的時候的最後一個參數timeval類型的變數指針指向的timeval結構變數來決定的,timeval結構由一個表示秒數的和一個表示微秒數(long類型)的成員組成,一般我們設置了秒數就行了,把微妙數設為0(註:1秒等於100萬微秒)。而select函數另一個值得一提的參數就是上面我們用到的fd_set類型的變數指針。調用之前,這個變數裡面存了要用select來檢查的描述符,調用之後,針對上面的程序這裡面是可寫的描述符,我們可以用宏FD_ISSET來檢查某個描述符是否在其中。由於我這里只有一個套介面描述符,我就沒有使用FD_ISSET宏來檢查調用select之後這個sockfd是否在set裡面,其實是需要加上這個判斷的。不過我用了getsockopt來檢查,這樣才可以判斷出這個套介面是否是真的連接上了,因為我們只是變相的用select來檢查它是否連接上了,實際上select檢查的是它是否可寫,而對於可寫,是針對以下三種條件任一條件滿足時都表示可寫的:
1)套介面發送緩沖區中的可用控制項位元組數大於等於套介面發送緩沖區低潮限度的當前值,且或者i)套介面已連接,或者ii)套介面不要求連接(UDP方式的)
2)連接的寫這一半關閉。
3)有一個套介面錯誤待處理。
這樣,我們就需要用getsockopt函數來獲取套介面目前的一些信息來判斷是否真的是連接上了,沒有連接上的時候還能給出發生了什麼錯誤,當然我程序中並沒有標出那麼多狀態,只是簡單的表示可連接/不可連接。
下面我來談談對這個程序測試的結果。我針對3種情形做了測試:
1. 目標機器網路正常的情況
可以連接到目標主機,並能成功以阻塞方式進行發包收包作業。
2. 目標機器網路斷開的情況
在等待設置的超時時間(上面的程序中為20秒)後,顯示目標主機不能連接。
3. 程序運行前斷開目標機器網路,超時時間內,恢復目標機器的網路
在恢復目標主機網路連接之前,程序一隻等待,恢復目標主機後,程序顯示連接目標主機成功,並能成功以阻塞方式進行發包收包作業。
以上各種情況的測試結果表明,這種設置connect超時的方法是完全可行的。我自己是把這種設置了超時的connect封裝到了自己的類庫,用在一套監控系統中,到目前為止,運行還算正常。這種編程實現的connect超時比起修改系統參數的那種方法的有點就在於它只用於你的程序之中而不影響系統。

⑵ linuxsocket無法斷開

c++
Linux環境中使用socket進行UDP和TCP多線程通信無法關閉socket

(^v^)
原創
關注
0點贊·641人閱讀
在Linux下,使用QT編程網路通信,為提高通信效率,使用原始socket進行網路編程,在QT線程中經常出現線程無法退出,原因來源於socket無法關閉。
線程處理如下:

void communicationClass::run()
{
// 開啟數據處理線程
#ifdef Q_OS_LINUX
//配置伺服器信息
bzero(&m_sServer_addr, sizeof(m_sServer_addr));
m_sServer_addr.sin_family = AF_INET;
//設置為IPV4通信
m_sServer_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//設置目的ip
m_sServer_addr.sin_addr.s_addr = inet_addr(m_strSendIP.toStdString().c_str());
//設置目的埠去鏈接伺服器
m_sServer_addr.sin_port = htons(m_ui16Port);

//配置本地信息
bzero(&m_sLocal_addr, sizeof(m_sLocal_addr));
m_sLocal_addr.sin_family = AF_INET;
//設置為IPV4通信
//loc_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//設置目的ip
m_sLocal_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//設置本地埠去鏈接伺服器
m_sLocal_addr.sin_port = htons(m_ui16Port);
m_iSockedFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //設置UDP報文傳輸 0表示默認 SOCK_DGRAM 默認使用UDP
//其中第三位 0 是調用方式標志位嫌岩吵,設置socket通方式,比如非阻塞
if(m_iSockedFd<0)
{
emit signal_networkInfoError(false, "棗豎socket create failure");
return;
}

//將本地配置使用bind綁定
int ret = bind(m_iSockedFd,(struct sockaddr*)&m_sLocal_addr,sizeof (m_sLocal_addr));
if(ret < 0)
{
emit signal_networkInfoError(false, "socket bind failure");
return;
}
emit signal_networkInfoError(true, "network success");
// 線程芹侍循環等待數據
while (!isInterruptionRequested())
{
char buf[1600];
int count = 0;
socklen_t i_server_addr_len = sizeof(m_sServer_addr);
count = recvfrom(m_iSockedFd, buf, sizeof(buf), 0, (struct sockaddr*)&m_sServer_addr,&i_server_addr_len);
if (count > 0)
{
// 組裝返回數據buffer
QByteArray arrayRecvData;
arrayRecvData.resize(count);
memcpy(arrayRecvData.data(), buf, count);
// qDebug() << "接收到數據:" << arrayRecvData.size();
emit signal_recvNetworkData(arrayRecvData);
}
msleep(1);
}
#endif

#ifdef Q_OS_WIN32
// 確定版本信息
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
emit signal_networkInfoError(false, "Version failure");
return;
}
// 創建socket
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET == m_socket)
{
emit signal_networkInfoError(false, "socket create failure");
return;
}
// 初始化本地地址信息
//地址族
m_sLocal_addr.sin_family = AF_INET;
//埠
m_sLocal_addr.sin_port = htons(m_ui16Port);
//IP
m_sLocal_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 初始化伺服器地址信息
//地址族
m_sServer_addr.sin_family = AF_INET;
//埠
m_sServer_addr.sin_port = htons(m_ui16Port);
//IP
m_sServer_addr.sin_addr.s_addr = inet_addr(m_strSendIP.toStdString().c_str());

int ret = bind(m_socket, (sockaddr*)&m_sLocal_addr, sizeof(m_sLocal_addr));
if (ret < 0)
{
emit signal_networkInfoError(false, "socket bind failure");
return;
}
emit signal_networkInfoError(true, "network success");
// 線程循環等待數據
while (!isInterruptionRequested())
{
char buf[1600];
// memset(buf,0,1600*sizeof(char));
int count = 0;
count = recv(m_socket, buf, sizeof(buf), 0);
if (count > 0)
{
// 組裝返回數據buffer
QByteArray arrayRecvData;
arrayRecvData.resize(count);
memcpy(arrayRecvData.data(), buf, count);
emit signal_recvNetworkData(arrayRecvData);
}
}
#endif
qDebug() << "communicationClass quit";
}
復制

退出線程:

#ifdef Q_OS_LINUX
close(m_iSockedFd);
#endif

#ifdef Q_OS_WIN32
closesocket(m_socket);
WSACleanup();
#endif
requestInterruption();
復制
在windows下線程能優雅退出。

但在Linux中會出現close()關閉socket失敗。
解決方法:

#include<sys/socket.h>
int shutdown(int sockfd,int how);
TCP連接是雙向的(是可讀寫的),當我們使用close時,會把讀寫通道都關閉,有時侯我們希望只關閉一個方向,這個時候我們能夠使用shutdown.
how的方式有三種分別是
SHUT_RD(0):關閉sockfd上的讀功能,此選項將不允許sockfd進行讀操作。
SHUT_WR(1):關閉sockfd的寫功能,此選項將不允許sockfd進行寫操作。
SHUT_RDWR(2):關閉sockfd的讀寫功能。
成功則返回0,錯誤返回-1,錯誤碼errno:EBADF表示sockfd不是一個有效描述符;ENOTCONN表示sockfd未連接;ENOTSOCK表示sockfd是一個文件描述符而不是socket描述符。

⑶ 我想請教LINUX 下socket 超時設置的問題

我建議 閱讀 《unix網路編程》裡面有很詳細的解釋

舉個例子:
你可以把socket的IO操作看做是等人
阻塞:
你站在和人越好的地毀念方等人,你們的約定了一個時槐森間,當你等的時間超過了這個時間後你就可以離開這個地點去干其他的事情,否則你將繼續在這里等人。而INFINIT就是無限等待下去

非阻塞:
就是你不需要站在越好的地點等人,你可以作在離這個地點很近的纖明困一個咖啡廳喝茶聽音樂,但你能夠看到這個約定地點的情況,一旦有人來你就可以走過去和那個人見面

阻塞:人來了以後你可以第一時間見到,而不用別人等你
非阻塞:和你正在做的事情有關,如果你在坐在咖啡廳看電視,就很有可能造成別人等你的情況了

⑷ LINUX C 進行TCP網路連接,怎樣設置連接超時時間

如果你確定,真的不需要等這么久,或者用戶希望可以隨時中上連接過程,那麼一般是用 非阻塞模式來做的. 看看我的這段連接代碼(節選),可以作為TCP連接的典範:

bool CRemoteLink::Connect()
{
OnDisconnected(); // 如果已經連接,則斷開

if(!m_bUseProxy)
{

m_iConnStatus = SS_CONNECTING; // 正在連接狀態
GNTRACE ("開始連接到遠程伺服器[%s][%ld]...\n", m_strip.c_str(), m_port);

// 建立套接字, 准備連接到伺服器
m_socket = ::socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0) {
if(m_pCallBack)
m_pCallBack->OnSocketError(SE_CREATE, MSG_SE_CREATE);
return false;
}

// 設為非同步操作方式
unsigned long on = 1;
if (::ioctlsocket(m_socket, FIONBIO, &on) < 0) {
::closesocket(m_socket);
if(m_pCallBack)
m_pCallBack->OnSocketError(SE_CREATE, MSG_SE_CREATE);
return false;
}

sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(m_strip.c_str());
addr.sin_port = htons(m_port);

int rt;
rt = ::connect(m_socket, (sockaddr *) &addr, sizeof(addr));
if (rt == 0) {
OnConnected();
return true;
}

// ==================================================================
timeval to;

// 首先建立連接
fd_set wfds;
fd_set efds;
FD_ZERO(&wfds);
FD_ZERO(&efds);

// test shutdown event each 100ms.
to.tv_sec = 0;
// CONNECT_TIMEOUT;
to.tv_usec = 100000;

int it = 0;
while(!m_meShutdown.Wait(0) && !m_meConnStop.Wait(0))
{
FD_SET(m_socket, &wfds);
FD_SET(m_socket, &efds);
int n = select(m_socket + 1, NULL, &wfds, &efds, &to);

if (n > 0) {
if(FD_ISSET(m_socket, &wfds))
{
OnConnected();
return true;
}
else
{
//int err = ::WSAGetLastError();
//const char* msg = GetLastErrorMessage(err);
GNTRACE ("CRemoteLink::Connect : connection attempt failed!\n");
if(m_pCallBack)
m_pCallBack->OnSocketError(SE_CONN, MSG_SE_CONN);
break;
}
} else if (n < 0) { // Select Error
int err = ::WSAGetLastError();
const char* msg = GetLastErrorMessage(err);
GNTRACE ("CRemoteLink::Connect : Select Error.[%d] - %s\n", err, msg);
if(m_pCallBack)
m_pCallBack->OnSocketError(err, msg);
break;
}
else
{
it += 100;
if(it > 30000) // 連接超時 -- (30S)
{
GNTRACE ("CRemoteLink::Connect : Time out.\n");
if(m_pCallBack)
m_pCallBack->OnSocketError(SE_TIMEOUT, MSG_SE_TIMEOUT);
break;
}
}
}
if(m_meConnStop.Wait(0))
{
GNTRACE("連接過程進行時被取消。\n");
}
}
else
{
// 通過代理伺服器連接

⑸ Linux下socket並發連接數怎麼設置

並發socket連接數的多少決定於系統資源的多少,沒有一個常值的.在實際開發或者linux系統管理中也會根據需配段要進行相應的設置.
1.一般來說每一個網路連接,都會敗銷建立相應的socket句柄,同時每個連接也會有標准輸入輸出等基本的文件文件句柄,而且每一個socket連接都是進行文件操作的,因此連接數決定於系統資源.

2.Linux上一般可以通過ulimit來進行相應的資源限制,默認能打開的文件描述符自己可以查看.如下圖所示:

3.ulimit的命令格式:ulimit [-acdfHlmnpsStvw] [size]
參數說明:
-H 設置硬資源限制.
-S 設置軟資源限制.
-a 顯示當前所有的資源限制.
-c size:設置core文件的最大值.單位:blocks
-d size:設置數據段的最大值.單位:kbytes
-f size:設置創建文件的最大值.單位:blocks
-l size:設置在內存中鎖定進程的最大值.單位:kbytes
-m size:設置可以使用的培枯譽常駐內存的最大值.單位:kbytes
-n size:設置內核可以同時打開的文件描述符的最大值.單位:n
-p size:設置管道緩沖區的最大值.單位:kbytes
-s size:設置堆棧的最大值.單位:kbytes
-t size:設置CPU使用時間的最大上限.單位:seconds
-v size:設置虛擬內存的最大值.單位:kbytes
-u <程序數目> 用戶最多可開啟的程序數目

⑹ socket超時什麼意思

你好,這分為兩種情況。
Socket.connect連接超時有二種情況:
1.由於網路的問題,TCP/IP三次握手時間>timeout的設置時間。這在國外訪問weibo時,並且網路環境極差的情況下有可能發生。
解決的辦法:調大socket.connect方法中的timeout參數值,比如50s,linux默認最高是70s,如果超過70s沒有意義,linux會採用70s.
但是當調大之後,發現不到10s就報timeout exception。
通過國外的機器ping api.weibo.com發現unreachable。
說明客戶端在傳輸層之下的網路層就發現連個Syn的報文都發不出去,更不用說三次握手了,客戶端直接失敗並拋timeout exception。
經驗:在connection timeout診斷的第一步應該是ping一下確認網路層沒有問題。
註:客戶端設置了timeout,但並不會等到超時才返回異常。客戶端只要第一時間發現連接失敗,就會拋timeout exception。

2.如果timeout設置的時間足夠,但是由於伺服器端的處理能力較差,比如緩沖連接隊列較小,而應用層的處理能力沒有連接緩沖快,導致緩沖連接占滿,而拒絕新的連接。
在服務端因為連接隊列占滿而拒絕服務的期間,客戶端的通過TCP協議重試三次。每次的時間翻倍。
如果三次時間的累加<timeout參數值且能連接上,屬於正常情況,表示隊列騰出空位放當前連接。
如果三次時間的累加<timeout參數值且未能連接上,則客戶端會立刻拋出timeout exception,而不等timeout到期才拋。

1.讀寫超時
read超時設置有意義,在伺服器處理能力差,但最終會響應的情況下,可以將客戶端的等待響應時間設長一些。如果太長的話,由於客戶端使用的是BIO的方式,線程會一直阻塞在IO而導致掛起。當客戶端的處理能力明顯快於服務端,這樣掛起的線程會很多。
不管客戶端還是伺服器端,當有很多線程阻塞時,對機器的性能都會影響。我在weibo的論壇上看到有人在read timed out後,將soTimeout的時間設為100s。這是很危險的,新浪的伺服器一旦崩潰,自己的伺服器也會由於大量線程積壓崩潰。
因為線程在掛起之後,它掌握的資源並不會釋放,比如內存,直到阻塞完成。同時大量線程的掛起就意味著系統要做大量上下文的恢復並調度執行。
解決辦法:
如果客戶端使用NIO的方式,如果服務端的響應能標出客戶端的請求,則線程在客戶端請求之後,完全可以把請求放入一個BlockQueue,然後利用Future或Wait/Notify等機制在帶著請求標志的響應返回的時候,喚想隊列中的請求接著處理,從而實現非同步處理,可以用少量線程服務大量請求。
同樣,如果伺服器端可以使用NIO做到請求每線程處理,而不是連接每線程,可以大大減少線程掛起導致資源的浪費,NIO適用於連接很多,請求很少的場合。另外,Commet又稱為伺服器推技術,它的主要特點是長連接。避免客戶端低效的請求輪詢。主要用於聊天室,WEIBO,因為連接多,請求不一定多,同樣也適合在伺服器端使用NIO
註:read timeout異常時,並不需要ping遠程機器,因為它是輔助定位connection timeout,如果ping不通,肯定是conneciton timeout而不會到read timeout。read timeout exception不會導致連接中斷。為重試提供了機會。

2.write超時一般不象connection timeout和read timeout可以在客戶端顯示調值,TCP有寫重傳的概念,一般8m內會重試,否則,直接斷開連接。
如果對您有幫助,還望採納。

⑺ linuxsocket阻塞如何退出

設置套接字為非阻塞模式。
1、通過設置套接字的屬性,把其從阻塞模式改為非阻塞模式,即使沒有數據凳喊到來或者連接建立,程序也不會一直等待,而是立刻返回。
2、褲碰超時機制:在代碼中設置超時機制,即如果套接字在指定時間內依然處於阻塞狀態,則退出程序。
3、信號處理:使用信號處理機制,在另一個線程中棗純野發送一個指定的信號,如SIGINT信號,當程序接收到該信號時,可以退出當前的阻塞狀態。

⑻ Linux如何清空Socket緩沖區

socket不是這么接收數據的 由於socket是以數據流的形式發送數據,接收方不知道對方一次性發送了多少數據,也能保證對方一次性發送的數據能在同一刻接收到,所以Receive方法是這么工作的: 接受一個byye[]類型的參數作為緩沖區,在經過一定的時間後把接收到的數據填充到這個緩沖區裡面,並且返回實際接收到數據的長度,這個實際接收到的數據長度有可能為0(沒有接收到數據)、大於0小於緩沖區的長度(接收到數據,但是沒有我們預期的多)、等於緩沖區的長度(說明接收到的數據大於等於我們預期的長度)。 每次接收緩沖區都用同一個byte[] byteMessage,並且你沒有檢查接收到的數據長度,所以第一次你接收到的數據是123456,第二次你只接收到了8,但是緩沖區裡面還有23456,所以加起來就是823456了。 socket接收緩沖區的大小有講究,設置大了接收起來慢,因為它要等盡可能多的數據接收到了再返回;設置小了需要重復多次調用接收方法才能把數據接收完,socket有個屬性,標識了系統默認的接收緩沖區大小,可以參考這個! 還有就是用recv讀取,但是由於不知道緩存里有多少數據,如果是阻塞模式,到最後必然等到超時才知道數據已經讀取完畢,這是個問題。 另一個是用fgetc,通過返回判斷是否是feof: whlie (1) { a=fgetc(f);if (feof(f)) break;//… b=fgetc(f);if (feof(f)) break;//…}當然,我不知道讀取完畢後最後一次調用fgetc會不會堵塞,需要測試。 在非阻塞模式下,我們用recv就可以輕松搞定了,但是阻塞模式下,由於我們不知道緩沖區有多少數據,不能直接調用recv嘗試清除。 使用一個小小的技巧,利用select函數,我們可以輕松搞定這個問題: select函數用於監視一個文件描述符集合,如果集合中的描述符沒有變化,則一直阻塞在這里,直到超時時間到達;在超時時間內,一旦某個描述符觸發了你所關心的事件,select立即返回,通過檢索文件描述符集合處理相應事件;select函數出錯則返回小於零的值,如果有事件觸發,則返回觸發事件的描述符個數;如果超時,返回0,即沒有數據可讀。 重點在於:我們可以用select的超時特性,將超時時間設置為0,通過檢測select的返回值,就可以判斷緩沖是否被清空。通過這個技巧,使一個阻塞的socket成了『非阻塞』socket. 現在就可以得出解決方案了:使用select函數來監視要清空的socket描述符,並把超時時間設置為0,每次讀取一個位元組然後丟棄(或者按照業務需要進行處理,隨你便了),一旦select返回0,說明緩沖區沒數據了(「超時」了)。 struct timeval tmOut;tmOut.tv_sec = 0;tmOut.tv_usec = 0;fd_set fds;FD_ZEROS(&fds);FD_SET(skt, &fds); int nRet; char tmp[2]; memset(tmp, 0, sizeof(tmp)); while(1) { nRet= select(FD_SETSIZE, &fds, NULL, NULL, &tmOut);if(nRet== 0) break;recv(skt, tmp, 1,0);} 這種方式的好處是,不再需要用recv、recvfrom等阻塞函數直接去讀取,而是使用select,利用其超時特性檢測緩沖區是否為空來判斷是否有數據,有數據時才調用recv進行清除。 有人說同樣可以用recv和socket的超時設置去清空啊,這個沒錯,但是你需要直接對socket描述符設置超時時間,而為了清空數據而直接修改socket描述符的屬性,可能會影響到其他地方的使用,造成系統奇奇怪怪的問題,所以,不推薦使用。

⑼ linux socket阻塞recv怎麼返回

recv是socket編程中最常用的函數之一,在阻塞狀態的recv有時候會返回不同的值,而對於錯誤值也有相應的錯誤碼,分別對應不同的狀態,下面是我針對常見的幾種網路狀態的簡單總結。
首先阻塞接收的recv有時候會返回0,這僅在對端已經關閉TCP連接時才會發生。
而當拔掉設備網線的時候,recv並不會發生變化,仍然阻塞,如果在這個拔網線階段,socket被關掉了,後果可能就是recv永久的阻塞了。
所以一般對於阻塞的socket都會用setsockopt來設置recv超時。
當超時時間到達後,recv會返回錯誤,也就是-1,而此時的錯誤碼是EAGAIN或者EWOULDBLOCK,POSIX.1-2001上允許兩個任意一個出現都行,所以建議在判斷錯誤碼上兩個都寫上。
如果socket是被對方用linger為0的形式關掉,也就是直接發RST的方式關閉的時候,recv也會返回錯誤,錯誤碼是ENOENT
還有一種經常在代碼中常見的錯誤碼,那就是EINTER,意思是系統在接收的時候因為收到其他中斷信號而被迫返回,不算socket故障,應該繼續接收。但是這種情況非常難再現,我嘗試過一邊一直在不停的發信號,一邊用recv接收數據,也沒有出現過。這種異常錯誤我附近只有一個朋友在用write的時候見到過一次,但是總是會有概率出現的,所以作為完善的程序必須對此錯誤進行特殊處理。
一般設置超時的阻塞recv常用的方法都如下:
while(1)
{
cnt = (int)recv(m_socket, pBuf,RECVSIZE, 0);
if( cnt >0 )
{
//正常處理數據
}
else
{
if((cnt<0) &&(errno == EAGAIN||errno == EWOULDBLOCK||errno == EINTR)) //這幾種錯誤碼,認為連接是正常的,繼續接收
{
continue;//繼續接收數據
}
break;//跳出接收循環
}
}
阻塞與非阻塞recv返回值沒有區分,都是 <0 出錯 =0 連接關閉 >0 接收到數據大小。

Linux環境下,須如下定義:struct timeval timeout = {3,0};
//設置發送超時
setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(struct timeval));
//設置接收超時
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval));

⑽ linux下setsockopt設置socket超時

she would watch a show and buy some gifts.

熱點內容
c語言大學教程第六版 發布:2025-05-19 16:04:21 瀏覽:739
androidvr播放器 發布:2025-05-19 15:55:32 瀏覽:964
我的世界pc如何創建伺服器 發布:2025-05-19 15:51:24 瀏覽:733
搶腳本 發布:2025-05-19 15:47:14 瀏覽:406
ct4哪個配置性價比最高 發布:2025-05-19 15:38:02 瀏覽:953
如何設置強緩存的失效時間 發布:2025-05-19 15:21:28 瀏覽:695
winxp無法訪問 發布:2025-05-19 15:19:48 瀏覽:947
文件預編譯 發布:2025-05-19 15:14:04 瀏覽:643
怎麼在伺服器上掛公網 發布:2025-05-19 15:14:02 瀏覽:272
濟南平安e通如何找回密碼 發布:2025-05-19 14:56:58 瀏覽:176