We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

converting void* to char*

kuntilanak
kuntilanak asked
on
Medium Priority
555 Views
Last Modified: 2012-05-06
Ok, I don't know if any of you is familiar with the recv function, if you aren't please look it here:

http://www.opengroup.org/onlinepubs/009695399/functions/recv.html

There basically it puts the response from the server back into a void pointer , called buffer.. say that buffer is actually strings... so how would I print it out?
Comment
Watch Question

Cast it to  (char *)buffer
The following method takes a buffer of a specified type and size where it will output data:

ssize_t recv(int socket, void *buffer, size_t length, int flags);

So if you know that this function is going to generate character data, then all you need to do is place that data within a character buffer.
int bufferSize = 1024;
char *myBuffer = new char[bufferSize];
 
if (recv(socket, myBuffer, 1024 * sizeof(char), flags) > 0)
{
     /* Display message when successful. */
     printf(myBuffer);
}

Open in new window

ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
if you mean a C null terminates string, you might use puts(biffer) or printf("%s",buffer)
otherwise, if it is not guarnateed to be null terminated, you might use
size= recv(socket, buffer, length, flags);
printf("%.*s",size,buffer)

Author

Commented:
Before printing out the actual buffer that the server sent I tried to print out the quote_length, which is supposed to be the buffer size.. and it turns out when I print it out it's 0. Why is this? Am I doing it right?
recv(sock_fd, quote_received, quote_length,0);
printf("Quote length is %d\n", quote_length);

Open in new window

Author

Commented:
and I don't know how big the buffer size sent by the server will be so I can't allocate
char *myBuffer = new char[bufferSize];

Open in new window

You can use the MSG_PEEK flag to determine the size of the next message. So you can use the value returned by that to allocate your buffer.

Author

Commented:
just to make it easier, I have attached my code below
cl.txt
length is in parameter.
Specifies the length in bytes of the buffer pointed to by the buffer argument.
should be like this
recv(sock_fd, quote_received, sizeof(quote_received),0);
ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
if you pass recv a quote_length=0, you are telling it to receive no bytes
If memory serves, you can do this like follows:
int quote_length = recv(sock_fd, quote_received, 0, MSG_PEEK);
 
char *myBuffer = new char[quote_length];
 
if (recv(sock_fd, quote_received, quote_length, 0) > 0)
{
     /* Display message when successful. */
     printf(myBuffer);
}

Open in new window

Author

Commented:
I changed it to this and it still doesn't work
recv(sock_fd, quote_received, sizeof(quote_received),0);

Open in new window

Author

Commented:
>>if you pass recv a quote_length=0, you are telling it to receive no bytes

I did not specify it to be 0 anywhere in the code, besides isn't the length determined by how much bytes the server send me

Author

Commented:
I also tried to print out what recv returns and it returns -1 which should be fine...
In your code, you are not allocating memory for quote_received. Allocate memory and read
ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:

RETURN VALUES
     These calls return the number of bytes received, or -1 if an error
     occurred.
As I said previously, you should be able to peek at the entry size with the following line. You can then use this value to allocate the memory you require.
/* First call to recv returns length of quote in bytes. */
int quote_length = recv(sock_fd, quote_received, 0, MSG_PEEK);
if (quote_length > 0)
{
     /* Allocate out buffer. */
     char *quote_recieved = new char[quote_length];
 
     /* Fetch data into buffer now that we know the size. */
     /* Verify that no errors were encountered. */
     if (recv(sock_fd, quote_received, quote_length, 0) > 0)
     {
          /* Display message when successful. */
          printf(quote_recieved);
     }
}

Open in new window

ozo
CERTIFIED EXPERT
Most Valuable Expert 2014
Top Expert 2015

Commented:
neither quote_received nor quote_length seem to have been initialzed
Sorry, a slight typo in my previous post. The MSG_PEEK call of recv still needs a buffer to put data. So a small buffer is required to satisfy this call, most of the message data will be truncated, but will not be removed from the queue.

