[英]Extract IP from connection that listen and accept in socket programming in Linux in c
[英]errno after accept in Linux socket programming
如RETURN VALUE
部分中的accept()
手冊頁所述:
錯誤處理
Linuxaccept()
(和accept4()
)將新套接字上已經掛起的網絡錯誤作為來自accept()
的錯誤代碼傳遞。 此行為與其他BSD套接字實現不同。 為了可靠運行,應用程序應在accept()
之后檢測為協議定義的網絡錯誤,並通過重試將其視為EAGAIN
。 在TCP / IP的情況下,這些都是ENETDOWN
,EPROTO
,ENOPROTOOPT
,EHOSTDOWN
,ENONET
,EHOSTUNREACH
,EOPNOTSUPP
,以及ENETUNREACH
。
這是否意味着必須在accept()
返回之后和檢查accept()
的返回值之前檢查errno
的值? 如果是,如果errno
必須采取哪些步驟?
這是我處理accept()
代碼片段:
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if((errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN ||
errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH))
return;
if (newsockfd < 0)
{
// error
}
else if(newsockfd > 0)
{
// accepted a new connection
}
else
{
// blah blah blah
}
我得出結論,在這種情況下,人們可能會在一段時間內再試一次。 我的結論是否正確?
根據SUSv4 :
成功完成后,
accept()
將返回已接受套接字的非負文件描述符。 否則,返回-1
並errno
以指示錯誤。
這意味着如果accept()
返回-1
,您只需要檢查errno
。
您的代碼可能看起來更像這樣:
ret = accept(fd, &addr, sizeof (addr));
if (ret == -1) {
switch (errno) {
case EAGAIN:
case EWOULDBLOCK:
/* do something */
break;
case EBADF:
/* do something different */
break;
default:
/* do something even more different */
}
}
(您如何處理每個錯誤情況取決於您的應用程序。)
另外,在檢查accept()
的返回值后立即檢查errno
很重要。 如果你先調用任何其他函數(即使是一個簡單的fprintf()
),你也有可能用不同的錯誤覆蓋errno
。
首先,檢查accept()
返回值。 如果accept()
返回值小於0
,那么你應該檢查errno
。 如果是ENETDOWN
, EPROTO
, ENOPROTOOPT
, EHOSTDOWN
, ENONET
, EHOSTUNREACH
, EOPNOTSUPP
,或ENETUNREACH
,那么你可以調用accept()
一次。 否則發生了一些不好的事情,你應該停止調用accept()
(例如,你已經通過bad listen socket作為accept()
的參數)。
這就是我理解代碼的方式。
以下是如何進行錯誤處理:
while (running) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
// error
perror ("accept");
if((errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN ||
errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)) {
continue;
}
exit (EXIT_FAILURE);
}
// accepted a new connection
// blah blah blah
}
您也應該處理EHOSTUNREACH
,它顯示“軟件導致連接中止”。
我處理了accept()
返回值作為接受的答案,但是我的一台服務器由於EHOSTUNREACH
崩潰。 在google之后,我意識到在ECONNABORTED
錯誤之后同樣沒有更改套接字憑據。 我們不應該只為ECONNABORTED
崩潰程序。
其各種約束如下:
如果尚未建立連接,即,如果它是來自客戶端的第一個請求,並且如果客戶端甚至在服務器有機會響應之前關閉連接,則服務器上的accept()調用結果為ECONNABORTED
。 服務器應忽略此錯誤,然后繼續執行隊列中的下一個請求。 如果客戶端需要再次連接到服務器,則必須執行另一個connect()。
如果客戶端和服務器之間的連接處於ESTABLISHED狀態,並且客戶端突然關閉連接,則服務器上的accept()調用將導致ECONNABORTED
。 在這種情況下,服務器必須關閉半開的連接。 否則,只要服務器進程處於活動狀態,這些半開的套接字就可能保持CLOSE_WAIT狀態。 看看這個網頁: http : //technopark02.blogspot.com/200...closewait.html ,了解更多有關CLOSE_WAIT及其影響的信息,略有不同。
最后,完整的代碼如下:
while(running)
{
sfd = accept(socketFd, (struct sockaddr *) &cli_addr, &addr_len);
if( sfd < 0)
{
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENONET ||
errno == EPROTO || errno == ENOPROTOOPT || errno == EOPNOTSUPP ||
errno == ENETDOWN || errno == ENETUNREACH || errno == EHOSTDOWN ||
errno == EHOSTUNREACH || errno == ECONNABORTED)
{
log_warn("accept error: %s\n", strerror(errno));
break;
}
else if( errno == EINTR)
{
continue;
}
else
{
log_error("AccepCb: accept error: %s\n", strerror(errno));
assert(false);
}
}
// logical works...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.