在 c 套接字中,为什么我的服务器无法接收全部内容?



我是这个领域的新手,并编写一个服务器和客户端,但它真的令人困惑,我不能得到所有的内容,但一些小剪辑。我的服务器代码:

        read(connfd, name, 20);
        //recv(connfd,name,1024,0);
        char* a=name;
        while(a[0]!='n'){
            a++;
        }
        a[0]='';
        printf("name:%sn", name);
        read(connfd, size, 20);
        printf("size:%sn", size);
        recv(connfd,buf,8192,0);
        printf("buf:%sn", 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="OKn";
        write(connfd, res, 1024);
        }
        fclose(stream);

和我的客户端代码是:

char buffer[8192];
bzero(buffer,8192);
char * put="PUTn";
if ((write(fd, put, 8192)) <= 0) {
    if (errno != EINTR) {
        fprintf(stderr, "Write error: %sn", 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 Failedn");
        break;
    }
    bzero(buffer, 8192);
}

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

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

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

发送文件时,lengsize接收实际从文件中读取的字节数。当lengsize为<8192(如果文件大小不是8192的偶数倍,通常是文件的最后一个块)。

但更重要的是,虽然客户端告诉服务器文件大小,但服务器会忽略它,以知道何时停止读取。服务器还忽略了recv()的返回值,以了解实际接收了多少字节,从而知道可以安全地将多少字节写入输出文件。

试试这样写:

共同

:

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] = '';
    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:%sn", name);
int32_t filesize;
if (readInt32(connfd, &filesize) <= 0) {
    // error handling ...
    free(name);
    sendStr(connfd, "Socket read error");
    return;
}
printf("size:%dn", 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:%.*sn", 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 Failedn");
        // error handling ...
        close(stream);
        exit(0);
    }
    if (sendData(fd, buffer, lengsize) <= 0) {
        printf("Send File Failedn");
        // 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 OKn");
else
    printf("Send File Failed: %sn", resp);
free(resp);

相关内容

最新更新