We can then use this value to allocate our actual quote buffer, and then actually get the information.

So amending this into the above code:
/* First call to recv returns length of quote in bytes. */
char temp_small_buffer[3];
int quote_length = recv(sock_fd, temp_small_buffer, 3, MSG_PEEK);
if (quote_length > 0)
{
     /* Allocate out buffer. */
     char *quote_recieved = new char[quote_length];
 
     /* Fetch data into buffer now that we know the size. */
     /* Verify that no errors were encountered. */
     if (recv(sock_fd, quote_received, quote_length, 0) > 0)
     {
          /* Display message when successful. */
          printf(quote_recieved);
     }
}
else if (quote_length < 0)
{
     /* A problem occurred whilst receiving data. */
     printf ("An error has occurred.");
}

Open in new window

Author

Commented:
>>neither quote_received nor quote_length seem to have been initialzed

how do you do that?

Author

Commented:
is there a way to fix this without using the MSG_PEEK

Author

Commented:
ok I just initialized the quote_length and quote_received as below... just for test purpose.. however it still doesn't work...

when I tried to print the quote_received it prints nothing
int quote_length = 1024;
char *quote_received = malloc(quote_length);

Open in new window

Author

Commented:
ok latest update:

for some reason when I do something like the code below it works and I have no idea why it is, can you guys tell me why this is??? is it because the server is sending two sent request back to the client so therefore I need two recv?
recv(sock_fd, quote_received, quote_length ,0);
printf("%s\n", quote_received);
recv(sock_fd, quote_received, quote_length ,0);
printf("%s\n", quote_received);

Open in new window

Author

Commented:
I am able to pull out the data from the server now using the below code:

However, the server replied this at the end:

read_quote_num(19640): read error on quote number : Connection reset by peer

I have no idea why this is, can anyone have a guess at this?
recv(sock_fd, quote_size, 4 ,0);
quote_received = malloc(ntohl(*quote_size));
recv(sock_fd, quote_received, ntohl(*quote_size) ,0);
printf("%s\n", quote_received);

Open in new window

CERTIFIED EXPERT
Top Expert 2009

Commented:
>> is it because the server is sending two sent request back to the client so therefore I need two recv?

Whether the server sends more than one request or not has no direct impact on how many recv's you need to do to get your data. The transport protocol streams the data to you, irrespective of the send's done on the sending side.

You need to do as many recv's as necessary to get the data you need. Always check the return value of recv to see how many (if any) bytes it returned. If you need more, then call recv again. If you have enough, no need to call recv again :)


>> read_quote_num(19640): read error on quote number : Connection reset by peer

"connection reset by peer" means that the other side closed the connection.
>>>> recv(sock_fd, quote_size, 4 ,0);
I wouldn't send and read each single attribut with a new call, especially if they are all of different type. That is too much error-prone and if you change one side you always have to change the other side too. You better send structures (with same alignment)  which build a full message. The last member of that structure could be of dynamic size though I rather would recommend to provide a very big char array at end which could hold any text size needed.

struct MyHeader
{
    unsigned int  quote_size;
    unsigned int  quote_received;
    unsigned int  message_type;
    unsigned int  message_length;
};
struct MyBuffer
{
     MyHeader  head;
     char  message[4080];
};

The sizeof(MyBuffer) should be 4096 on both sides.

You would send it like

   MyBuffer buf = { 0 };  // makes all zero
   buf.head.quote_size        = qs;
   buf.head.quote_received = qr;
   buf.head.quote_message_type = 1;  // say 1 is Normal_Text
   buf.head.quote_message_length = strlen(szmsg);
   strcpy(buf.head.message, szmsg);
   send(sock_fd, (char*)&buf, sizeof(buf.head) +
                                               buf.head.quote_message_length + 1, 1);


