文件传输服务器/客户端使用插座 [英] File transfer server/client using socket

查看:126
本文介绍了文件传输服务器/客户端使用插座的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使服务器和客户端之间的文件传输,但工作非常糟糕。基本上需要采取什么措施是:结果
1)客户端发送一个txt文件到服务器(我把它叫做quotidiani.txt)结果
2)服务器在另一个txt文件(receive.txt)结果,将其保存
3)服务器上运行一个脚本来修改它,并用另一个名称(output.txt的),结果将其保存
4)服务器上的文件的名称(final.txt)

发回给保存它(在同一插座上的客户端)

的问题是,所述第一文件(quotidiani.txt)被读取只是一小部分,然后有一些错误。我希望有人来帮助我了解和纠正我的错误。

下面是我的code:

client.c:

 的#include<&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&errno.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&; netinet / in.h中>
#包括LT&; SYS / wait.h>
#包括LT&; SYS / socket.h中>
#包括LT&;&signal.h中GT;
#包括LT&;&文件ctype.h GT;
#包括LT&; ARPA / inet.h>
#包括LT&;&netdb.h中GT;#定义端口20000
#定义长度为512
无效错误(为const char * MSG)
{
    PERROR(MSG);
    出口(1);
}INT主(INT ARGC,CHAR *的argv [])
{
    / *变量定义* /
    INT的sockfd;
    INT nsockfd;
    焦炭revbuf [长度]
    结构SOCKADDR_IN REMOTE_ADDR;    / *获取套接字文件描述符* /
    如果((的sockfd =插座(AF_INET,SOCK_STREAM,0))== -1)
    {
        fprintf中(标准错误,错误:未能获得socket描述符(错误=%d)\\ n,错误号);
        出口(1);
    }    / *填充套接字地址结构* /
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(PORT);
    inet_pton(AF_INET,127.0.0.1,&安培; remote_addr.sin_addr);
    bzero(及(remote_addr.sin_zero),8);    / *尝试远程连接* /
    如果(连接(的sockfd,(结构sockaddr *)及REMOTE_ADDR,的sizeof(结构sockaddr))== -1)
    {
        fprintf中(标准错误,错误:无法连接到主机(错误号=%d)\\ n!,错误号);
        出口(1);
    }
    其他
        的printf([客户]端口%d的连接到服务器... OK \\ n!,PORT);    / *发送文件到服务器* /
    //如果(!fork()的)
    // {
        字符* fs_name =/home/aryan/Desktop/quotidiani.txt;
        烧焦sdbuf [长度]
        的printf([客户]发送%s到服务器...,fs_name);
        FILE * FS = FOPEN(fs_name,R);
        如果(FS == NULL)
        {
            的printf(错误:文件%s没有找到\\ n,fs_name);
            出口(1);
        }        bzero(sdbuf,长度);
        INT fs_block_sz;
        而((fs_block_sz = FREAD(sdbuf,sizeof的(炭),长度,FS))0)
        {
            如果(发送(的sockfd,sdbuf,fs_block_sz,0)℃下)
            {
                fprintf中(标准错误,错误:无法发送文件%s(错误=%d)\\ n,fs_name,错误号);
                打破;
            }
            bzero(sdbuf,长度);
        }
        的printf(OK文件%s从客户端发送\\ n!,fs_name);
    //}    / *从服务器接收文件* /
    的printf([客户] Receiveing​​从服务器上的文件并将其保存为final.txt ......);
    字符* fr_name =/home/aryan/Desktop/progetto/final.txt;
    FILE * FR =的fopen(fr_name,一个);
    如果(FR == NULL)
        的printf(文件%s不能打开\\ n,fr_name);
    其他
    {
        bzero(revbuf,长度);
        INT fr_block_sz = 0;
        而((fr_block_sz =的recv(的sockfd,revbuf,长度,0))0)
        {
            INT write_sz = FWRITE(revbuf,sizeof的(炭),fr_block_sz,FR);
            如果(write_sz< fr_block_sz)
            {
                错误(文件写入失败\\ n);
            }
            bzero(revbuf,长度);
            如果(fr_block_sz == 0 || fr_block_sz!= 512)
            {
                打破;
            }
        }
        如果(fr_block_sz℃,)
        {
            如果(错误== EAGAIN)
            {
                输出(的recv()超时\\ n);
            }
            其他
            {
                fprintf中(标准错误的recv()失败,原因是错误号=%d个\\ N,错误号);
            }
        }
        的printf(OK从服务器接收\\ n!);
        FCLOSE(FR);
    }
    接近(的sockfd);
    的printf([客户]连接丢失\\ n);
    返回(0);
}

