2017-09-27 136 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

相关问题