and receive it

    int rc = 0;
    int nread = 0;
    MyBuffer buf = { 0 };  // makes all zero
   
    // we have to read in a loop cause the buffer may be sent incomplete
    nread = 0;
    while (true)
    {
         rc = recv(sock_fd, ((char*)&buf)[nread], sizeof(buf)-nread, 0);
         if (rc == -1) // error
         {
               // handle error: get errno or call GetWSALastError on windows
         }
         nread += rc;
         if (nread >= (int)sizeof(buf.head) && 
             nread == sizeof(buf.head) + buf.head.message_length+1)
         {
                // coming here we have read all that was sent and break the loop
                break;
         }
         // read the rest nect cycle

     }
     
      // now the buf is filled and we could access the members e.g.
      printf("%s", buf.head.message);  
>>>> "connection reset by peer" means that the other side closed the connection.

That often happens if you have a console prog for send and the prog terminates before the client makes the read.

You should run the sender in a loop or at least ask for quit at end of prog.

Author

Commented:
ok, then maybe I should use a while loop instead... the problem is that the first data sent back to the client is a 32 bit and the next one is I don't know what size it is... so how can I do this?

Author

Commented:
I tried the while loop approach from my code below

however the program never quits, I never knew why.. although it seems like it's only printing the quote once...

can anyone help?
recv(sock_fd, quote_size, 4 ,0);
		quote_received = malloc(ntohl(*quote_size));
		while (recv(sock_fd, quote_received, ntohl(*quote_size) ,0) != 0)
			printf("%s\n", quote_received);
		close(sock_fd);

Open in new window

CERTIFIED EXPERT
Top Expert 2009

Commented:
>> the problem is that the first data sent back to the client is a 32 bit and the next one is I don't know what size it is... so how can I do this?

As soon as you have received the 32bit value, you know the size of the rest of the data.
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> however the program never quits

1) you need to ALWAYS check the return value of recv. Also for the first call, to make sure that it actually received 4 bytes. Note that recv will return a negative value in certain cases - don't forget to check for that too. Check the reference page (you posted it in your question) for more information.

2) you're depending on the fact that the received data is null terminated. That isn't necessarily so.
CERTIFIED EXPERT
Top Expert 2009

Commented:
What's the type of quote_size btw ?

Author

Commented:
>>What's the type of quote_size btw ?

I declared this on top as I know the first byte sent from the server will be 32-bit integer in network byte-order.

int  quote_size[4];
CERTIFIED EXPERT
Top Expert 2009

Commented:
You might want to make that an unsigned int type.

Author

Commented:
and I think quote_size does the job right... as when I confirmed with the number of bytes that the server will send to the client, it matches it fine...

problem with my while loop above is that.. recv returns a 4 at the end and not a 0, I don't know where this 4 comes from.. my guess it's the 4 bytes that specifies how large the next buffer will be, but why is it sent at the end instead of the first time? If it is sent at the end then how come I can get the correct size of buffer when I do recv for the very first time? Can it be the case that the server sends the data backwards?
CERTIFIED EXPERT
Top Expert 2009

Commented:

Author

Commented:
i checked it and it returns 4 bytes which means it's a 32 bit
CERTIFIED EXPERT
Top Expert 2009

Commented:
And the rest of that post ? Regarding recv returning a negative value and assuming null termination of the received data ?

Author

Commented:
when I do something like this:

it works for some reason that I don't know why...
do {
			flag = recv(sock_fd, quote_received, ntohl(*quote_size) ,0);
			printf("%s\n", quote_received);
		} while (flag !=  ntohl(*quote_size) || flag != -1);

Open in new window

CERTIFIED EXPERT
Top Expert 2009

Commented:
Euhm, that will loop infinitely. Are you sure that works ?

In any case, that's not what I was referring to.

