套接字数据损坏

时间:2014-08-10 15:34:28

标签: c sockets

我正在开发一个简单的套接字客户端,它向服务器发送一个简单的字母“p”,然后从服务器读取响应。除了一个令人困惑的问题外,它正在全力以赴。第一次读取套接字(它发生在循环中)时,数据会出现乱码和损坏,结果如“ÿýÿû”和“μÞv”。第一次回复后收到的所有数据都很好且有效。

我用来接收的代码是:

int n;
char buffer[256];
bzero(buffer,256);
strcpy(buffer, "p");
n = write(manSock,buffer,256);
if (n < 0)
{
 error("ERROR writing to management server");
}
bzero(buffer,256);
n = read(manSock,buffer,256);
if (n < 0)
{
 error("ERROR reading from management server");
}
return buffer;

manSock是套接字文件描述符。

关于为什么会发生这种情况的任何想法?

4 个答案:

答案 0 :(得分:1)

这似乎不是与套接字相关的问题,而是与内存管理有关的问题。

您似乎返回一个指向内存的指针,该指针仅对函数本地有效。

假设你的真实&#34;代码看起来像这样

char * foo(void)
{
  char buffer[256];

  /* read into buffer */

  return buffer;
}

void bar (void)
{
  char * p = foo();
  printf("%s\n", p);
}

然后p引用foo()返回后的无效内存,因为缓冲区已在foo()返回时被隐式释放。

解决此问题

  • 使用malloc(), calloc()strdup()

    buffer中分配foo()动态广告
    char * foo(void)
    {
      char * buffer = malloc(256);
      memset(buffer, 0, 256);
      /* read into buffer */
      return buffer;
    }
    

    char * foo(void)
    {
      char * buffer = calloc(256, sizeof(*buffer));
      /* read into buffer */
      return buffer;
    }
    

    char * foo(void)
    {
      char buffer[256] = {0};
      /* read into buffer */
      return strdup(buffer);
    }
    
  • 或传递给foo()bar()(或更高)中分配的缓冲区的引用。

    void foo(char * buffer)
    {
       /* read into where buffer points */
    }
    
    void bar(void)
    {
      char buffer[256] = {0};
      foo(buffer);
      /* print buffer */
    }
    

答案 1 :(得分:0)

您只需要发送缓冲区的长度(strlen)。最佳做法是在实际发送数据之前始终发送缓冲区的长度。

int len;
len = strlen(buffer);
n = write(manSock,&len , sizeof(int));
if (n < 0)
{
 error("ERROR writing to len management server");
}
n = write(manSock,buffer,strlen(buffer));
if (n < 0)
{
 error("ERROR writing to management server");
}
bzero(buffer,256);
n = read(manSock,&len,sizeof(int));
if (n < 0)
{
  error("ERROR reading len from management server");
}
n = read(manSock,buffer,len);
if (n < 0)
{
  error("ERROR reading from management server");
}

答案 2 :(得分:0)

现在你的代码(假设它是一个函数)很糟糕,即使你接受了有关writeread函数的其他答案和评论中给出的建议。

原因是您返回本地定义的数组(实际上是第一个元素的地址)buffer,并且这样做是未定义的行为。因此,如果您正在检索返回值,buffer不再有效,并且可以想象包含垃圾数据,即使您在函数中填充了有效数据。

C ++标记已被删除,但如果您确实使用的是C ++,则可以始终将结果复制到std::string并返回:

std::string someFunc()
{
    int n;
    char buffer[256];
    //.. your code goes here
    //...
    return std::string(buffer, len); // where len is the number of characters read
}

如果你正在使用C,那么让用户通过你的缓冲区并在函数中填写它。不要创建本地数组并返回它们 - 这就是底线。

答案 3 :(得分:0)

您完全错误地设计了API

  1. 您将返回本地缓冲区的地址,该地址缓冲区将不存在,并且可能会在通话后被覆盖。
  2. 你丢弃了recv()返回的长度,所以调用者无法知道缓冲区有多少是有效的,即使你以某种方式修复了(1)。
  3. 您需要调用者来提供缓冲区,并且需要返回长度。这使得您的方法签名看起来非常像recv()。换句话说,你可能根本不需要这种方法。调用者只能调用recv()。