server.c

 的#include<&stdlib.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&errno.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&; netinet / in.h中>
#包括LT&; SYS / wait.h>
#包括LT&; SYS / socket.h中>
#包括LT&;&signal.h中GT;
#包括LT&;&文件ctype.h GT;
#包括LT&; ARPA / inet.h>
#包括LT&;&netdb.h中GT;#定义端口20000
#定义5积压
#定义长度为512无效错误(为const char * MSG)
{
    PERROR(MSG);
    出口(1);
}诠释的main()
{
    / *定义变量* /
    INT的sockfd;
    INT nsockfd;
    INT NUM;
    INT sin_size;
    结构SOCKADDR_IN addr_local; / *客户地址* /
    结构SOCKADDR_IN addr_remote; / *服务器地址* /
    焦炭revbuf [长度] //接收缓冲区    / *获取套接字文件描述符* /
    如果((的sockfd =插座(AF_INET,SOCK_STREAM,0))== -1)
    {
        fprintf中(标准错误,错误:未能获得socket描述符(错误=%d)\\ n,错误号);
        出口(1);
    }
    其他
        的printf([服务器]获得socket描述成功\\ n);    / *填充客户端套接字地址结构* /
    addr_local.sin_family = AF_INET; //协议族
    addr_local.sin_port = htons(PORT); //端口号
    addr_local.sin_addr.s_addr = INADDR_ANY; //自动填充本地地址
    bzero(及(addr_local.sin_zero),8); //冲洗结构的其余部分    / *绑定一个特殊的端口* /
    如果(绑定(的sockfd,(结构sockaddr *)及addr_local,的sizeof(结构sockaddr))== -1)
    {
        fprintf中(标准错误,错误:未能绑定端口(错误=%d)\\ n,错误号);
        出口(1);
    }
    其他
        的printf([服务器]绑定的TCP端口%d在地址127.0.0.1成功地\\ n,PORT);    / *听远程连接/调用* /
    如果(听(的sockfd,积压)== -1)
    {
        fprintf中(标准错误,错误:无法监听端口(错误=%d)\\ n,错误号);
        出口(1);
    }
    其他
        的printf([服务器]侦听的端口%成功Ð\\ n,PORT);    INT成功= 0;
    而(成功== 0)
    {
        sin_size = sizeof的(结构SOCKADDR_IN);        / *等待连接,并获取新的套接字文件despriptor单连接* /
        如果((nsockfd =接受(的sockfd,(结构sockaddr *)及addr_remote,&安培; sin_size))== -1)
        {
            fprintf中(标准错误,错误:获得新的Socket Despcritor(错误=%d)\\ n,错误号);
            出口(1);
        }
        其他
            的printf([服务器]服务器已经得到了来自%s的连接\\ n,INET_NTOA(addr_remote.sin_addr));        / *从客户端接收文件* /
        字符* fr_name =/home/aryan/Desktop/receive.txt;
        FILE * FR =的fopen(fr_name,一个);
        如果(FR == NULL)
            的printf(文件%s无法在服务器打开的文件\\ n,fr_name);
        其他
        {
            bzero(revbuf,长度);
            INT fr_block_sz = 0;
            而((fr_block_sz =的recv(nsockfd,revbuf,长度,0))0)
            {
                INT write_sz = FWRITE(revbuf,sizeof的(炭),fr_block_sz,FR);
                如果(write_sz< fr_block_sz)
                {
                    错误(文件写入服务器上失败\\ n);
                }
                bzero(revbuf,长度);
                如果(fr_block_sz == 0 || fr_block_sz!= 512)
                {
                    打破;
                }
            }
            如果(fr_block_sz℃,)
            {
                如果(错误== EAGAIN)
                {
                    输出(的recv()超时\\ n);
                }
                其他
                {
                    fprintf中(标准错误的recv()失败,原因是错误号=%d个\\ N,错误号);
                    出口(1);
                }
            }
            的printf(OK从客户收到\\ n!);
            FCLOSE(FR);
        }        / *调用脚本* /
        系统(CD;搭配chmod + X script.sh; ./script.sh);        / *发送文件到客户端* /
        //如果(!fork()的)
        // {
            字符* fs_name =/home/aryan/Desktop/output.txt;
            烧焦sdbuf [长度] //发送缓冲区
            的printf([服务器]发送%s到客户端...,fs_name);
            FILE * FS = FOPEN(fs_name,R);
            如果(FS == NULL)
            {
                fprintf中(标准错误,错误:文件%s不在服务器上找到(错误=%d)\\ n,fs_name,错误号);
                出口(1);
            }            bzero(sdbuf,长度);
            INT fs_block_sz;
            而((fs_block_sz = FREAD(sdbuf,sizeof的(炭),长度,FS))0)
            {
                如果(发送(nsockfd,sdbuf,fs_block_sz,0)℃下)
                {
                    fprintf中(标准错误,错误:无法发送文件%s(错误=%d)\\ n,fs_name,错误号);
                    出口(1);
                }
                bzero(sdbuf,长度);
            }
            的printf(OK发送到客户端\\ n!);
            成功= 1;
            关闭(nsockfd);
            的printf([服务器]与客户端连接服务器关闭现在稍候... \\ n);
            而(waitpid函数(-1,NULL,WNOHANG)大于0);
        //}
    }
}