With every call of recv you need to check the return value. If it's smaller than 0, then an error occurred, and you need to take appropriate action. If 0 is returned, then no data was received (if you need more data, just wait a bit and try again). If a value larger than 0 is returned, then that's the amount of bytes that was received (if you need more, then you need to call recv again to get the rest of the data).

Plus, as I said earlier : you cannot depend on the received data being null terminated, so specifically, you cannot use %s for it.

Author

Commented:
so if I can't use %s then what should I do?
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> so if I can't use %s then what should I do?

First receive all the data you need, then add a null terminator, and then show it to the user. But you're skipping the most important part of my post ;)

Author

Commented:
it's weird that now it doesn't work again and I don't know what i've changed...  here's what I did based on your suggestion
do {
                        flag = recv(sock_fd, quote_received, ntohl(*quote_size) ,0);
			   if (flag == -1 || flag == 0){
				close(sock_fd);
				exit(1);
			   }
                        printf("%s\n", quote_received);
                } while (flag > 0);
		free(quote_received);

Open in new window

CERTIFIED EXPERT
Top Expert 2009

Commented:
>> it's weird that now it doesn't work again

Please re-read my suggestions. You've missed some important parts :)

Author

Commented:
I did read your suggestion:

It's this part right?

With every call of recv you need to check the return value. If it's smaller than 0, then an error occurred, and you need to take appropriate action. If 0 is returned, then no data was received (if you need more data, just wait a bit and try again). If a value larger than 0 is returned, then that's the amount of bytes that was received (if you need more, then you need to call recv again to get the rest of the data).
CERTIFIED EXPERT
Top Expert 2009

Commented:
If recv returns 0, it doesn't mean there was an error - it simply means that no data was available (yet). If you need more data, just wait, and try again.

And how about the parts where I speak about null termination ?

You might also want to show an error message in case recv returns -1 ... so you at least know what the problem was.

Author

Commented:
>>you need more data, just wait, and try again.

how do you wait?
CERTIFIED EXPERT
Top Expert 2009

Commented:
You could use the MSG_WAITALL flag (see the reference page you posted in your question), or you can actually call a system wait yourself ... Which one depends on your platform (Sleep, usleep, wait, ...).
CERTIFIED EXPERT
Top Expert 2009

Commented:
At this point, I think it's more worthwhile for you to read up on socket programming before continuing. I suggest reading through this excellent tutorial ("Beej's Guide to Network Programming") :

        http://beej.us/guide/bgnet/

Author

Commented:
ok.. I think that's beyond the scope of the course.. I think we can assume here that it will never wait..

also my implementation above works only if the quote sent is smaller or at least equal to quote_size, if it's bigger.. I don't know why it doesn't work

Author

Commented:
I've read that as well before making this thread Infinity08

Author

Commented:
anyway what you said was right, the code above goes through an infinite loop... it prints out the quotes I want perfectly, but it never goes out of that while loop...
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> ok.. I think that's beyond the scope of the course.. I think we can assume here that it will never wait..

If the course is about learning socket programming, then learning how to do it correctly is not beyond it's scope, I'd assume.


>> also my implementation above works only if the quote sent is smaller or at least equal to quote_size, if it's bigger.. I don't know why it doesn't work

Null termination ?
Multiple recv's to receive the whole data before showing it to the user ?
I think I already mentioned that ;)

Btw, you already know the size of the data to receive ... How is it possible that you receive more than that size ?
If the first 4 bytes tell you to receive x bytes, then call recv until you have received those x bytes, and stop there ...


>> I've read that as well before making this thread Infinity08

Maybe not in enough detail. That tutorial contains very clear code examples that show how to handle this kind of situation correctly.

Author

Commented:
>>Btw, you already know the size of the data to receive ... How is it possible that you receive more than >>that size ?
>>If the first 4 bytes tell you to receive x bytes, then call recv until you have received those x bytes, and >>stop there ...

Yes that is right, that's why I am saying that we don't need a while loop here as we know how much the size of the data to receive after the first response from the server, therefore all we need to do is just do a recv command for the second time right...

