Weiheng Li Weiheng Li - 20 days ago 4
C Question

In c socket, why my server can't receive the whole content?

I am new in this field, and writing one server and client, but it really confusing that I can't get all the content, but some small clip.
My server code:

read(connfd, name, 20);
//recv(connfd,name,1024,0);
char* a=name;
while(a[0]!='\n'){
a++;
}
a[0]='\0';
printf("name:%s\n", name);
read(connfd, size, 20);
printf("size:%s\n", size);
recv(connfd,buf,8192,0);
printf("buf:%s\n", buf);
if((stream = fopen(name,"w+t"))==NULL){
printf("The file was not opened! \n");
}
int write_length = fwrite(buf,sizeof(char),8192,stream);
bzero(buf,8192);
if(put){
char *res="OK\n";
write(connfd, res, 1024);
}
fclose(stream);


and my client code is:

char buffer[8192];
bzero(buffer,8192);
char * put="PUT\n";
if ((write(fd, put, 8192)) <= 0) {
if (errno != EINTR) {
fprintf(stderr, "Write error: %s\n", strerror(errno));
exit(0);
}
}
struct stat st ;
stat( put_name, &st );
char str[100];
sprintf(str, "%d", st.st_size);
int len;
char *current=NULL;
len=strlen(put_name);

char sendname[1024];
strcpy(sendname,put_name);
strcat(sendname,"\n");
write(fd, sendname, 10);
strcat(str,"\n");
write(fd, str, 10);
FILE *stream;
if((stream = fopen(put_name,"r"))==NULL)
{
printf("The file was not opened! \n");
exit(1);
}
int lengsize = 0;
while((lengsize = fread(buffer,1,8192,stream)) > 0){
if(send(fd,buffer,8192,0)<0){
printf("Send File is Failed\n");
break;
}
bzero(buffer, 8192);
}


Now, I can send all content, but can receive part of them. for example, on my mac, server can receive name but the
str
is neglected, when I printf the str in the server, it shows the content of file. and the content of file is not the whole file content. Some content disappear. Could you tell me why?

Answer

You are ignoring the return values of send() and recv(). You MUST check return values!

When sending the file, lengsize receives how many bytes were actually read from the file. Your client is sending too many bytes when lengsize is < 8192 (typically the last block of the file if the file size is not an even multiple of 8192).

But more importantly, although the client is telling the server the file size, the server is ignoring it to know when to stop reading. The server is also ignoring the return value of recv() to know how many bytes were actually received so it knows how many bytes can safely be written to the output file.

Try something more like this instead:

common:

int readData(int s, void *buf, int buflen)
{
    int total = 0;
    char *pbuf = (char*) buf;
    while (buflen > 0) {
        int numread = recv(s, pbuf, buflen, 0);
        if (numread <= 0) return numread;
        pbuf += numread;
        buflen -= numread;
        total += numread;
    }
    return total;
}

int sendData(int s, void *buf, int buflen)
{
    int total = 0;
    char *pbuf = (char*) buf;
    while (buflen > 0) {
        int numsent = send(s, pbuf, buflen, 0);
        if (numsent <= 0) return numsent;
        pbuf += numsent;
        buflen -= numsent;
        total += numsent;
    }
    return total;
}

int readInt32(int s, int32_t *value)
{
    int res = readData(s, value, sizeof(*value));
    if (res > 0) *value = ntohl(*value);
    return res;
}

int sendInt32(int s, int32_t value)
{
    value = htonl(value);
    return sendData(s, &value, sizeof(value));
}

char* readStr(int s)
{
    int32_t size;
    if (readInt32(s, &size) <= 0)
        return NULL;

    char *str = malloc(size+1);
    if (!str)
         return NULL;

    if (readData(s, str, size) <= 0) {
        free(str);
        return NULL;
    }
    str[size] = '\0';

    return str;
}

int sendStr(int s, const char *str)
{
    int len = strlen(str);
    int res = sendInt32(s, len);
    if (res > 0)
        res = sendData(s, str, len);
    return res;
}

server:

char buffer[8192];

char *name = readStr(connfd);
if (!name) {
    // error handling ...
    sendStr(connfd, "Socket read error");
    return;
}
printf("name:%s\n", name);

int32_t filesize;
if (readInt32(connfd, &filesize) <= 0) {
    // error handling ...
    free(name);
    sendStr(connfd, "Socket read error");
    return;
}
printf("size:%d\n", filesize);

if ((stream = fopen(name, "wb")) == NULL) {
    // error handling ...
    printf("The file was not opened!\n");
    free(name);
    sendStr(connfd, "File not opened");
    return;
}

while (filesize > 0) {
    int numread = readData(connfd, buf, min(filesize, sizeof(buffer)));
    if (numread <= 0) {
        // error handling ...
        close(stream);
        free(name);
        sendStr(connfd, "Socket read error");
        return;
    }

    printf("buf:%.*s\n", numread, buf);

    if (fwrite(buf, 1, numread, stream) != numread) {
        // error handling ...
        close(stream);
        free(name);
        sendStr(connfd, "File write error");
        return;
    }

    filesize -= numread;
}

fclose(stream);
free(name);

sendStr(connfd, "OK");

client:

char buffer[8192];

struct stat st;
if (stat( put_name, &st ) != 0) {
    // error handling ...
    exit(0);
}

if ((stream = fopen(put_name, "rb")) == NULL) {
    // error handling ...
    printf("The file was not opened!\n");
    exit(0);
}

if (sendStr(fd, put_name) <= 0) {
    // error handling ...
    close(stream);
    exit(0);
}

int32_t filesize = st.st_size;
if (sendInt32(fd, filesize) <= 0) {
    // error handling ...
    close(stream);
    exit(0);
}

int lengsize;
while (filesize > 0) {
    lengsize = fread(buffer, 1, min(filesize , sizeof(buffer)), stream);
    if (lengsize <= 0) {
        printf("Read File Failed\n");
        // error handling ...
        close(stream);
        exit(0);
    }

    if (sendData(fd, buffer, lengsize) <= 0) {
        printf("Send File Failed\n");
        // error handling ...
        close(stream);
        exit(0);
    }

    filesize -= lengsize;
}

close(stream);

char *resp = readStr(fd);
if (!resp) {
    // error handling ...
    exit(0);
}

if (strcmp(resp, "OK") == 0)
    printf("Send File OK\n");
else
    printf("Send File Failed: %s\n", resp);

free(resp);