简体   繁体   中英

How to send and receive bytes with socket apis?

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.

"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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM