在c socket中,为什么我的服务器无法接收整个内容?

时间:2016-11-16 20:00:48

标签: c sockets

我是这个领域的新手,并且编写了一个服务器和客户端,但我真的很困惑,我无法获得所有内容,而是一些小剪辑。 我的服务器代码:

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

我的客户代码是:

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);
}

现在,我可以发送所有内容,但可以收到部分内容。例如,在我的Mac上,服务器可以接收名称,但str被忽略,当我在服务器中打印str时,它显示文件的内容。并且文件的内容不是整个文件内容。有些内容消失了。你能告诉我为什么吗?

2 个答案:

答案 0 :(得分:4)

readwrite函数无法保证通过一次调用发送或接收整个消息。相反,你应该坐在一个循环中,逐步写入消息,直到所有内容都已发送,并逐步读取所有内容,直到读完所有内容。例如,如果您知道完全已发送了多少,您可以执行以下操作:

char recvBuffer[BUFFER_SIZE];
int  bytesRead = 0;

while (bytesRead < BUFFER_SIZE) {
    int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
    if (readThisTime == -1) {
       // handle error...
    }
    bytesRead += readThisTime;
}

如果您不确切知道发送了多少,请尝试:

char recvBuffer[BUFFER_SIZE];
int  bytesRead = 0;

while (bytesRead < BUFFER_SIZE) {
    int readThisTime = read(file, recvBuffer + bytesRead, BUFFER_SIZE - bytesRead);
    if (readThisTime == -1) {
       // handle error...
    }
    if (readThisTime == 0) break; // Done!

    bytesRead += readThisTime;
}

答案 1 :(得分:2)

您忽略了send()recv()的返回值。你必须检查返回值!

发送文件时,lengsize会收到实际从文件中读取的字节数。 lengsize&lt; recv()时,您的客户端发送的字节数太多8192(如果文件大小不是8192的偶数倍,通常是文件的最后一个块)。

但更重要的是,虽然客户端告诉服务器文件大小,但服务器忽略它以知道何时停止读取。服务器也忽略了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; } 的返回值,知道实际接收了多少字节,因此它知道可以安全地将多少字节写入输出文件。

尝试更像这样的东西:

常见:

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");

服务器:

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

客户端:

class Form extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {
      someCheckboxState: false,
    }
  }
  render() {
    return (
      <input onChange={this.handleChange} checked={this.state.someCheckboxState} />
    );
  }
  handleChange(event) {
    this.setState({
      someCheckboxState: event.target.checked,
    });
  }
}