解决方案

在没有特定的顺序一些评论:


  • 你往往向上传递的机会,要知道确切的错误:

     如果(听(的sockfd,积压)== -1)
    {
        的printf(错误:无法侦听端口%d个\\ N,PORT);
        返回(0);
    }

    此块绝对应该包括 PERROR(听)或类似的东西。始终包括 PERROR()字符串错误()的时候,错误的详细信息将通过<$报告每个错误处理区块C $ C>错误号。有确切的失败的原因将在编程时节省您的时间和将节省您和您的用户时,时间事情有望在未来不工作。


  • 您的错误处理需要一些进一步规范:

     如果((的sockfd =插座(AF_INET,SOCK_STREAM,0))== -1)
    {
        的printf(错误:无法获得socket描述符\\ n);
        返回(0);
    }

    这应该的返回0 ,因为这将发出信号,告知程序运行完成没有错误的外壳。你应该收益1 (或使用 EXIT_SUCCESS EXIT_FAILURE )信号异常退出。

     其他
        的printf([服务器]服务器已经得到了来自%s的连接\\ n,INET_NTOA(addr_remote.sin_addr)); / *从客户端接收文件* /

    在此preceding块你得到一个错误的条件,但无论如何继续执行。这是一个快速的方法来获取非常不可取的行为。这应该可以重新启动主服务器循环或退出子进程或者类似的东西。 (取决于如果你把多进程的服务器。)

     如果(!fork()的)
    {

    在preceding块忘了占叉()没有的。 叉()就可以了,没有失败 - 尤其是在高校普遍共享托管环境 - 所以你应该ppared为全$ P $,复杂的的从叉可能的返回值():失败,子女,父母


  • 看来你使用叉()乱;您的客户端和服务器都非常简单,它们被设计成运行方式意味着他们的无法的可用于同时服务多个客户端。你或许应该坚持只有一个过程每个,至少要等到算法是完全调试和你找出一些方法来同时运行多个客户端。我希望这是你现在遇到的问题的根源。


  • 您需要使用的功能封装细节;写连接到服务器的功能,一个功能发送的文件,一个功能写文件等写函数来处理复杂部分写入。 (我特别推荐在偷 writen 功能在UNIX环境 href=\"http://www.apuebook.com/\">高级编程本书的源$ C ​​$ C。文件的lib / writen.c )。如果你写的正常运行,你可以在客户端和服务器重新使用它们。 (喜欢的东西放置在 utils.c 和编译像节目的gcc -o服务器server.c utils.c 。)

    拥有更小的功能,每做一件事可以让你在一个时间集中在少量的code的的的写每个小的测试,这将有助于你缩小$的哪些板块C $ç仍然需要改进。


I am trying to make a file transfer between server and client, but is working very badly. Basically what needs to happen is:
1) The client send a txt file to the server (I called it "quotidiani.txt")
2) The server saves it in another txt file ("receive.txt")
3) The server runs a script on it that modifies it and saves it with another name ("output.txt")
4) The server send the file back to the client that saves it (on the same socket) with the name (final.txt)

The problem is that the first file (quotidiani.txt) is read just for a little part, and then there are some errors. I'd like someone to help me understand and correct my errors.

Here's my code:

client.c:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 20000
#define LENGTH 512 


