J.kol
J.kol

Reputation: 43

c++ read unknow amount of data from socket

I wrote a simple tcp/ip connection client-server in c++.

This is the part of the server that handles the connection

int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = 0;

sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
    cout << "Error opening socket" << endl;
    exit(1);
}

bzero((char*)&serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);

if(bind(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0){
    cout << "Error binding" << endl;
    exit(1);
}

listen(sockfd,1);
clilen = sizeof(cli_addr);

newsockfd = accept(sockfd,(struct  sockaddr *)&cli_addr, &clilen );

if(newsockfd < 0){
    cout << "Error accepting" << endl;
    exit(1);
}

bzero(bytes,size_tot);
uint64_t total_bytes_read = 0;
uint64_t total_bytes_to_read = size_tot;
while(total_bytes_read < total_bytes_to_read){
    int bytes_read = read(newsockfd,bytes + total_bytes_read,total_bytes_to_read - total_bytes_read);
    if(bytes_read == -1){
        cout << "error reading "<< endl;
        n = -1;
        break;
    }
    total_bytes_read += bytes_read;
}

but this works if I know the total amount of bytes to be read. What if the total amount of data to be read is unknown? How I can modify this piece of code?

Upvotes: 1

Views: 4260

Answers (2)

David Schwartz
David Schwartz

Reputation: 182761

You asked how to fix your low-level receiving code. That's simple -- just call read once and don't use a while loop. The call to read will return as soon as at least one byte of data can be read. For the number of bytes to read, just pass in the size of your buffer (or the space left in it if there's already some leftover in it from a prior call).

You will also need high-level protocol code, just as you do if you know the number of bytes. That code will probably need to be a bit different. If the chunk of bytes you got includes your stop indication, then process all the bytes up to the stop indication and keep the extra in the buffer for next time. If not, just call read again and get a bunch more bytes.

Your protocol handling code should look sort of like this:

  1. Call read and add however many bytes you got to the buffer. (Handle an error or normal close here.)
  2. If the data in the buffer does not include the stop indication, go to step 1.
  3. Process all the bytes up to the stop indication.
  4. Remove the processed bytes from the buffer, leaving any unprocessed bytes.
  5. Go to step 2.

Also, the code you gave in the question will spin forever if the other side closes the connection. In this case, read will return zero and you will never be able to read any more data from the connection. You should break out of the loop if read returns zero.

Upvotes: 3

SergeyA
SergeyA

Reputation: 62563

First of all, get rid of all bzero calls. I do not know why this keeps creeping into good people's code. There is zero, nada, nicht need for this.

Second of all, you'd need to either somehow communicate the size of transmission beforehand - for example, HTTP 1.1 provides for this information in the header - or simply state that connection is closed once all the data has been transferred - this would be HTTP 1.0 model.

Upvotes: 2

Related Questions