1

我正在尝试使用 TCP 协议将文件从服务器传输到客户端。我设法发送文件的整个 syze,但是当客户端创建文件时,它无法打开。在这种情况下,我发送一个 jpg 文件。

下面是 server.c 的代码:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 59000

int main(int argc,char *argv[]) {
int port, fd, newfd, n, nw, addrlen;
int port_was_given = 0;
char buffer[128], *ptr, *topic, *data;
size_t result;
struct hostent *h;
struct sockaddr_in addr;
FILE *send;

if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)exit(1); //error
memset((void*)&addr,(int)'\0',sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);

if (argc == 3) {
    port = atoi(argv[2]);
    port_was_given = 1;
}
    
if(port_was_given == 1) 
    addr.sin_port=htons((u_short)port);
else 
    addr.sin_port=htons((u_short)PORT);

if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)exit(1); //error

if(listen(fd,5)==-1)exit(1); //error

    while(1) {
        addrlen=sizeof(addr);
        if((newfd=accept(fd,(struct sockaddr*)&addr,&addrlen))==-1)exit(1); //erro
        h=gethostbyaddr((char*)&addr.sin_addr,sizeof(struct in_addr),AF_INET);
    
        while((n=read(newfd,buffer,128))!=0) {
            if(n==-1)exit(1);

        topic = strtok(buffer," ");
        topic = strtok(NULL," ");

        if (strcmp(topic, "Nacional\n")==0) {
            send = fopen("flag","r");
            fseek(send, 0L, SEEK_END); //vai ate ao fim do ficheiro
            int sz = ftell(send); //size of file
            fseek(send,0L,SEEK_SET);
            //rewind(send);
            data = (char*)malloc(sizeof(char)*sz);
            result = fread(data,1,sz,send);
            //fseek(send,0L,SEEK_SET);
            fclose(send);
            char ptr2[300] = "REP ok ";
            char *ptrInt; //for s -> int
            sprintf(ptrInt, "%d", sz);
            strcat(ptr2, ptrInt);
            strcat(ptr2, " ");
            strcat(ptr2, data);
            strcat(ptr2, "\n");
            while(n>0) {
                nw=write(newfd,ptr2,n); //write n bytes on each cycle
            }

        }
            
        }
            
        
            
        close(newfd);
    }
    close(fd);
    exit(0);
}

好的,逻辑是:客户端请求一种内容,在这种情况下,内容是“Nacional”,因此服务器必须将“flag.jpg”发送给客户端。服务器的答案有以下类型:

REP 状态大小数据

其中状态可以是“ok”或“nok”。如果“nok”,则不发送文件。size 是数据的大小。data 是文件本身的数据。

现在client.c:

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

#define PORT 58000
#define NG 10
  
int main (int argc,char *argv[]) 
{

    /** ... variables declarations and other stuff ... */

    fdtcp=socket(AF_INET,SOCK_STREAM,0);
    if (fdtcp==-1) exit(1); // Erro

    inet_aton(ip, &address);  
    
    if (strcmp(lsname, "localhost")==0)
        newHost = gethostbyname("localhost");
    else
        newHost = gethostbyaddr((const void *)&address,sizeof ip,AF_INET);

    newPort = atoi(newport);  
        
    memset((void*)&addrtcp,(int)'\0',sizeof(addrtcp));  
    addrtcp.sin_family=AF_INET;     
    addrtcp.sin_addr.s_addr=((struct in_addr *)(newHost->h_addr_list[0]))->s_addr;  
    addrtcp.sin_port=htons((u_short)newPort);
        
    k = connect(fdtcp,(struct sockaddr*)&addrtcp,sizeof(addrtcp));
    if (k==-1) exit(1); // Erro
    
    // REQ Tn (Conteudo Solicitado)
    ptr = strcat(reqdata, tn);
    ptr = strcat(reqdata, "\n");

    // Envia-se o Comando REQ
    nreqleft = 25;
    while(nreqleft>0) {
        kwrite=write(fdtcp,ptr,nreqleft); 
        if (kwrite<=0) exit(1); // Erro
        nreqleft -= kwrite;
        ptr += kwrite;
    }

    // Recebe-se o Comando REP
    nreqleft = 128;
    ptr = &buffertcp[0];
    kread=read(fdtcp,ptr,nreqleft);
    if (kread==-1) exit(1); // Erro
    cmd = strtok(buffertcp, " ");   // REP
    cmd = strtok(NULL, " ");    // Status
    if(strcmp(cmd,"ok")) {
        printf("ERR\n");
        exit(1); // Erro
    }
    cmd = strtok(NULL, " ");    // Size
    size = atoi(cmd);
    // Recebem-se os Dados do Conteúdo Desejado
    nreqleft = size;
    char data[size];
    ptr = &data[0];
    while(nreqleft>0) {
        kread=read(fdtcp,ptr,nreqleft);
        if (kread==-1) exit(1); // Erro
        nreqleft -= kread;
        ptr += kread;
    }

    file = fopen("file","w");
    fwrite(data, 1, size, file);
    fclose(file);
    
    close(fdtcp); 

    // ---------------------------------------------------  //

    exit(0);
}

“其他东西”部分只是变量声明和与另一台服务器的 UDP 连接,与这部分无关,所以我 100% 确定它不会影响这部分。事实上,在 client.c 上,如果我放置从服务器接收到的消息的 printf,它将显示“REP ok 31800 ?????” 哪个 ???我假设将是文件的数据。

问题是创建的“文件”无法打开。帮助?

4

1 回答 1

0

一个问题是 31800 比 300 大得多,因此当您将 附加dataptr2服务器中的阵列时,缓冲区溢出。您可以通过write()在将“标头”发送到ptr2. 您的write()循环看起来会永远循环,但我猜您并没有显示所有代码。

在接收器中,我没有看到任何尝试解析标头以将标头与数据分开。由于您最多读取 128 个字节,因此该读取可能已接收到文件的标题和一些数据,并且您没有尝试检测和保存文件的该部分。

在调试文件传输应用程序时,我会从文本文件开始,以便您可以直观地看到生成的文件,然后diff对您保存的文件与实际文件运行一个简单的文件,看看是否有差异。

于 2013-10-05T16:50:38.857 回答