c - 通过 TCP 发送的文件创建类型为 : application/octet-stream

标签 c file tcp

我正在尝试使用 TCP 协议(protocol)将文件从服务器传输到客户端。 我设法发送文件的整个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 ??????”哪个 ???我认为是文件的数据。

问题是创建的"file"无法打开。帮忙?

最佳答案

一个问题是 31800 比 300 大得多,因此当您将 data 附加到服务器中的 ptr2 数组时,就会出现缓冲区溢出。您可以通过在 ptr2 中发送“ header ”后不使用单独的 write() 调用发送数据来纠正此问题。您的 write() 循环看起来会永远循环,但我猜您没有显示所有代码。

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

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

关于c - 通过 TCP 发送的文件创建类型为 : application/octet-stream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19200108/

相关文章:

java - 多个数据输入/输出流混淆

windows-7 - 捕获和重定向来自给定 ip :port to target ip:port 的传出流量

networking - TCP 慢启动术语混淆

c - 从 i386 移动到 x86_64 时的浮点精度

如果文件已经存在(在写入模式下),fopen 会失败吗?

java - 从文件读取时出现 ArrayIndexOutOfBoundsException

c - 如何使用 FILE* 作为其 stdin、stdout 或 stderr 创建子进程?

mysql_real_escape_string() 导致段错误

c++ - C 字符串 : Simple Question

delphi - TidHttp 文件下载引发内存不足异常