void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    /* Variable Definition */
    int sockfd; 
    int nsockfd;
    char revbuf[LENGTH]; 
    struct sockaddr_in remote_addr;

    /* Get the Socket file descriptor */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
        exit(1);
    }

    /* Fill the socket address struct */
    remote_addr.sin_family = AF_INET; 
    remote_addr.sin_port = htons(PORT); 
    inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); 
    bzero(&(remote_addr.sin_zero), 8);

    /* Try to connect the remote */
    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
        exit(1);
    }
    else 
        printf("[Client] Connected to server at port %d...ok!\n", PORT);

    /* Send File to Server */
    //if(!fork())
    //{
        char* fs_name = "/home/aryan/Desktop/quotidiani.txt";
        char sdbuf[LENGTH]; 
        printf("[Client] Sending %s to the Server... ", fs_name);
        FILE *fs = fopen(fs_name, "r");
        if(fs == NULL)
        {
            printf("ERROR: File %s not found.\n", fs_name);
            exit(1);
        }

        bzero(sdbuf, LENGTH); 
        int fs_block_sz; 
        while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
        {
            if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
            {
                fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
                break;
            }
            bzero(sdbuf, LENGTH);
        }
        printf("Ok File %s from Client was Sent!\n", fs_name);
    //}

    /* Receive File from Server */
    printf("[Client] Receiveing file from Server and saving it as final.txt...");
    char* fr_name = "/home/aryan/Desktop/progetto/final.txt";
    FILE *fr = fopen(fr_name, "a");
    if(fr == NULL)
        printf("File %s Cannot be opened.\n", fr_name);
    else
    {
        bzero(revbuf, LENGTH); 
        int fr_block_sz = 0;
        while((fr_block_sz = recv(sockfd, revbuf, LENGTH, 0)) > 0)
        {
            int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
            if(write_sz < fr_block_sz)
            {
                error("File write failed.\n");
            }
            bzero(revbuf, LENGTH);
            if (fr_block_sz == 0 || fr_block_sz != 512) 
            {
                break;
            }
        }
        if(fr_block_sz < 0)
        {
            if (errno == EAGAIN)
            {
                printf("recv() timed out.\n");
            }
            else
            {
                fprintf(stderr, "recv() failed due to errno = %d\n", errno);
            }
        }
        printf("Ok received from server!\n");
        fclose(fr);
    }
    close (sockfd);
    printf("[Client] Connection lost.\n");
    return (0);
}

server.c

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>          
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 20000 
#define BACKLOG 5
#define LENGTH 512 

void error(const char *msg)
{
    perror(msg);
    exit(1);
}