however for a very large files.. this doesn't work.. I will need a while loop. The problem with my current while loop is that.. the loop is stuck when calling receive.. I think it calls receive but there's nothing to be received so therefore it's just sitting there like a dumb guy on a street and do nothing.. so somehow I need to fix this and after that it should run fine
CERTIFIED EXPERT
Top Expert 2009

Commented:
>> Yes that is right, that's why I am saying that we don't need a while loop here as we know how much the size of the data to receive after the first response from the server, therefore all we need to do is just do a recv command for the second time right...

You DO need a while loop, since recv might not return all of the data immediately. You need to call recv 1 or more times until you have received all data.


>> The problem with my current while loop is that.. the loop is stuck when calling receive..

Are you using a blocking socket ? Is the data you need actually available ?

Author

Commented:
>>Are you using a blocking socket ? Is the data you need actually available ?

I don't even know what a blocking socket is,below is my latest attempt
while (flag = recv(sock_fd, quote_received, ntohl(*quote_size), 0) > 0){
			if (flag == -1){
				perror("Error: Receiving message failed \n");
				close(sock_fd);
				exit(1);
			}
              	printf("%s\n", quote_received);
		} 

Open in new window

Author

Commented:
the problem why receive won't go through is because of this:

If no messages are available at the socket and O_NONBLOCK is not set on the socket's file descriptor, recv() shall block until a message arrives

I didn't set O_NONBLOCK at the socket's file descriptor.. how can I set that? so that it won't block...
CERTIFIED EXPERT
Top Expert 2009

Commented:
You often WANT it to block, and in this case it seems appropriate, because you know how much data you need to receive, so you just wait (block) until it's available.


>> I didn't set O_NONBLOCK at the socket's file descriptor.. how can I set that? so that it won't block...

http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking

Author

Commented:
where should I put the:

fcntl(sock_fd, F_SETFL, O_NONBLOCK);

at?

Author

Commented:
>>You often WANT it to block, and in this case it seems appropriate, because you know how much data >>you need to receive, so you just wait (block) until it's available.

but in this case even after all data has been received the recv still blocks... that's my problem.
CERTIFIED EXPERT
Top Expert 2009
Commented:
>> but in this case even after all data has been received the recv still blocks... that's my problem.

That's because you didn't follow all of my suggestions ;)

In short : you don't need to call recv any more if you have already received the data you needed ...

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
so are you saying we need some kind of counter that checks how much data have we received? if that counter has been reached then we close the socket and exit?
CERTIFIED EXPERT
Top Expert 2009

Commented:
That would be a good start, yes :)

Author

Commented:
>>That would be a good start, yes :)

thanks inifnity08 my code works now, I have a question about the recvfrom() function:

ssize_t recvfrom(int socket, void *buffer, size_t length, int flags,
             struct sockaddr *address, socklen_t *address_len

so if I don't need to send back to the server after I receive something from the server can I set struck sockaddress* address and socklen_t* address_len to 0?
CERTIFIED EXPERT
Top Expert 2009

Commented:
recvfrom is only really useful for UDP or other connectionless protocols. For TCP, there's no need. Just stick with recv ;)

Author

Commented:
yes.. I am trying to connect with UDP right now... :D that's why I am asking
CERTIFIED EXPERT
Top Expert 2009

Commented:
We're getting far from the original question then ...

You can set that parameter to NULL if you don't need the sender address.

Author

Commented:
we need the sender address (i.e server address here) if we want to send another message back to them right?
CERTIFIED EXPERT
Top Expert 2009

Commented:
yes. Unless you already have it.

Author

Commented:
and so I can set socklen_t *address_len to NULL as well.....?
CERTIFIED EXPERT
Top Expert 2009

Commented:
Yes. How is this related to the original question ?

Author

Commented:
nothing...it's quite off topic
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.