C++ HTTP 服务器文件下载器与 Ajax 上传器问题

问题描述 投票:0回答:1

出于某些原因和教育目的,我从头开始开发了一个 C++ HTTP 服务器,它应该使用处理动态请求的 AJAX 从 HTML 页面捕获文件上传,并将其保存在服务器程序所在的同一目录中。

服务器对于 .txt 文件运行良好。文件上传并保存在服务器目录中,没有任何缺陷。一切仍然完美,但当我尝试上传可执行文件、视频文件、音乐文件等二进制文件时,问题就开始了。基本上,服务器可以正常处理 .txt 文件,而不是其他文件。每当上传二进制文件时,服务器端的输出文件都会以某种方式损坏。

我知道有用于这些操作的 PHP 和 NodeJS 框架,但实际上我将在裸机控制器服务器上部署这个项目,该服务器的资源非常有限,无法承受复杂的框架。所以使用scratch的C++服务器似乎是实现我的目标的唯一方法。尽管我无法直接将此代码移植到控制器中,但过程保持不变。要第一手了解该过程,我必须使用 Windows Sockets 在 Windows 上进行一些实验。

这是我迄今为止尝试过的,

C++ HTTP 服务器代码。

#include <stdio.h>
#include <math.h>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <winsock2.h>
#include <windows.h>


#define PORT 12345


WSADATA ws;

char Command[8888];

char FILEDATA[(2 * 1024)];  // FILE HEADER and BUFFER
SOCKET soc, acpt;
FILE *f ;




unsigned long long FileSize(char * direc){
    
    unsigned long long size = 0;
    
    FILE *fsize = fopen(direc,"rb");
    
    fseek(fsize,0,SEEK_END);
    size = _ftelli64(fsize);
    fseek(fsize,0,SEEK_SET);
    
    fclose(fsize);
    
    return size;
    
}
        


void Serve(){
    
    
    int optval = 1;
    int RecvBytes=0;
    
    sockaddr_in addr, peerAddr;
    struct timeval RequestTimeout = {0,5000000} , DownloadTimeout= {0,500000};
    char URL[4000]={0};
    char FileName[260]={0};
    
    
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    
    fd_set rfd;
    FD_ZERO(&rfd);
    
    
    soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    setsockopt(soc,SOL_SOCKET,SO_REUSEADDR,(const char*)&optval,sizeof(optval));
    
    bind(soc,(sockaddr*)&addr,sizeof(addr));
    listen(soc,100);
    
    
    
    
    acpt = accept(soc,NULL,NULL);
    
    FD_SET(acpt,&rfd);
    
    int connstat = select(acpt+1,&rfd,NULL,NULL,&RequestTimeout); // act only if a stable reading can be performed
    
    if(connstat){
    
        int x = 0;
        RecvBytes = recv(acpt,Command,sizeof(Command),0);     // Receives HTTP header
    
        RecvBytes = recv(acpt,FILEDATA,sizeof(FILEDATA),0);     // Receives File headers and content
        
        char * namePtr = strstr(FILEDATA,"\r\n\r\n");
        namePtr = strstr(FILEDATA,"filename=\"") + strlen("filename  "); // Extraction of File Name begins here
        
        while(namePtr[x]!='"'){
            x++;
        }
        
        strncpy(FileName,namePtr,x);              // Extraction of file name ends here.
        
        printf("NAME: %s\n\n",FileName);
        
        int NumberOfBytes = (&strstr(FILEDATA,"\r\n\r\n")[0]+2 - &FILEDATA[0])+2;
        
        f = fopen(FileName,"wb");             // Open file for writing
        
        
        fwrite(strstr(FILEDATA,"\r\n\r\n")+3,1,RecvBytes - NumberOfBytes ,f);   // Received Number of Bytes - Number of Bytes Till Header
        
        
        while(select(acpt+1,&rfd,NULL,NULL,&DownloadTimeout)){    // Keep reading if more data remains available
            RecvBytes = recv(acpt,FILEDATA,sizeof(FILEDATA),0);   // receive
            if(RecvBytes==0){                                     
                break;
            }
            fwrite(FILEDATA,1,RecvBytes,f);
        }
        
    }
    
    
    
    fclose(f);
    
    
    unsigned long long truncFile = FileSize(FileName) - 45;
    
    f = fopen(FileName,"r+");                     // truncating file to remove the webkit boundary substring at the end of the file.
    ftruncate(fileno(f),truncFile);
    fclose(f);
    
    printf("OUTPUT FILE SIZE: %llu\n\n",FileSize(FileName));
    
    MessageBeep(MB_ICONERROR); // A beep means operation is complete
    
    
    shutdown(acpt,2);
    closesocket(acpt);
    
    closesocket(soc);
    shutdown(soc,2);
    
    acpt = NULL;
    soc = NULL;
    
    memset(FILEDATA,'\0',sizeof(FILEDATA));
    
}
        

int main(){
    
    //printf("%d\n",strlen("------WebKitFormBoundary5BlPHcjSKYuZFzV3--")); 42
    
    WSAStartup(MAKEWORD(2,2),&ws);
    
    while(1){
        Serve();
    }
    
    
    return 0;
}   

现在用于上传的AJAX HTML页面,

<!DOCTYPE html>
<html>

<body>
The content of the body element is displayed in your browser.

<input type="file" id="image-file">
<button onclick="Send()">Send</button>

