套接字数据损坏

我正在研究一个简单的套接字客户端,它向服务器发送一个简单的字母“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是套接字文件描述符。

有关为何发生这种情况的任何想法?

您只需要发送缓冲区的长度(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"); } 

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

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

假设你的“真实”代码看起来像这样

 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()foo()分配buffer动态

     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 */ } 

你现在的代码(假设它是一个函数)很糟糕,即使你接受了其他答案中给出的建议和有关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,那么让用户传递缓冲区并在函数中填写它。 不要创建本地数组并返回它们 – 这就是底线。

您完全错误地设计了API

  1. 您将返回本地缓冲区的地址,该地址缓冲区将不存在,并且可能在调用后被覆盖。
  2. 你丢弃了recv()返回的长度,所以调用者无法知道缓冲区有多少是有效的,即使你以某种方式修复了(1)。

您需要调用者提供缓冲区,您需要返回长度。 这使得您的方法签名看起来非常像recv()。 换句话说,你根本不需要这种方法。 调用者只能调用recv()。