2010-07-23 56 views
1

我正在使用Winsock2的小型网络项目。我正在使用TCP连接,实际上正在使用IRC作为例子,因为IRC非常简单。我正在做的是连接到服务器并发送初始缓冲区,以便服务器识别连接。这工作正常。Multipe Send()和Recv()使用Winsock2

我担心的是我无法再次写入套接字。在我发送初始缓冲区之后,如果我不使用shutdown()(在SD_SEND上),我的程序似乎会挂起。

因此,我想发送的下一个数据(基于RFC 1459)是USER和NICK信息,但是,我觉得使用shutdown()是导致我当前的问题的原因。有没有办法重新初始化写入套接字?

谢谢!

添加的代码

注意,这些都位于一个类中,因此仍可能会稍微模糊。我正在使用我拥有的元素将其写入更简单的示例中。一切都是正确定义的,所以如果我忘记定义事情,我很抱歉,但我的许多重复变量都是为类的范围定义的。

int main(int argc,char *argv[]) 
{ 
     int iResult; 
     SOCKET Connection; 
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
    if(iResult != 0) 
     throw "Startup failed!"; 

    // Prep stuff 
    ZeroMemory(&hints,sizeof(hints)); // This struct is defined addrinfo 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 

    // Now resolve server addr 
    iResult = getaddrinfo(argv[1],argv[2],&hints,&result); 
    if(iResult != 0) 
     throw "getaddrinfo() failed!"; 

    // Now try to connect 
    for(ptr=result;ptr != NULL;ptr = ptr->ai_next) 
    { 
     Connection = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); // defined in that "hints" struct. argument number 2 
     if(Connection == INVALID_SOCKET) 
     { 
      freeaddrinfo(result); 
      WSACleanup(); 
      throw "Error at socket();"; 
     } 

     // Connect to server 
     iResult = connect(Connection, ptr->ai_addr, (int)ptr->ai_addrlen); 
     if(iResult != 0) 
     { 
      closesocket(Connection); 
      Connection = INVALID_SOCKET; 
      continue; 
     } 
     break; 
    } 

    freeaddrinfo(result); 

    // Send initial buffer so server know you're there :) 
    iResult = send(Connection, "", 1, 0); 
    if(iResult == SOCKET_ERROR) 
    { 
     close(); 
     throw "Could not send initial buffer!"; 
    } 

    // Close this connection for the inital buffer 
    iResult = shutdown(Connection, SD_SEND); 
    if(iResult == SOCKET_ERROR) 
    { 
     close(); 
     throw "Could not close initial buffer socket!"; 
    } 

     bool connected = true; 

     // This is taken from my read function within the class 
     // BEGIN READ FUNCTION 
    iResult = 0; // Reset 
    std::string data = ""; // Capture the output and send it all at once! 

    // This only works if we're connected sweet cakes <3 
    if(connected) 
    { 
     do 
     { 
      iResult = recv(socket, recvbuf, BUFLEN, 0); 
      if(iResult > 0) 
      { 
       // Working properly 
       // Save all data even if there is more than BUFLEN sent 
       continue; 
      } 
      else if(iResult == 0) 
       // Connection closed properly 
       break; 
      else 
       printf("ERROR!"); 
     } while(iResult > 0); 
    } 
    data += recvbuf; 
    ZeroMemory(&recvbuf,sizeof(recvbuf)); 
     // Function returns std::string but essentially this is what happens 
     printf("%s",data.c_str()); 
     // END READ FUNCTION 

     // BEGIN WRITE FUNCTION 
    iResult = 0; // Reset 
     SOCKET socket = Connection; // Write function arg 1 
     char *data; // Write function arg 2 

    iResult = send(socket,data,(int)strlen(data),0); 
    if(iResult == SOCKET_ERROR) 
    { 
     close(); 
     printf("Could not write data: %ld",WSAGetLastError()); 
       return 1; 
    } 

    // Data sent, let's close the write socket 
    iResult = shutdown(socket, SD_SEND); 
    if(iResult != 0) 
    { 
     close(); 
     printf("Could not close write socket!"); 
       return 1; 
    } 

    //return iResult; 
     // END WRITE FUNCTION 

     // Now that will produce "Could not write data: 0" for any value of data 
     // So realistically I want to send the USER and NICK data, then read 
     // and probably process a PING string from the server and send my PONG response 

     return 0; 
} 