<script>


function Send(){
    
    let photo = document.getElementById("image-file").files[0];  // file from input
    let req = new XMLHttpRequest();
    let formData = new FormData();

    formData.append("photo", photo);                            
    req.open("POST", 'http://localhost:12345/');
    req.send(formData);
    
}


</script>

</body>

</html>

我想有一个最快的解决方案来解决这个问题。感谢您理解我的担忧,问候...

c++ windows http xmlhttprequest winsock2
1个回答
0
投票

经过一番努力,这些代码终于完美运行了!

C HTTP 服务器下载器

#include <stdio.h>
#include <math.h>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <winsock2.h>
#include <windows.h>


#define PORT 12345


WSADATA ws;

char Command[8888];

char FILEDATA[(16 * 1024 * 1024)];  // FILE HEADER and BUFFER
SOCKET soc, acpt;
FILE *f ;




unsigned long long FileSize(char * direc){
    
    unsigned long long size = 0;
    
    FILE *fsize = fopen(direc,"rb");
    
    fseek(fsize,0,SEEK_END);
    size = _ftelli64(fsize);
    fseek(fsize,0,SEEK_SET);
    
    fclose(fsize);
    
    return size;
    
}
        


void Serve(){
    
    
    int optval = 1;
    int RecvBytes=0;
    
    sockaddr_in addr, peerAddr;
    struct timeval RequestTimeout = {0,5000000} , DownloadTimeout= {0,500000};
    char URL[4000]={0};
    char FileName[260]={0};
    
    
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    
    fd_set rfd;
    FD_ZERO(&rfd);
    
    
    soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    setsockopt(soc,SOL_SOCKET,SO_REUSEADDR,(const char*)&optval,sizeof(optval));
    
    bind(soc,(sockaddr*)&addr,sizeof(addr));
    listen(soc,100);
    
    
    
    
    acpt = accept(soc,NULL,NULL);
    
    FD_SET(acpt,&rfd);
    
    int connstat = select(acpt+1,&rfd,NULL,NULL,&RequestTimeout);
    
    if(connstat){
    
        int x = 0;
        RecvBytes = recv(acpt,Command,sizeof(Command),0);     // Receives HTTP header
    
        RecvBytes = recv(acpt,FILEDATA,sizeof(FILEDATA),0);     // Receives File headers and content
        
        char * namePtr = strstr(FILEDATA,"\r\n\r\n");
        namePtr = strstr(FILEDATA,"filename=\"") + strlen("filename  "); // Extraction of File Name begins here
        
        while(namePtr[x]!='"'){
            x++;
        }
        
        strncpy(FileName,namePtr,x);              // Extraction of file name ends here.
        
        printf("NAME: %s\n\n",FileName);
        
        int NumberOfBytes = (&strstr(FILEDATA,"\r\n\r\n")[0]+2 - &FILEDATA[0])+2;
        
        f = fopen(FileName,"wb");             // Open file for writing
        
        printf("CONTENTS: %d ",  &strstr(FILEDATA,"\r\n\r\n")[0]+2 - &FILEDATA[0]);
        
        fwrite(strstr(FILEDATA,"\r\n\r\n")+4,1,RecvBytes - NumberOfBytes ,f);   // Received Number of Bytes - Number of Bytes Till Header
        
        
        while(select(acpt+1,&rfd,NULL,NULL,&DownloadTimeout)){    // Keep reading if more data remains available
            RecvBytes = recv(acpt,FILEDATA,sizeof(FILEDATA),0);   // receive
            if(RecvBytes==0){                                     
                break;
            }
            fwrite(FILEDATA,1,RecvBytes,f);
        }
        
    }
    
    
    
    fclose(f);
    
    
    unsigned long long truncFile = FileSize(FileName) - 45;
    
    f = fopen(FileName,"r+b");                     // truncating file to remove the webkit boundary
    ftruncate(fileno(f),truncFile);
    fclose(f);
    
    printf("OUTPUT FILE SIZE: %llu\n\n",FileSize(FileName));
    
    MessageBeep(MB_ICONERROR); // A beep means operation is complete
    
    
    shutdown(acpt,2);
    closesocket(acpt);
    
    closesocket(soc);
    shutdown(soc,2);
    
    acpt = NULL;
    soc = NULL;
    
    memset(FILEDATA,'\0',sizeof(FILEDATA));
    
}
        

int main(){
    
    //printf("%d\n",strlen("------WebKitFormBoundary5BlPHcjSKYuZFzV3--")); 42
    
    WSAStartup(MAKEWORD(2,2),&ws);
    
    while(1){
        Serve();
    }
    
    
    return 0;
}   

使用 AJAX 上传器的 HTML

 <!DOCTYPE html>
<html>

<body>
The content of the body element is displayed in your browser.

<input type="file" id="image-file">
<button onclick="Send()">Send</button>

<script>


function Send(){
    
    let photo = document.getElementById("image-file").files[0];  // file from input
    let req = new XMLHttpRequest();
    let formData = new FormData();

    formData.append("photo", photo);                            
    req.open("POST", 'http://localhost:12345/');
    req.send(formData);
    
}


</script>

</body>

</html>

上面的 C HTTP 服务器代码完美地处理并下载上传请求到服务器保存的目录中,而不会损坏文件。

© www.soinside.com 2019 - 2024. All rights reserved.