int main ()
{
    /* Defining Variables */
    int sockfd; 
    int nsockfd; 
    int num;
    int sin_size; 
    struct sockaddr_in addr_local; /* client addr */
    struct sockaddr_in addr_remote; /* server addr */
    char revbuf[LENGTH]; // Receiver buffer

    /* Get the Socket file descriptor */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
    {
        fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor. (errno = %d)\n", errno);
        exit(1);
    }
    else 
        printf("[Server] Obtaining socket descriptor successfully.\n");

    /* Fill the client socket address struct */
    addr_local.sin_family = AF_INET; // Protocol Family
    addr_local.sin_port = htons(PORT); // Port number
    addr_local.sin_addr.s_addr = INADDR_ANY; // AutoFill local address
    bzero(&(addr_local.sin_zero), 8); // Flush the rest of struct

    /* Bind a special Port */
    if( bind(sockfd, (struct sockaddr*)&addr_local, sizeof(struct sockaddr)) == -1 )
    {
        fprintf(stderr, "ERROR: Failed to bind Port. (errno = %d)\n", errno);
        exit(1);
    }
    else 
        printf("[Server] Binded tcp port %d in addr 127.0.0.1 sucessfully.\n",PORT);

    /* Listen remote connect/calling */
    if(listen(sockfd,BACKLOG) == -1)
    {
        fprintf(stderr, "ERROR: Failed to listen Port. (errno = %d)\n", errno);
        exit(1);
    }
    else
        printf ("[Server] Listening the port %d successfully.\n", PORT);

    int success = 0;
    while(success == 0)
    {
        sin_size = sizeof(struct sockaddr_in);

        /* Wait a connection, and obtain a new socket file despriptor for single connection */
        if ((nsockfd = accept(sockfd, (struct sockaddr *)&addr_remote, &sin_size)) == -1) 
        {
            fprintf(stderr, "ERROR: Obtaining new Socket Despcritor. (errno = %d)\n", errno);
            exit(1);
        }
        else 
            printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));

        /*Receive File from Client */
        char* fr_name = "/home/aryan/Desktop/receive.txt";
        FILE *fr = fopen(fr_name, "a");
        if(fr == NULL)
            printf("File %s Cannot be opened file on server.\n", fr_name);
        else
        {
            bzero(revbuf, LENGTH); 
            int fr_block_sz = 0;
            while((fr_block_sz = recv(nsockfd, revbuf, LENGTH, 0)) > 0) 
            {
                int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr);
                if(write_sz < fr_block_sz)
                {
                    error("File write failed on server.\n");
                }
                bzero(revbuf, LENGTH);
                if (fr_block_sz == 0 || fr_block_sz != 512) 
                {
                    break;
                }
            }
            if(fr_block_sz < 0)
            {
                if (errno == EAGAIN)
                {
                    printf("recv() timed out.\n");
                }
                else
                {
                    fprintf(stderr, "recv() failed due to errno = %d\n", errno);
                    exit(1);
                }
            }
            printf("Ok received from client!\n");
            fclose(fr); 
        }

        /* Call the Script */
        system("cd ; chmod +x script.sh ; ./script.sh");

        /* Send File to Client */
        //if(!fork())
        //{
            char* fs_name = "/home/aryan/Desktop/output.txt";
            char sdbuf[LENGTH]; // Send buffer
            printf("[Server] Sending %s to the Client...", fs_name);
            FILE *fs = fopen(fs_name, "r");
            if(fs == NULL)
            {
                fprintf(stderr, "ERROR: File %s not found on server. (errno = %d)\n", fs_name, errno);
                exit(1);
            }

            bzero(sdbuf, LENGTH); 
            int fs_block_sz; 
            while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs))>0)
            {
                if(send(nsockfd, sdbuf, fs_block_sz, 0) < 0)
                {
                    fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
                    exit(1);
                }
                bzero(sdbuf, LENGTH);
            }
            printf("Ok sent to client!\n");
            success = 1;
            close(nsockfd);
            printf("[Server] Connection with Client closed. Server will wait now...\n");
            while(waitpid(-1, NULL, WNOHANG) > 0);
        //}
    }
}

解决方案

Some comments in no particular order:

  • You're passing up the opportunity to know exact errors too often:

    if(listen(sockfd,BACKLOG) == -1)
    {
        printf("ERROR: Failed to listen Port %d.\n", PORT);
        return (0);
    }
    

    This block should definitely include a perror("listen") or something similar. Always include perror() or strerror() in every error handling block when the error details will be reported via errno. Having exact failure reasons will save you hours when programming and will save you and your users hours when things don't work as expected in the future.

  • Your error handling needs some further standardizing:

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
    {
        printf("ERROR: Failed to obtain Socket Descriptor.\n");
        return (0);
    }
    

    This should not return 0 because that will signal to the shell that the program ran to completion without error. You should return 1 (or use EXIT_SUCCESS and EXIT_FAILURE) to signal an abnormal exit.

     else 
        printf("[Server] Server has got connected from %s.\n", inet_ntoa(addr_remote.sin_addr));
    
     /*Receive File from Client */
    

    In this preceding block you've gotten an error condition but continue executing anyway. That's a quick way to get very undesirable behavior. This should either re-start the main server loop or exit the child process or something similar. (Depends if you keep the multi-process server.)

    if(!fork())
    {
    

    The preceding block forgot to account for fork() failing. fork() can, and does fail -- especially in shared hosting environments common at universities -- so you should be prepared for the full, complicated three possible return values from fork(): failure, child, parent.

  • It appears you're using fork() indiscriminately; your client and server are both very simple and the way they are designed to run means they cannot be used to service multiple clients simultaneously. You should probably stick to exactly one process for each, at least until the algorithm is perfectly debugged and you figure out some way to run multiple clients simultaneously. I expect this is the source of the problem you're encountering now.

  • You need to use functions to encapsulate details; write a function to connect to the server, a function to send the file, a function to write the file, etc. Write a function to handle the complicated partial writes. (I especially recommend stealing the writen function from the Advanced Programming in the Unix Environment book's source code. File lib/writen.c.) If you write the functions correctly you can re-use them in both the client and server. (Something like placing them in utils.c and compiling the programs like gcc -o server server.c utils.c.)

    Having smaller functions that each do one thing will allow you to focus on smaller amounts of code at a time and write little tests for each that will help you narrow down which sections of code still need improvement.

这篇关于文件传输服务器/客户端使用插座的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