2017-02-18 171 views
0

我有多線程應用程序,它定期輪詢幾百個設備。 每個線程服務於一個設備,其套接字和其他描述符封裝在單個對象上,因此沒有共享描述符。 closesocket(fSock)偶爾應用程序崩潰,當我嘗試設置描述符fSock爲0.服務器在closesocket後崩潰

我假設,如果closesocket(fSock)返回SOCKET_ERROR,我不應該設置fSock = 0。 還是有其他原因嗎?

我的代碼:

bool _EthDev::Connect() 
{ 
    int sockErr, ret, i, j; 
    int szOut = sizeof(sockaddr_in); 

    // create socket 
    if ((fSock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
    { 
     sockErr = GetLastError(); 
     Log("Invalid socket err %d", sockErr); 
     fSock = 0; 
     return false; 
    } 

    // set fast closing socket (by RST) 
    linger sLinger; 
    sLinger.l_onoff = 1; 
    sLinger.l_linger = 0; 
    if (sockErr = setsockopt(fSock, SOL_SOCKET, SO_LINGER, (const char FAR*)&sLinger, sizeof(linger))) 
    { 
     sockErr = WSAGetLastError(); 
     Log("Setsockopt err %d", sockErr); 
     closesocket(fSock); 
     fSock = 0;   // here crashes 
     return false; 
    } 

    // connect to device 
    fSockaddr.sin_port = htons((u_short)(baseport)); 
    if (connect(fSock, (struct sockaddr*)&fSockaddr, szOut)) 
    { 
     closesocket(fSock); 
     fSock = 0; 
     return false; 
    } 

    ... 

    return true; 
} 
+0

零不是一個套接字無效的值。如果你想表明fSock不再是一個有效的套接字,你應該將它設置爲INVALID_SOCKET而不是0,因爲INVALID_SOCKET根據定義是一個永遠不會被有效套接字使用的值。 –

回答

0

我多線程應用程序,... [它]偶爾崩潰

多線程應用程序,偶爾崩潰是一個種族的條件的典型症狀。我認爲,爲了防止出現崩潰,需要弄清楚代碼中的競爭條件,並解決該問題。

我假定,我不應該設置fSock = 0,如果關閉套接字(fSock)返回 SOCKET_ERROR。還是有其他原因嗎?

我懷疑問題實際上是與closesocket()或將fSock設置爲0.請記住,套接字實際上只是整數,並將整數設置爲0不會導致其崩潰擁有。什麼可能導致崩潰是寫入無效內存 - 並且fSock = 0確實寫入成員變量fSock位於(或位於)的內存位置。

因此,更可能的假設是_EthDev對象被線程B刪除,而線程A仍然在調用Connect()的中間。在connect()調用執行時,這很可能會發生,因爲阻塞connect()調用可能需要相當長的時間才能返回。因此,如果在connect()調用期間有另一個線程粗暴地刪除了_EthDev對象,則只要connect()返回,下一行代碼就會寫入到(現在刪除的)_EthDev對象所使用的位置將是「fSock = 0;」行,這可能會導致崩潰。

我建議您檢查一下刪除_EthDev對象的代碼,如果它不小心先使用這些對象關閉任何線程(並且還要等待線程退出!),然後再刪除_EthDev對象,你應該重寫它,以便它可靠地做到這一點。在另一個線程可能仍在使用的時候刪除一個對象會造成麻煩。

+0

謝謝傑里米!實際上,我創建對象並在應用程序啓動時啓動線程,並在退出之前停止線程並刪除對象。 但現在我認爲問題更多的是多線程而不是套接字。 – swampmanster