我希望澄清事情!

编辑

我想我已经想通了什么错误。我将下面列出的更正作为我的代码;多谢你们。但是,这是我的阅读循环,这是与事情搞乱。即使它拥有所有的信息,似乎它在发送输出之前正在等待连接关闭。有任何想法吗?我的输出目前看起来是这样的(字节写入/总是我加入,以确保一切快要落山正确的线)

Bytes Written: 41 
Bytes Total: 41 
Data: ERROR :Closing Link: raged123[127.0.0.1] 6667 (Ping timeout) 
... 
:irc.foonet.com NOTICE AUTH :*** Found your hostname (cached) 
PING :2ED39CE5 
[A bunch of funny characters]WinSock 2.0 

所以它似乎已超时,因为PING没有及时收到PONG但是,如果没有首先处理PING请求,我不能发送PONG,这意味着在连接关闭之前,我需要能够读取输出。有任何想法吗?

+0

请展示一个简短的示例,演示您遇到的问题。否则,我们没有完整的图片。 – 2010-07-23 21:36:40

+0

更新,谢谢! – RageD 2010-07-23 22:08:02

回答

2

不应该有任何需要像你所做的那样发送“初始缓冲区”。服务器将在客户端连接时收到通知,它不依赖于实际发送任何内容的客户端。 (特别是,IRC协议说服务器将在您连接后立即开始发送给您的东西。)

shutdown()的呼叫是高度可疑的。你为什么期望需要这样做?关闭套接字是您在完成连接时执行的操作,而不是刚开始时的操作。你应该完全删除它。

我不确定recvbuf是什么类型,但它看起来像你使用不正确。某些可以追加到std::string的东西可能也不能有ZeroMemory()的调用,而没有其中一个错误。您也没有使用iResult这是从服务器收到的实际字节数。

您的写入功能还包含一个对shutdown()的调用,您应该删除它。

+0

啊你是对的。我将char recvbuf [LENGTH]中的recvbuf更改为char recvbuf,对不起。我删除了“shutdown()”,但我得到了相同的输出。现在程序不是无限期地挂起,但是,输出读取消息10053(软件导致连接中止)需要大约20秒。服务器已启动;我正在使用一个std IRC客户端。 (写入<(int)strlen(data))时,我还添加了一个循环,其中写入init为0,并且每个循环都写入=写入+ iResult;有任何想法吗? – RageD 2010-07-23 22:44:51

1

根据男人送(2)

成功时,这些调用返回 号码发送的字符。出错时,返回 -1,并适当设置errno。

发生什么情况可能是发送不会立即发送完整的缓冲区,您必须在其周围使用循环。

这可能不是然而是实际的问题,因为你,再发送一个空字符串...

我会强烈建议使用Wireshark,所以你可以查阅一下下降到线

0
data += recvbuf; 

这不能工作。有没有办法知道有多少字节已收到。这个函数需要一个C风格的字符串,而不是任意的字节块。

但是你也有一个非常基本的设计问题。您期望您的程序能够说出IRC协议,但它不包含任何协议的实现。例如,IRC协议指定了消息被分隔的特定方式,并且您没有任何代码来解析这些消息。

因此,从阅读到写作的过渡基本上是随机的,由TCP时序的变幻莫测以及服务器如何选择分段输出来确定。由于允许服务器对输出进行分段,但是它令人满意(协议很明显,客户端不能依赖分段来解析协议,而是必须依赖面向行的特性),所以程序的行为是不可预测的。

相关问题