我用socket类的send函数通过局域网向另一台机器发数据,连接已经建立,网络没有问题,但是send函数返回的发送长度是-1,说明我的数据根本就没有发送成功,不是对方没有接收到我的数据。我是循环发数据,头几批能够发成功,但是后来的就全部都发送不出去,程序运行时没有触发windows的onclose事件,说明对方机器没有把我的socket断开。但是是需连接的可能性很小。

解决方案 »

  1.   

    在返回-1得时候调用
    void GetError()
    {
    LPTSTR lpMsgBuf;
    unsigned long i;
    FormatMessage( 
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    i = GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL 
    );
    MessageBox(NULL,lpMsgBuf,"ERROR",MB_OK);
    LocalFree( lpMsgBuf );
    }看看
      

  2.   

    个人认为是你的代码有问题,没有充分理解TCP协议!(“我是循环发数据,头几批能够发成功,但是后来的就全部都发送不出去”)send只是把数据copy到发送缓冲区,而发送是由tcp协议来完成。如果缓冲区是満的,你将不能调用send向缓冲区copy数据,调用将返回错误。你只有在收到来自系统提示(FD_WRITE),缓冲区有空隙,再次send方能成功。<个人观点!>
      

  3.   

    我把onreceive去掉又加上,加上后就能发送出去,而且,后来发现,只要我把里面的对收到数据取出的函数Receive()去掉后,就不能发送了,我想知道为什么,现在怀疑是收发数据缓冲区的问题,难道接收函数Receive有对接收缓冲区清空的操作?而且,我把Receive()去掉后,连对方把我的socket断开我的机器都不会触发windows的onclose事件了。
      

  4.   

    如果接收方缓冲区是満的,TCP协议将不能把发送方缓冲区中的数据移到吸收方缓冲区。此时如果发送方缓冲区已被你填満,那还调用send将失败。理解协议很重要。还有(“Receive有对接收缓冲区清空的操作?”)
    virtual int Receive( void* lpBuf, int nBufLen, int nFlags = 0 );nFlags :
    Specifies the way in which the call is made. The semantics of this function are determined by the socket options and the nFlags parameter. The latter is constructed by combining any of the following values with the C++ OR operator: MSG_PEEK:   Peek at the incoming data. The data is copied into the buffer but is not removed from the input queue.
    MSG_OOB:   Process out-of-band data . 
      

  5.   

    引用::
        个人认为是你的代码有问题,没有充分理解TCP协议!(“我是循环发数据,头几批能够发成功,但是后来的就全部都发送不出去”)send只是把数据copy到发送缓冲区,而发送是由tcp协议来完成。如果缓冲区是満的,你将不能调用send向缓冲区copy数据,调用将返回错误。你只有在收到来自系统提示(FD_WRITE),缓冲区有空隙,再次send方能成功。<个人观点!>
        说得对!
      

  6.   

    http://community.csdn.net/Expert/topic/3762/3762710.xml?temp=.964657
      

  7.   

    关于楼主的问题,首先表示歉意,没有帮上什么忙,首先贴两个函数,关于socket发送和接收函数的描述,涉及到发送和接收缓冲区,详细的将下面的URL
    http://community.csdn.net/Expert/topic/3687/3687759.xml?temp=.8385431
    五、send函数
      int send(
         SOCKET s,              
         const char FAR *buf,  
         int len,               
         int flags              
       );
       不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。这里只描述同步Socket的send函数的执行流程。当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲区的长度,如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len,如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完,如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)
    注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
    六、recv函数
       int recv(
         SOCKET s,       
         char FAR *buf,  
         int len,        
         int flags       
       );
       不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,只到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。
    注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
      

  8.   

    MSG_PEEK,MSG_OOB是有这两个参数选项,但是他的默认值是0,别忘了,而且我用的刚好是这个默认的0!
      

  9.   

    下面谈一下我对这个问题的理解,
    send 返回-1,捕捉到的错误码1054,表示服务器主动断开了socket连接,也就是说是服务器端调用了closesocket来断开你的socket,所以,你要想知道发生什么错误,你可以让服务器端帮你跟踪一下,在那里调用了closesocket了,为什么调用这个函数?因为服务器肯定是捕捉到错误了才关闭socket的,必然服务器端recv ()返回-1,try catch块捕捉到错误等都有可能关闭socket,这样你就知道你的客户端到底做了什么让服务器关闭了socket,错误就好查找了,写网络传输的东西,就需要服务器和客户端互相配合才能确定错误的
      

  10.   

    还有我想知道的是为什么我把Receive去掉后,程序触发不了OnClose事件,就是说我发送时对方给我断开了连接,但是我却不知道,在我把Receive去掉前,是不会这样的,但是我的Receive又不是用来的到tcp信息的,而是用缓冲区提取服务器的回应然后对取出的数据进行处理!
      

  11.   

    我想说的是为什么MSG_PEEK是可选项,当我们要(Peeks at the incoming data. The data is copied into the buffer but is not removed from the input queue)。当为0时应该为(removed from the input queue),如果为0时没有移去,那么你第二次接收时,是否能吸收到以前吸收的数据+新到的数据!不可能吧。(最好自己测一下那样会加深你对协议的理解)#define MSG_PEEK        0x2             /* peek at incoming message */
      

  12.   

    你收不到OnClose事件可能还是跟协议有关,我记得TCP里面好像有这样一句。TCP不会主动发数据来测试连接是否还存在,因为那样会占用带宽(在协议设计之初就这样定义的),当然原话不是这样,我记不起了。你保证你的关闭是正常关闭吗,还是直接拨网线,或其它非正常方式,还有,你是否指定了FD_CLOSE。原因很多!