1

TCP プロトコルを使用してサーバーからクライアントにファイルを転送しようとしています。ファイルのサイズ全体をなんとか送信できましたが、クライアントがファイルを作成すると、開くことができません。この場合、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

1 つの問題は、31800 が 300 よりもはるかに大きいため、サーバーの配列に を追加するdataと、ptr2バッファー オーバーランが発生することです。write()で「ヘッダー」を送信した後、別の呼び出しでデータを送信しないことで修正できますptr2。あなたのwrite()ループは永遠にループするように見えますが、すべてのコードを表示していないと思います。

受信側では、ヘッダーを解析してヘッダーをデータから分離しようとする試みは見られません。最大 128 バイトを読み取るため、その読み取りはファイルのヘッダーと一部のデータの両方を受信した可能性があり、ファイルのその部分を検出して保存しようとはしません。

ファイル転送アプリケーションをデバッグするときは、結果のファイルを視覚的に確認できるようにテキスト ファイルから開始しdiff、実際のファイルと一緒に保存したファイルに対して簡単なテストを実行して、違いがあるかどうかを確認します。

于 2013-10-05T16:50:38.857 に答える