tags:

views:

139

answers:

3

c++

#define BUF_LEN 1024

the below code only receives one byte when its called then immediately moves on.

output = new char[BUF_LEN];
bytes_recv = recv(cli, output, BUF_LEN, 0);
output[bytes_recv] = '\0';

Any idea how to make it receive more bytes?

EDIT: the client connecting is Telnet.

A: 

Force the sending side to send more bytes using Nagle's algorithm, then you will receive them in packages.

alemjerus
the client is telnet.
0xe9
this code should work correctly right? all examples i can find on the internet do no different.
0xe9
Telnet explicitly disables Nagle to send, receive and echo a char at a time. Try a bulk protocol like ftp.
Nikolai N Fetissov
+3  A: 

The thing to remember about networking is that you will be able to read as much data as has been received. Since your code is asking for 1024 bytes and you only read 1, then only 1 byte has been received.

Since you are using a telnet client, it sounds like you have it configured in character mode. In this mode, as soon as you type a character, it will be sent.

Try to reconfigure your telnet client in line mode. In line mode, the telnet client will wait until you hit return before it sends the entire line.

On my telnet client. In order to do that, first I type ctrl-] to get to the telnet prompt and then type "mode line" to configure telnet in line mode.

Update

On further thought, this is actually a very good problem to have.

In the real world, your data can get fragmented in unexpected ways. The client may make a single send() call of N bytes but the data may not arrive in a single packet. If your code can handle byte arriving 1 by 1, then you know it will work know matter how the data arrives.

What you need to do is make sure that you accumulate your data across multiple receives. After your recv call returns, you should then append the data a buffer. Something like:

char *accumulate_buffer = new char[BUF_LEN];
size_t accumulate_buffer_len = 0;

...

bytes_recv = recv(fd,
                  accumulate_buffer + accumulate_buffer_len,
                  BUF_LEN - accumulate_buffer_len,
                  0);
if (bytes_recv > 0)
    accumulate_buffer_len += bytes_recv;

if (can_handle_data(accumulate_buffer, accumulate_buffer_len))
{
    handle_data(accumulate_buffer, accumulate_buffer_len);
    accumulate_buffer_len = 0;
}

This code keeps accumulating the recv into a buffer until there is enough data to handle. Once you handle the data, you reset the length to 0 and you start accumulating afresh.

R Samuel Klatchko
+1  A: 

First, in this line:

output[bytes_recv] = '\0';

you need to check if bytes_recv < 0 first before you do that because you might have an error. And the way your code currently works, you'll just randomly stomp on some random piece of memory (likely the byte just before the buffer).

Secondly, the fact you are null terminating your buffer indicates that you're expecting to receive ASCII text with no embedded null characters. Never assume that, you will be wrong at the worst possible time.

Lastly stream sockets have a model that's basically a very long piece of tape with lots of letters stamped on it. There is no promise that the tape is going to be moving at any particular speed. When you do a recv call you're saying "Please give me as many letters from the tape as you have so far, up to this many.". You may get as many as you ask for, you may get only 1. No promises. It doesn't matter how the other side spit bits of the tape out, the tape is going through an extremely complex bunch of gears and you just have no idea how many letters are going to be coming by at any given time.

If you care about certain groupings of characters, you have to put things in the stream (ont the tape) saying where those units start and/or end. There are many ways of doing this. Telnet itself uses several different ones in different circumstances.

And on the receiving side, you have to look for those markers and put the sequences of characters you want to treat as a unit together yourself.

So, if you want to read a line, you have to read until you get a '\n'. If you try to read 1024 bytes at a time, you have to take into account that the '\n' might end up in the middle of your buffer and so your buffer may contain the line you want and part of the next line. It might even contain several lines. The only promise is that you won't get more characters than you asked for.

Omnifarious
+1 very nice explanation of some tricky concepts
Bill Forster