使用文件指针通过TCP传输文件的问题

时间:2011-02-12 14:05:27

标签: c++ unix network-programming

我需要通过TCP传输8.3MB的文件,当我使用文件指针读取和写入文件然后我发送大约8.6MB数据,并通过计算发送和recv调用的输出也接收8.6 MB的数据我的文件大小是8.3 MB,进一步当我通过查看其属性单独检查文件的大小然后它是大约3-5 MB(每次传输不同)但当我使用文件描述符代替文件指针然后我发送和recv正好8.3 MB的数据和文件属性大小也显示8.3 MB。那么使用文件指针有什么问题?为什么在文件描述符的情况下它被删除....但如果我使用文件描述符,那么我无法读取我发送的文本文件。文本编辑器在文件中显示一些二进制数据。我没有得到一些正在发生的事情......请提前帮助和感谢

server.cpp

#include "server.h"
void server()
{
    int fd = open("out.txt",O_WRONLY);
    struct sockaddr_in sin;
    socklen_t addr_size;
    char buf[MAX_LINE];
    int len;
    int s, new_s;
    /* build address data structure */
    bzero((char *) & sin, sizeof (sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(SERVER_PORT);
    printf("File Descriptor : %d", fd);
    /* setup passive open */
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("simplex-talk: socket");
        exit(1);
    }
    if ((bind(s, (struct sockaddr *) & sin, sizeof (sin))) < 0)
    {
        perror("simplex-talk: bind");
        exit(1);
    }
    listen(s, MAX_PENDING);
    // wait for connection, then receive and print text */
    while (1) 
    {
        if ((new_s = accept(s, (struct sockaddr *) & sin, &addr_size)) < 0)
        {
            perror("simplex-talk: accept");
            exit(1);
        }
        float total = 0;
        printf("File Descriptor : %d", fd);
        while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
        {
            buf[len] = 0;
            total = total+len;
            //write(stdout, buf, len);
            write(fd, buf, len);
            //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
        }
        printf("File Descriptor : %d", fd);
        close(new_s);
    }
}

client.cpp

#include "client.h"
void client(int argc, char** argv)
{
    int fd = open("/home/nikku/Desktop/data.txt",O_RDONLY);
    if (fd < 0 ) perror("File not opened\n");
    struct hostent *hp;
    struct sockaddr_in sin;
    char *host;
    char buf[MAX_LINE];
    int s;
    int len;
    host = argv[1];
    if (argc == 2)
    {
        host = argv[1];
    }
    else
    {
        fprintf(stderr, "usage: simplex-talk host\n");
        exit(1);
    }
    /* translate host name into peer’s IP address */
    gethostname(host,20);
    printf("%s\n",host);
    hp = gethostbyname(host);
    if (!hp)
    {
        fprintf(stderr, "simplex-talk: unknown host: %s\n", host);
        exit(1);
    }
    /* build address data structure */
    bzero((char *) & sin, sizeof (sin));
    sin.sin_family = AF_INET;
    bcopy(hp->h_addr, (char *) & sin.sin_addr, hp->h_length);
    sin.sin_port = htons(SERVER_PORT);
    /* active open */
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("simplex-talk: socket");
        exit(1);
    }
    if (connect(s, (struct sockaddr *) & sin, sizeof (sin)) < 0)
    {
        perror("simplex-talk: connect");
        close(s);
        exit(1);
    }
    printf("Connection Succeeded\n");
    /* main loop: get and send lines of text */
    float total = 0;
    while (read(fd, buf, MAX_LINE))
    {
        //usleep(1000);;
        len = strlen(buf) + 1;
        total += send(s, buf, len, 0);
        //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
    }
    send(s, "close", 6, 0);
    close(fd);
}

如果我用指针替换文件描述符的使用并使用fgets和fputs进行读写,那么我的文件传输就不能正常进行。但如果我使用文件描述符,那么我无法读取我发送的文本文件。文本编辑器在文件中显示一些二进制数据。

1 个答案:

答案 0 :(得分:1)

while (read(fd, buf, MAX_LINE))
{
    //usleep(1000);;
    len = strlen(buf) + 1;
    total += send(s, buf, len, 0);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}

此处存在问题,您无法保证read将读取零字节,因此strlen(buf)可能存在危险。另请注意,当您将len设置为strlen(buf) + 1时,如果您对零字节进行了输入,则会通过套接字发送它,但如果您没有读取零字节,strlen将会读取超出数组末尾并在套接字上发送“垃圾”。

存储read的返回值是明智的,这样您就可以知道实际从fd读取了多少字节。

while (len = recv(new_s, buf, MAX_LINE, 0) && strcmp(buf,"close"))
{
    buf[len] = 0;
    total = total+len;
    //write(stdout, buf, len);
    write(fd, buf, len);
    //printf("%fKB and %fMB\n",total/1024, total/(1024*1024));
}

您的接收方似乎假设每次调用recv都不会包含零字节,因为您手动终止缓冲区为0.请注意,如果实际recv实际上没有空间可以执行此操作收到MAX_LINE个字节,因为buf只包含MAX_LINE个元素。由于您的写入在任何情况下都受到长度限制,因此无需执行buf[len] = 0;