tags:

views:

266

answers:

4

I am building a server-client program with c and having some problen wtih sendina a whole file with send() and recv() function. I need to send the whole file with these but all these functions can do is send a string. The main problem is with sending the exe or other binary formet data. Should I use htons or htonl func? I dunno how to use those along these as I am merely a noob.

I am stuck with this and love your help. Thanks!!

Here is the server side recv function ::

if (socket_type != SOCK_DGRAM)
    {

            fi = fopen (final,"wb");
            retval = recv(msgsock, recv_buf, strlen(recv_buf), 0);
            /*recv_buf[retval] = '\0';
            fprintf (fi,"%s",recv_buf);*/

            int i;
            i=atoi(recv_buf);
            char *q;
            q=(char *)malloc(i*sizeof(char));
            retval = recv(msgsock, q, strlen(q), 0);
            //printf ("%s",q);
            fwrite(q,i,1,fi);
            fclose(fi);

    }
    else
    {
        retval = recvfrom(msgsock,recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from, &fromlen);
        printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
        printf ("SOCK_DGRAM");
    }

    if (retval == SOCKET_ERROR)
    {
        fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
        closesocket(msgsock);
        //continue;
    }
    else
        printf("Server: recv() is OK.\n");

    if (retval == 0)
    {
        printf("Server: Client closed connection.\n");
        closesocket(msgsock);
            //continue;
    }
    printf("Server: Received %d bytes, data from client\n", retval);

The client side sending function :::

void send_command() { int bytesent; FILE *file_out; //file_out = fopen(file_path,"rb"); char str_all[100000];//flag [30]="end";

///////////////////////getsize//////////////
char fsize[5];
int filesize;
file_out = fopen(file_path, "rb");
fseek(file_out, 0, SEEK_END);
filesize = ftell(file_out);
rewind (file_out);
itoa (filesize,fsize,10);
/////////////////////////////////////////////
send (ConnectSocket, fsize, strlen (fsize), 0);

char *r = (char *)malloc (filesize * sizeof(char));

fread(r,filesize,1,file_out);
bytesent = send( ConnectSocket, r, strlen(r), 0 );
printf("\nClient: Bytes sent: %ld\n", bytesent);
fclose (file_out);

/*while (fscanf(file_out,"%s",&str_all) != EOF)
{
    bytesent = send( ConnectSocket, str_all, strlen(str_all), 0 );
    printf("\nClient: Bytes sent: %ld\n", bytesent);
    //Sleep(500);
}*/

/*printf("%s",flag);
send( ConnectSocket, flag, strlen(flag), 0 );*/
WSACleanup();
//return 0;
}
+3  A: 

send() does not send a string, it sends an array of bytes. You create your buffer, fill it, send the buffer and pass the # of bytes in it to send(), and from there.

Joe
+2  A: 

Depending on the operating system you are on, there may be a sendfile command; but it is not guaranteed to work portably across different operating systems. The most portable way is to just read() the file in in chunks into a buffer, and then write() it out (or send() it out, if you're using a socket, though write() should work just fine too).

See my answer to this previous question asking essentially the same thing.

Brian Campbell
+1  A: 

What you have to do is to send your data in several chunks, one chunk at a time. So, essentially you read your file N bytes at a time into a buffer and send() those N bytes.

MAK
+3  A: 

You'll need to implement that functionality yourself, or use a library that does so. send(2) just sends a raw byte buffer. If you want to send a file, you'll need to use some sort of protocol that both the client and the server understand.

The simplest possible protocol might be to have the client send the filename, the length of the file, and then the raw file data. For example (error checking omitted for clarity):

// Server:
const char *filename = ...;
uint32_t filenameLen = strlen(filename);
uint32_t filenameLenNet = htonl(filenameLen);
send(fd, &filenameLenNet, sizeof(filenameLenNet), 0);
send(fd, filename, filenameLen, 0);

// You should probably use a 64-bit file length; also, for large files, you
// don't want to read the entire file into memory, you should just stream it
// from disk to network in reasonably-sized chunks.
const void *fileData = ...;
uint32_t fileLen = ...;
uint32_t fileLenNet = htonl(fileLen);
send(fd, &fileLenNet, sizeof(fileLenNet), 0);
send(fd, fileData, fileLen, 0);

// Client:
char *filename;
uint32_t filenameLen;
recv(fd, &filenameLen, sizeof(filenameLen), 0);
filenameLen = ntohl(filenameLen);
filename = malloc(filenameLen + 1);
recv(fd, filename, filenameLen, 0);
filename[filenameLen] = 0;
uint32_t fileLen;
recv(fd, &fileLen, sizeof(fileLen), 0);
fileLen = ntohl(fileLen);
void *fileData = malloc(fileLen);
recv(fd, fileData, fileLen, 0);
// Write file Data to the output file.  Again, for large files, it would be
// better to stream it in in chunks instead of reading it all in at once.

Also, be careful about partial sends/receives. Make sure you check the return values from send and recv, since they can (and do) often only send or receive a subset of the data you intent to send or receive. When that happens, you have to recover by resending or rereceiving in a loop until you've processed all the data you intended or an error occurs.

As an alternative to using your own protocol, you can use an existing protocol with a library such as libftp or libcurl.

Adam Rosenfield
This function is for 32 bit variable on linux,can u tell me about the windows variable?? pLease It will be a great help as I cannot implement it in windows.