2017-09-27 135 views
-1

我做了正常(?)步驟的tcp套接字連接,如下面的代碼所示。但發送有時導致錯誤,而服務器端打印一些日誌,說連接,我不知道我的代碼有什麼問題。任何幫助表示讚賞。 有關穩定和可靠的Windows套接字編程的任何信息,讚賞。爲什麼我的winsocks2有時會發送10057錯誤的結果?

MSDN描述約10057錯誤:

Socket is not connected.A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using sendto) no address was supplied. Any other type of operation might also return this error—for example, setsockopt setting SO_KEEPALIVE if the connection has been reset.


PS:在下面的代碼段的真實IP地址是由127.0.0.1取代。代碼不可運行。

int connect_to_server() { 
SOCKET soc; 
SOCKADDR_IN serveraddr; 
SOCKADDR_IN clientaddr; 
unsigned char buf[1024]; 

WSADATA wsa; 
WSAStartup(MAKEWORD(2, 2), &wsa); 

/* create a tcp socket; */ 
if ((soc = socket(AF_INET, SOCK_STREAM, 0/*IPPROTO_TCP*/)) <= 0) 
{ 
    LOGFMTF("errcode[-1], create socket fail!"); 
    return -1; 
} 

serveraddr.sin_family = AF_INET; 

serveraddr.sin_port = htons(9102); 
serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 

unsigned long mode = 1; // 1 to enable non-blocking socket 
if (ioctlsocket(soc, FIONBIO, &mode) == SOCKET_ERROR) { 
    LOGFMTF("errcode[-2], ioctlsocket fail."); 
    return -2; 
} 

if (::connect(soc, (SOCKADDR *)&serveraddr, sizeof(serveraddr)) != 0) 
{ 
    /* FIONBIO socket enters here can go run; non-FIONBIO socket enters here stands for real error;*/ 
    if (WSAGetLastError() != WSAEWOULDBLOCK) { 
     LOGFMTF("errcode[-3], connect fail."); 
     //return -3; 
    } 

    //return -1; 
} 

g_client_fd = soc; 

LOGFMTT("client_fd[%d]", g_client_fd); 
LOGFMTT("connect to server last err[%d].", WSAGetLastError()); 

return 0; 
} 

/** send loop; */ 
DWORD WINAPI send_thread_loop(LPVOID pM) { 
LOGFMTT("send thread[%d] start.", GetCurrentThreadId()); 

for (;!g_to_exit;) 
{ 
    QMutexLocker locker(&g_send_queue_lock); 
    if (g_send_queue.count() == 0) { 
     Sleep(Send_Thread_Gap); 
    }else { 
     LOGFMTT("send one packet."); 
     int pakcet_size = g_send_queue.begin()->size; 
     char *addr = g_send_queue.begin()->data; 
     ::send(g_client_fd, addr, pakcet_size, 0); 

     /* ------------!Attention begin------------ */ 
     LOGFMTT("send last err[%d].", GetLastError());--------> sometimes got 10057 error. 
     /* ------------!Attention end------------ */ 

     delete[]addr; 
     g_send_queue.erase(g_send_queue.begin()); 
    } 
} 

LOGFMTT("send thread[%d] exit.", GetCurrentThreadId()); 

return 0; 
} 

int start_net_thread() { 
g_recv_thread = CreateThread(NULL, 0, recv_thread_loop, NULL, 0, NULL); 

g_send_thread = CreateThread(NULL, 0, send_thread_loop, NULL, 0, NULL); 

return 0; 
} 

int main(){ 
if(connect_to_server() != 0) 
{ 
    QMessageBox msgBox; 
    msgBox.setText("failed."); 
    msgBox.exec(); 
    return -1; 
} 

start_net_thread(); 

return 0; 
} 
+1

片狀連接,連接丟失,忽略錯誤代碼。 – CodeCaster

+0

@CodeCaster也許我有很多功課要做。如果我忽略此錯誤並嘗試稍後再發送,那麼可以嗎?我已經改變了我的代碼以改進它,並且會測試更多以查看它是否適用於我的明天工作。 – waterd

+0

@CodeCaster我想我錯過了一些關於我的錯誤的重要背景。連接到服務器,發送線程開始和我的fisrt嘗試發送登錄數據包到服務器是逐行的。到現在爲止,如果第一次發送失敗,不會再發送數據包。所以我在第一個回覆中有這個問題。更多的工作需要等到明天。謝謝您的回覆。 – waterd

回答

-1

希望我的淺淺的答案將有助於某人。

原來我的ioctlsocket客戶端套接字爲非阻塞模式之前connect。當connect返回時,連接可能無法完成,但我立即啓動發送線程。有機會發送線程send數據到未連接的soeckt

MSDN一樣,使用非阻塞套接字,連接嘗試不能立即完成。

PS:send可以發送小於預期字節經由send第三個參數指定字節。

int remain_size = pakcet_size; 
int this_read_cnt = 0; 
for (;;) { 
    if ((this_read_cnt = ::send(g_client_fd, addr+ pakcet_size - remain_size, remain_size, 0)) != SOCKET_ERROR) { 
     remain_size = pakcet_size - this_read_cnt; 
    } 
    else { 
     LOGFMTT("send last err[%d].", GetLastError()); 
    } 

    if (remain_size == 0) { 
     delete[]addr; 
     g_send_queue.erase(g_send_queue.begin()); 
     break; 
    } 
} 
+1

這不是'改進'。你讓糟糕的代碼變得更糟。 – EJP

2

Why did my winsocks2 send result in 10057 error sometimes?

它沒有。至少,沒有證據表明它確實如此。

::send(g_client_fd, addr, pakcet_size, 0); 
/* ------------!Attention begin------------ */ 
LOGFMTT("send last err[%d].", GetLastError());--------> sometimes got 10057 error. 

它是無效的調用WSAGetLastError()除非一個錯誤,在這種情況下會被通過信號返回send() -1。但是,由於你沒有檢查這個,除了你在send()附近的編碼差,沒有證據表明這個問題有待解決。它應顯示爲:

if (::send(g_client_fd, addr, pakcet_size, 0) == -1) 
{ 
    /* ------------!Attention begin------------ */ 
    LOGFMTT("send last err[%d].", GetLastError());--------> sometimes got 10057 error. 
} 

注意該單詞拼寫爲「數據包」,而不是「pakcet」。

+0

謝謝你解釋清楚,我詳細解答了我的答案。這是我的第一版。當我遇到此問題時,我已將'send'部分更改爲'loop',就像我的答案一樣。希望你能讓我更清楚** 10057錯誤**何時會出現,以及我的代碼應該做什麼。 – waterd

+0

這是正確的。 'send'返回一個必須被檢查的值,沒有例外。 – Matt

+0

無論我的代碼有多糟糕,發送都會導致** 10057錯誤**,並且在我的情況下,**我不應在10057錯誤**之後停止發送。 – waterd

相關問題