【问题标题】:C++ , Send() function sends extra bytesC++,Send() 函数发送额外字节
【发布时间】:2011-09-10 17:09:49
【问题描述】:

我在使用 Winsock2 包装类(客户端-服务器)时遇到了问题,经过无数小时的摸索,我决定最好征求您的意见。

更具体地说,问题是每次我使用我的 Send() 函数时,客户端和服务器(并非总是如此!)都会发送一两个额外的字节!

例如,我使用 SendBytes("Hello") 并且 Recv 函数返回 "Hello•",并在字符数组的末尾带有 '•' 或其他随机字符。

    //main.cpp (Client)
    #include "Socket.h"

    int main() 
    {
        NetworkService::Client cService = NetworkService::Client();
        int res = cService.Initialize("127.0.0.1","20248");
        if(res == 0){
            int local = cService.SendBytes("Hello!");
            printf("Bytes Sent: %ld\n", local);
            cService.Shutdown();

            char* temp = cService.Recv();
            printf("String Recieved: %s  - Size: %d",temp,strlen(temp));
            printf("\nSTRLEN: %d",strlen("X5"));
        }
        else{
            cService.Clean();
        }
        cService.Close();
        while(!kbhit());
        return 0;
    }

当然,服务器发送字符串“X5”,客户端打印strlens ...

//The result with "X5" as the dummy text:  
String Recieved: X5? - Size: 3 //Notice the extra '?' character  
STRLEN: 2

发送 // 接收函数

    int NetworkService::Client::SendBytes(char* lData){
            int local = send( ConnectSocket, lData, (int)strlen(lData), 0 );
            if (local == SOCKET_ERROR) {
                Close();
                return WSAGetLastError();
            }
            return local;
    }

    char* NetworkService::Client::Recv(){
        recv(ConnectSocket, recvbuf , recvbuflen, 0);
        return recvbuf;
    }

我们将不胜感激^_^。

【问题讨论】:

  • 您没有在字符串中发送终止 NUL 字节。
  • 非常感谢您这么快回答!事情就是这样,我在字符串的末尾添加了 '\0' ,但它没有做任何事情。我仍然得到随机插入。
  • @christian:你已经通过字符串文字有一个隐含的 \0 。但是,为了发送它,您需要调整 send() 调用中的 size 参数。将其从 strlen(lData) 更改为 strlen(lData)+1 以包括尾随 \0。如果您仍然不确定为什么需要这样做,请务必查看 strlen() 函数。
  • 这不是真的必要,我之前只是用它来比较长字符串的长度,因为我在处理超过 2 字节字符串的问题。我认为 (ldata)+1 会起作用,谢谢,我会试一试!

标签: c++ sockets networking winsock winsock2


【解决方案1】:

对不起,但是

 int local;
 (...)
 return (int*)local;

你想达到什么目的?您的代码中有许多严重的问题。

【讨论】:

  • 警告/错误吞噬者,因为 RecvBytes 是 int* 并且 Recv 返回 int。
  • 我不明白。您正在从没有意义的整数中创建指针。我的警告你的意思是段错误吗?好吧,更清晰的想法是抛出异常。
【解决方案2】:

这不是您通过网络发送数据的方式。错误太多。

如果您想通过网络发送以空字符结尾的字符串:

int local = send( ConnectSocket, lData, (int)strlen(lData), 0 );

正如大家所说,您实际上并没有发送空终止符。如果您在长度上加 1,您会发送它。此外,对于长字符串,send() 函数不能保证您一次发送整个字符串。您必须检查并重新发送丢失的部分。

recv(ConnectSocket, recvbuf , recvbuflen, 0);

你不检查返回值,所以你无法知道接收到的字符串的长度。由于您不发送空字节,因此接收到的数据不是空终止的。此外,如果空终止符是您发送的更多数据的唯一分隔符,则您必须逐字节读取(效率不高),以免错过空终止符才能知道何时完成。另一种方法是制定自己的缓冲方案(因此下一次读取将部分返回前一次的结果),或更改协议以预先知道传输数据的长度。此外,这里也适用与 send 函数有关的部分读取的相同评论。

顺便说一句,返回静态/全局缓冲区并不是好代码的标志。

【讨论】:

  • 好吧,嗯,首先,我应该返回什么? Recv 将传入的数据复制到缓冲区中,因此完成后,我返回缓冲区。看,我知道发送数据 1 次容易出错,我必须发送两次并在客户端比较结果。我也试过了,但它不能保证我想要的结果,即按原样来来去去的数据包。顺便说一句,这是微软的代码,我只是将所有内容都包装在一个类中:)。
  • 实际上将长度增加 1 并通过 NUL 终止符发送就可以了!感谢 Steve-o 首先注意到!以及其他所有人的提示!
  • @Christian 您已将代码从“发生不工作”更改为“发生工作”。它仍然被大量破坏,因为它忽略了来自 recv 的返回值,并将其视为 C 风格的字符串数据,不能保证是 C 风格的字符串。
  • @jpaleck 感谢您的回答。尽管它没有被标记,但它确实帮助了我:)
【解决方案3】:

你没有真的检查recv的返回值。

有一个do-while,但它什么也没做。即使recv 失败,你也没有正确处理错误就从函数返回,但你永远不会知道。

你也不要发送终止\0,这不一定是坏事,取决于你想要做什么,例如你可以在接收后添加。

【讨论】:

  • 我尝试添加 \0 但它没有做任何事情。我仍然在字符串末尾插入随机字符。所以,问题仍然是,是什么导致了插入?感谢 recv 说明,我一直认为每次 recv 向缓冲区添加另一个字节时,它的返回值都会增加 1。
  • 好吧,我想它已经修复了。我会给你学分^^。
  • 不,它不是固定的。你怎么知道发生了错误?还有,和=比较,认真吗?
  • 我将 recvbuflen 移至 public:我将 RecvBytes 返回的值与 main.cpp 中的值进行比较。当然,我要发送的数据大约是 3 个字节,因此不会与 Windows Socket 错误代码混淆,因为最低的是 6。我想我忘记编辑页面了,哦。
猜你喜欢
  • 2020-08-23
  • 2012-12-20
  • 1970-01-01
  • 1970-01-01
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多