I have a client/server that exchanges messages, and i am trying to add the size of the string i am sending, in the beginning of the string, in order for the server to know how many bytes to read.
I added the message starting from the +4 pos of the char* and used memcpy to copy the strlen of the string. It doesnt seem to work and something tells me its the wrong way to do it. This is my code.
//*CLIENT*//
send_message = malloc(1024 * sizeof(char));
strcpy(send_message + 4,"GETFILES ");
strcat(send_message,"/");
strcat(send_message,directory_name);
size = strlen(send_message) + 1;
csize = malloc(4 * sizeof(char));
csize = (char*)&size;
memcpy(&send_message,csize,4);
if((sent = send(sock, send_message, strlen(send_message) + 1, 0)) < 0)
perror("write");
//*SERVER*//
while(1){
count = recv(events[i].data.fd, buf, sizeof(buf),0);
if(count == -1){
//if errno = EAGAIN we have read all data. going back to main loop
if(errno != EAGAIN){
perror("read");
done = 1;
}
break;
}
else if(count == 0){
//End of file. The remote has closed the connections
done = 1;
break;
}
printf("received message %s and count %d\n", buf, count);
}
if i comment these lines
csize = malloc(4 * sizeof(char));
csize = (char*)&size;
memcpy(send_message,csize,4);
I get this output:
received message ▒�w�GETFILES /test and count 19
otherwise i get no output..Any ideas how to fix it and add the header so my server knows in advance how many bytes to read?
As commented already, the main problem is the use of strlen(), but there is some more error.
First the strlen() and other str functions could be used in this way.
strcpy(send_message + 4,"GETFILES ");
strcat(send_message + 4,"/");
strcat(send_message + 4,directory_name);
size = strlen(send_message + 4) + 1;
It is not a good way to fix it, but it is easier to understand why your code is not working.
This is unnecessary
csize = malloc(4 * sizeof(char));
csize = (char*)&size;
memcpy(&send_message,csize,4);
You could simply do this
memcpy(send_message,&size,4);
BUT, for good practice and portability, replace all your magic 4 for sizeof(int32_t).
send_message is an array, so you do not need to get it address (&send_message), it may work this way, but if it was a pointer instead of an array it would break your code.
And last, you are printing the entire buff, but you forgot that you have a 4 bytes header, and that is the main reason it do not print anything if you properly initialize the csize.
If you try to do this
printf("received message %s and count %d\n", buf+4, count);
It will probably works, but it do not mean it is correct.
Edit: I will not update my answer to not make it bigger and harder to you see your mistake, but consider #thuovila comments below and look for more informations about htonl ntohl and how to use them.
Related
I am doing socket programming for achieve communication between different entities in my application. When sending a message, I prefix the message with the length of the message and I terminate it with \0. I have recv() in a loop as follows:
void receive(int socket)
{
int num_of_bytes_read = 0, msg_len;
char *msg = NULL, *msg_p = NULL;
char recv_buf[MAX_LEN];
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
{
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
msg_len = ntohl(msg_len);
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
systemError("Could not receive new message\n");
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
msg_p = msg;
}
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
systemError("memcpy failed in receive()\n");
msg_p += num_of_bytes_read;
}
printf("%p\n", msg); /* prints (nil) !!!!!*/
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
/* pass the a pointer to the beginning of the message skipping msg_len*/
int res = processMessage(msg + sizeof(uint32_t));
}
When I run the program I obviously get segmentation fault with the following error:
message=0x4
What is wrong with msg?? Can someone please help.
while(num_of_bytes_read = recv(socket, recv_buf, MAX_LEN, 0))
This is already wrong. You should test for > 0. If num_of_bytes is zero you should close the socket, and if it is -1 you should log the associated errno, e.g. with perror(), and close the socket, and in both cases stop reading.
if(msg == NULL)
{
memcpy(&msg_len, message, 4);
As long as message points to four bytes of addressable memory this will succeed. You have provided no information on the point. The purpose remains obscure.
msg_len = ntohl(msg_len);
Here you are assuming that message pointed to four bytes that magically contain an int that has magically been set to a value you are prepared to regard as a message length. Why, I don't know. Again you have provided no information on the point.
if((msg = (char *)(sizeof(char) * msg_len)) == NULL)
This is complete nonsense. Is there a malloc() missing in there somewhere?
systemError("Could not receive new message\n");
A meaningless error message. The problem appears to be about allocating memory, but it's anybody's guess. It certainly has nothing to do with receiving messages.
printf("%p\n", msg); /* prints 0xe!! Why is the address not 4B long??*/
Here you appear to think the address should be 4B long. I don't know why.
if(memcpy(&msg_p, recv_buf, num_of_bytes_read) == NULL)
You are copying data to the address of msg_p. This doesn't make sense. Also, at this point num_of_bytes_read could be -1 due to your incorrect loop condition above, so anything could happen, including trying to copy 0xffffffff bytes.
systemError("memcpy failed in receive()\n");
The only way you can get to this line is if msg_p's address was null, which is impossible. Remove the & from &msg_p in the memcpy() call. Now you can only get to this systemError() call if msg_p was zero, which would already have caused a SEGV, so you still can't get to this line. A bit of preventative coding is indicated here.
msg_p += num_of_bytes_read;
Again num_of_bytes_read could be -1 at this point, sending your pointer backwards instead of forwards.
printf("%p\n", msg); /* prints (nil) !!!!!*/
Nil indicates that msg was zero.
printf("%p\n", msg + sizeof(uint32_t)); /* prints 0x4 */
0x4 again indicates that msg was zero.
You need to improve your code in the areas indicated.
msg = (char *)(sizeof(char) * msg_len)
You are setting msg to some address based on the msg_len. Not actually anything to do with where the msg resides in memory...
I'm still refining my C coding skills and keep running into issues with properly managing memory--go figure. Anyhow, I'm reading from a socket and I'm fine as long as my total response length from the socket it no bigger than my buffer size. I know this because when I increase the buffer size large enough for the incoming data, it works just fine for the larger payloads. Creating a really large "just-in-case" buffer on the stack isn't feasible, obviously, so I want to grow the buffer dynamically on the heap. Here's what I'm doing currently:
raw_response = NULL;
// Receive from the Web server
retcode = recv(server_s, in_buf, BUF_SIZE, 0);
while ((retcode > 0) || (retcode == -1))
{
totalLength += retcode;
if (raw_response == NULL) {
raw_response = (char*)malloc(sizeof(char)*totalLength);
memcpy(raw_response, in_buf, totalLength);
} else {
raw_response = (char*)realloc(raw_response, sizeof(char)*totalLength);
memcpy(raw_response+previousLength, in_buf, retcode);
}
previousLength = retcode;
retcode = recv(server_s, in_buf, BUF_SIZE, 0);
if (retcode == 0 || retcode == -1) {
printf("\n\nNo more data, bailing. Data length was: %lu\n\n", totalLength);
}
}
If the raw_response is NULL, I know I have not received any data yet, so I use malloc. Otherwise, I use realloc so that I don't have to build up a new buffer. Instead I can just append the incoming data. So to get the end of the existing data after the first iteration, I take the address of raw_response and add the previous length to that and append the new data there assuming it's correctly appending on each subsequent call to recv().
The problem is that my final buffer is always corrupted unless I change BUF_SIZE to something larger than my total incoming data size.
Seem like it's probably just something simple I'm overlooking. Any thoughts?
The problem is these lines:
memcpy(raw_response+previousLength, in_buf, retcode);
previousLength = retcode;
Your function will work for the first and second iterations but after that will start corrupting data. I assume you meant to write previousLength += retcode;
There are some other problems with the code which aren't the answer to your question. Firstly, what happens if realloc or malloc fails? You don't check for this in your little sample. Also, you can always just use realloc (which will act like malloc if the pointer is NULL see this SO question). i.e.
char *tmp = realloc(raw_response, sizeof(*tmp) * totalLength);
if (tmp == NULL)
return -ENOMEM;
raw_response = tmp;
memcpy(raw_response + previousLength, in_buf, ret_code)
Secondly, you might call memcpy when ret_code is -1 (also changing totalLength by -1 which will again cause problems).
In C I had working code but have no idea why it worked, so I started rewriting it so I could actually understand what is going on.
So far so good! I rewrote and am 90% sure I understand everything that is going on now; the issue however, is that I have no idea how to store the data chunk received by recv (databff) into my pre-allocated buffer (htmlbff).
Consider the following code (note that I stripped this down quite a bit, so it only includes the basics, e.g. no memory reallocation or leak protection, etc...):
#define BUFFERSIZE 4096
#define MAXDATASIZE 256
char *htmlbff, databff[MAXDATASIZE];
int c, i = BUFFERSIZE, q = 0;
if(!(htmlbff = malloc(i)))
{
printf("\nError! Memory allocation failed!");
return 0x00;
}
while((c = recv(sock, databff, MAXDATASIZE, 0)) > 0)
{
/*memory checks stripped out since they are irrelevent for this post*/
/*store data to the appropriate area in htmlbff*/
q += c;
}
So (if I am doing this right, and things are going as I think they are) c is the size of the current data chunk, and q is the total amount of data received so far (q is incremented by c each time the loop repeats). At the moment I am using q for memory handling (in case anybody was wondering) but I believe that it will also have purpose in the solution to this problem.
At any rate the question I am asking is in regards to the second comment. How do I store the data from recv into htmlbff correctly?
Use memcpy() to copy (append) data to the htmlbff but you also need to ensure you do not exceed the size of htmlbff. Either stop receving data when BUFFERSIZE bytes have been received or use realloc() to extend htmlbff to contain more data.
For example:
char* htmlbff;
size_t htmlbff_size = BUFFERSIZE;
htmlbff = malloc(htmlbff_size);
if (htmlbff)
{
while((c = recv(sock, databff, MAXDATASIZE, 0)) > 0)
{
if (c + q > htmlbff_size)
{
htmlbff_size *= 2; /* Arbitrary doubling of size. */
char* tmp = realloc(htmlbff, htmlbff_size);
if (tmp)
{
htmlbff = tmp;
}
else
{
/* memory allocation failure. */
free(htmlbff);
htmlbff = 0;
break;
}
}
memcpy(htmlbff + q, databff, c);
q += c;
}
}
Use memcpy, and offset htmlbff by q:
memcpy(htmlbff + q, databff, c);
You can similarly recv directly into htmlbff:
c = recv(sock, htmlbff + q, MAXDATASIZE, 0));
But it's fine to keep a separate buffer, and depending upon your full code, it may make things clearer.
Be sure that you add checks against BUFFERSIZE so that you don't copy past the bounds of htmlbff. You mentioned that you've stripped out realloc handling, so maybe you're already handling this.
Your constant names are a bit confusing, when buffering data I would use BUFFERSIZE to indicate the size of each chunk, i.e. the size of databff.
What I would do is recv() data directly into htmlbff, unless you need to do more processing on it.
Make sure that you realloc() htmlbff when i - q is less than MAXDATASIZE so that there is always room for another recv().
Then you would call recv(sock, htmlbff + q, MAXDATASIZE, 0)
You need to keep reallocating/expanding the buffer to fit all the data (if the data read off the socket exceeds MAXDATASIZE) = That way as recv reads data into the databff, your htmlbff can grow in memory and then the new read can be appended to your overall htmlbff.
q and c are like cursors to keep track of where you are up to and how far you have to go.
memcpy(htmlbff+q, databff, c); //Do this in your whle loop to append the data
Hi i have written a server application which accepts a name from the client which usually is a file name.It opens the file ,reads the contents into a buffer and then transmits the buffer over the ethernet using send().But the problem arises in the client side where all the bytes are not received successfully.I receive only a part of what i send.
For your reference ,here's the code snippet for the server side:
Server:
fp = fopen(filename,"r+");
strcpy(str,"");
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
fread(str, size, 1,fp);
fclose(fp);
printf("Size of the file is : %d\n",size);
sprintf(filename, "%d", size);
n = send(nsd, filename, strlen(filename), 0);
while(size > 0){
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
}
Please help me with writing the client app.I am currently confused about how to go about writing it.Shall i place the recv() part in a while(1) loop so that the client keeps running until all the bytes have been received successfully?
EDITED
For starters, you could both read from the file and write to the socket in chunks at the same time.
Since, you are transferring data over TCP, remember that data is transferred reliably as a stream and not as messages. So, don't make assumptions about how the data is recv'd except for the order.
Here is how it could be written:
open socket
open file
size_of_file = read_file_size(file);
send(socket, &size_of_file, sizeof(int), ...)
while (all is written)
read fixed chunk from file
write as much was read to the socket
cleanup // close file, socket
As for the recv part, I think it is best you send the file size over as an integer and keep reading in a while loop until you have recv'd as many bytes as you are sending from the server.
It's like this:
recv(socket, &size_of_msg, sizeof(int), ...)
while(all is read)
read fixed chunk from the socket
cleanup
Well I see atleast some issue with the way you are sending message over socket.
First from the man page of fread:
The function fread() reads nmemb elements of data, each size bytes
long, from the stream pointed to by stream, storing them at the loca-
tion given by ptr.
and what you are trying is this:
fread(str, size, 1,fp);
I assume what you meant was
fread(str, 1,size,fp);
Though it shold not casue the issue.
But the problem lies here:
n = send(nsd, str, strlen(str), 0);
printf("%d bytes sent successfully\n",n);
if(n == 0) break;
sentbytes = sentbytes + n;
size = size - sentbytes;
Though you are decreasing 'size' by decreasing by number of bytes successfully send, where are you extending str to point to new buffer location where data will be send.This will only resend initial bytes of the buffer repeatedly.
str += n; //Assuming str is char*
will solve your issue.
Using strlen doesn't seem appropriate. You've read the file, you know how long it is, so why do strlen? Either you'll just get the same result (so it's redundant) or you'll get something else (so it's a bug).
"Shall i place the recv() part in a while(1) loop so that the client keeps running until all the bytes have been received successfully?"
Something like that. Never presume that a recv() call got everything that was sent -- tcp/ip breaks messages into packets at a lower level, and recv() will return after reading whatever amount of data has actually been received at whatever point. You don't have to worry about that directly, except in so far as you do need to use some kind of protocol to indicate how long a message is so the receiver knows how much to read, then eg.:
char buffer[4096];
int msgsz = 600, // see below
sofar = 0,
cur;
while (sofar < msgsz) {
cur = recv (
socket_fd,
&buffer[sofar],
msgsz - sofar,
0
);
if (cur == -1) {
// error
break;
} else if (cur == 0) {
// disconnected
break;
}
sofar += cur;
}
WRT msgsz, you would include this somewhere in a fixed length header, which is read first. A simple version of that might be just 4 bytes containing a uint32_t, ie, an int with the length. You could also use a null terminated string with a number in it, but that means reading until '\0' is found.
This loop is supposed to take data from a socket line by line and put it in a buffer. For some reason, when there is no new data to return, recv returns the last couple lines it got. I was able to stop the bug by commenting out the first recv, but then I cant tell how long the next line will be. I know it's not a
while(this->connected){
memset(buf, '\0', sizeof(buf));
recv(this->sock, buf, sizeof(buf), MSG_PEEK); //get length of next message
ptr = strstr(buf, "\r\n");
if (ptr == NULL) continue;
err = recv(this->sock, buf, (ptr-buf), NULL); //get next message
printf("--%db\n%s\n", err, buf);
tok[0] = strtok(buf, " ");
for(i=1;tok[i-1]!=NULL;i++) tok[i] = strtok(NULL, " ");
//do more stuff
}
The manual states:
MSG_PEEK
This flag causes the receive operation to return data from the
beginning of the receive queue without
removing that data from the queue.
Thus, a subsequent receive call will
return the same data.
So I think you're getting the correct behavior, but perhaps expecting something else.
Your problem is that when you use recv with MSG_PEEK, you are giving recv the whole size of your buffer, if there are two lines already there, like "HELLO\r\nHELLO\r\n" it will read them into your buff.
ptr would point to the first \r\n, then you call recv with (ptr - buff) which will make recv to read only the first HELLO, into buf, but since you already READ that info into buff, you will process the two lines, but leaving \r\nHELLO\r\n in your queue, because you did not fully read them.
Next time you would peek into it and have info hanging that you already processed, leading you to believe that you are getting repeated data.
(I hope I wrote this clear enough, it is a very confusing bug you got there :)
I needed to add 2 to the length of the second recv so I'd take the "\r\n". Otherwise, it sees the first "\r\n" and thinks the line of the end is buf[0].
Hi i find the solution :
void receiver(int accepted_client) {
// Ready to receive data from client.
while (true) {
char buffer[256];
recv(accepted_client, &buffer, 255, 0);
int sum = 0;
for (int i = 0; i < 256; i++) // Check that buffer value is zero or not.
sum |= buffer[i];
if (sum != 0) {// If buffer value is not zero then start to print the new received message.
string string_message(buffer);
cout << string_message << endl;
}
memset(&buffer, 0, 256); // Clear the buffer.
}
}