c - 使用TCP从服务器下载文件

标签 c linux sockets tcp

我正在尝试为客户端编写C程序,该程序可以使用TCP从服务器下载文件。客户端从服务器接收文件后,将打印并保存文件内容。要编译客户端程序,它需要服务器的IP地址和端口号。我在Linux中实现了它,但是在收到文本后显示0。保存的文本文件是相同的。我不知道如何仅输出文本。接收缓冲区中可能有错误吗?

服务器代码:

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>

#define portnum 12345
#define FILE_SIZE 500 
#define BUFFER_SIZE 1024


void *client_fun(void * fd);

int main()
{
    int new_fd;
    pthread_t thread_id;
    int server_fd=socket(AF_INET,SOCK_STREAM,0);
    if(-1==server_fd)
    {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in server_addr;   
    server_addr.sin_family=AF_INET;   
    server_addr.sin_port=htons(portnum);  
    (server_addr.sin_addr).s_addr=htonl(INADDR_ANY);
    if(-1==bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)))  
    {
        perror("bind");
        close(server_fd);
        exit(6);
    }

    if(-1==listen(server_fd,5)) 
    {
        perror("listen");
        close(server_fd);
        exit(7);
    }

    while(1)
    {
        struct sockaddr_in client_addr;
        int size=sizeof(client_addr);
        new_fd=accept(server_fd,(struct sockaddr *)&client_addr,&size);  

        if(new_fd < 0)
        {
            perror("accept");
            continue;      
        }
        printf("accept client ip锛?s:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);

        //printf("new_fd=%d\n",new_fd);
        if (new_fd > 0)
        {
            pthread_create(&thread_id, NULL, client_fun, (void *)&new_fd);  
            pthread_detach(thread_id);
        }

    }
    close(server_fd);

    return 0;
}

void *client_fun(void *arg)
{
    int new_fd = *((int *)arg);
    int file2_fp;
    int len;


    char buffer[BUFFER_SIZE];
    memset( buffer,0, sizeof(buffer) ); 

    while(1)
    {

        if((len=recv(new_fd, buffer, sizeof(buffer), 0)) <= 0)
        {
            continue;
        }

        char file_name[FILE_SIZE]; 
        memset( file_name,0, sizeof(file_name) );   
        strncpy(file_name, buffer, strlen(buffer)>FILE_SIZE?FILE_SIZE:strlen(buffer)); 
        memset( buffer,0, sizeof(buffer) );
        printf("Client requests file %s\n", file_name); 

        if( strcmp(file_name,"exit")==0 )
        {
           break;
        }


         file2_fp = open(file_name,O_RDONLY,0777); 
         if(file2_fp<0) 
         { 
            printf("File %s Not Found\n", file_name);
            char* err_info = "File not found\n";
            if (write(new_fd, err_info, sizeof(err_info)) < 0)
            {
                printf("Send error information failed\n");
                break;
            }
            continue;
         } 
         else 
         { 
            int length = 0; 
            memset( buffer,0, sizeof(buffer) );

            while( (length = read(file2_fp, buffer, sizeof(buffer))) > 0  )    
            {   
                if( write(new_fd, buffer, length) < 0) 
                { 
                    printf("Send File %s Failed.\n", file_name); 
                    break; 
                } 
                memset( buffer,0, sizeof(buffer) );
            } 

             close(file2_fp); 
             printf("Transfer file %s successfully!\n", file_name);
         }   
    }
    close(new_fd);

}

客户代码:
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>

int main(int argc, char *argv[])
{
    int sockfd = 0;
    char recvBuff[1024];
    char file_name[500];
    char *serverIP=argv[1];
    int portno=atoi(argv[2]);
    printf("IP Addresses: %s   Port Number: %s\n", argv[1], argv[2]);
    memset(recvBuff,'0',sizeof(recvBuff));
    struct sockaddr_in server_addr;
    /* Creat a socket*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    /*Initialize sockaddr_in structure*/
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(portno);
    (server_addr.sin_addr).s_addr=inet_addr(serverIP);
    /*Attempt a connection*/
    printf("Connect status: ");
    if (connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))<0)
    {
        printf("fail\n");
        return 0;
    } 
    printf("success\n");
    /*Request file from server*/
  while(1)
  {
    printf("Input the file name to be requested from the server: ");
    fgets(file_name,500, stdin);
    char *p=strchr(file_name,'\n');
    if (p) *p=0;
    if (send(sockfd, file_name, strlen(file_name), 0)<0) 
    {
        printf("Send failed.\n");
        break;
    }
    printf("Send success.\n");
    if (strcmp(file_name,"exit")==0)
        break;

    int length=0;
    printf("Send status: ");

    if (length=read(sockfd, recvBuff, sizeof(recvBuff))<0)
    {
        printf("fail\n");
        continue;
    }
    else if (strcmp(recvBuff,"File not found\n")==0)
    {
        printf("fail\n");
        continue;
    }
    else
    {    
        printf("success\n");   
        /*Create file where text will be stored*/
        FILE *fp;
        fp=fopen("received_file.txt","w"); 
        printf("Open file status: ");
        if (fp==NULL)
        {
            printf("fail\n");
            continue;
        }


        printf("success\n");
        printf("Received text: ");

        if (fprintf(fp, "%s", recvBuff)<0)
        {
            printf("Save status: fail\n");
            continue;
        }

        fflush(fp);
        printf("%s",recvBuff);

        memset(recvBuff,0,1024);

        while ((length=read(sockfd, recvBuff, sizeof(recvBuff)))>0)
        {
           if (fprintf(fp, "%s", recvBuff)<0)
           { 
               printf("Save status: fail\n");  
               break;         
           }
           fflush(fp);
           printf("%s",recvBuff);
           memset(recvBuff,0,1024); 
        }

        printf("Save status: success");      
    }
  }      
}

另一个问题是,客户端应该一直请求文件,直到发送“退出”为止。但是在收到第一个文件后,它不再要求客户端输入文件名。循环出了什么问题?

最佳答案

你有几个问题。

首先:-比较运算符的优先级高于赋值,因此长度获得FALSE(0)值,而不是接收到的数据的实际数量

if (length=read(sockfd, recvBuff, sizeof(recvBuff))<0)

它应该是:
if ((length=read(sockfd, recvBuff, sizeof(recvBuff)))<0)

秒:您正在使用零终止的字符串进行操作,但是您没有从服务器发送零('\0'),并且客户端未在数据块的末尾设置它。
因此,您需要在此处在客户端显式设置它
if ((length=read(sockfd, recvBuff, sizeof(recvBuff)))<0)
{
    printf("fail\n");
    continue;
}
else if (strcmp(recvBuff,"File not found\n")==0)
{
    printf("fail\n");
    continue;
}
else
{    
   recvBuff[length]='\0';

和这里:
while ((length=read(sockfd, recvBuff, sizeof(recvBuff)))>0){
  recvBuff[length]='\0';

关于c - 使用TCP从服务器下载文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58957234/

相关文章:

linux - 查找包含在名为的目录中的所有文件

linux - 如何知道nc使用的源ip地址连接到目的地

node.js - 当服务器向特定客户端发出事件(不同的 Angular2 服务)时,不要将 socket.io-client 与 Angular2 一起使用

c - 为什么运行此代码时 cmd 会崩溃?

c - 良好的轻量级C或C++主从网络库

c++ - 确定字符中设置位的数量

python - 在 Windows 路径上使用 os.path.dirname

c - 多客户端 C 服务器的异步 C 客户端

python - 多个客户端的套接字编程

c++ - C/C++ Paypal 集成