Reputation: 13
I'm working on a simple socket client, that sends a simple letter "p" to the server, and then reads the response from the server. It is working fully, except for one confusing issue. The very first time the socket is read from (it happens in a loop), the data is garbled and corrupt, with results like "ÿýÿû" and "µÞv". All the data received after the first response is fine and valid.
The code I'm using to receive is:
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
is the socket file descriptor.
Any ideas on why this is happening?
Upvotes: 0
Views: 2151
Reputation: 310860
You've designed your API completely incorrectly
You need the caller to supply the buffer, and you need to return the length. This makes your method signature look remarkably like that of recv(). In Other words you possibly don't really need this method at all. The caller could just call recv().
Upvotes: 0
Reputation: 70893
This does not seem to be a problem related to sockets, but to memory management.
You seem to return a pointer to memory being valid only local to the function.
Assuming your "real" code looks like this
char * foo(void)
{
char buffer[256];
/* read into buffer */
return buffer;
}
void bar (void)
{
char * p = foo();
printf("%s\n", p);
}
then p
refers to invalid memory after foo()
returned, as buffer had been implicitly deallocated upon foo()
's return.
To fix this
either allocate buffer
dynamical in foo()
using malloc()
, calloc()
or strdup()
char * foo(void)
{
char * buffer = malloc(256);
memset(buffer, 0, 256);
/* read into buffer */
return buffer;
}
or
char * foo(void)
{
char * buffer = calloc(256, sizeof(*buffer));
/* read into buffer */
return buffer;
}
or
char * foo(void)
{
char buffer[256] = {0};
/* read into buffer */
return strdup(buffer);
}
or pass down to foo()
a reference to a buffer being allocated in bar()
(or higher).
void foo(char * buffer)
{
/* read into where buffer points */
}
void bar(void)
{
char buffer[256] = {0};
foo(buffer);
/* print buffer */
}
Upvotes: 1
Reputation: 1377
You need to send only upto the length(strlen) of the buffer. Its best practice to always send the length of the buffer before actually sending the data.
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");
}
Upvotes: 0
Reputation: 35440
Your code as it stands now (assuming it is a function) is bad, even if you took the advice given in the other answers and comments concerning the write
and read
functions.
The reason is that you're returning a locally defined array (actually the address of the first element), buffer
, and doing so is undefined behavior. So if you're retrieving the return value, buffer
is no longer valid and could conceivably contain garbage data, even if you filled it with valid data within the function.
The C++ tag was removed, but if you really are using C++, you could always copy the results to a std::string
and return that instead:
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
}
If you're using C, then have the user pass you the buffer and you fill it in within the function. Don't create local arrays and return them -- that's the bottom line.
Upvotes: 0