如何使用 c++ 通过 http 发送文件

发布于 2024-11-09 07:55:23 字数 1825 浏览 0 评论 0原文

我想写一个服务器端代码。它应该适用于流行的浏览器和 wget。我的服务器检查文件是否存在,如果存在则浏览器可以下载它。但我有一些问题。 老实说,我读了很多问题答案(例如:发送使用 C 套接字的 HTTP 响应中的二进制文件),但我没有找到。我的浏览器(Chrome)可以获取文本。但我无法发送任何二进制数据或图像等。我正在根据下载文件更改标头。但我还无法发送可下载的文件。

我有一些问题。

void *clientWorker(void * acceptSocket) {
     int newSocket = (int) acceptSocket;
     char okStatus[] = "HTTP/1.1 200 OK\r\n"
                       "Content-Type: text/html\r\n"
                       "Connection: close\r\n"
                       "Content-Length: 20\r\n"
                       "\r\n"
                       "s";
     writeLn(newSocket, okStatus);
     const char * fileName = "/home/tyra/Desktop/example.txt";
     sendF(newSocket, fileName);
}

1-如果我不在okStatus中写入“s”或其他内容,我的消息将无法发送。我对此一无所知。

这是 writeLn 函数:

void writeLn(int acceptSocket, const char * buffer) {
    int n = write(acceptSocket, buffer, strlen(buffer) - 1);
    if (n < 0) {
        error("Error while writing");
    }
}

这是 sendF 函数:

string buffer;
string line;
ifstream myfile(fileName);
struct stat filestatus;
stat(fileName, &filestatus);
int fsize = filestatus.st_size;
if (myfile.is_open()) {
    while (myfile.good()) {
        getline(myfile, line);
        buffer.append(line);
    }
    cout << buffer << endl;
}
writeLn(acceptSocket, buffer.c_str());
cout << fsize << " bytes\n";

有点乱。我还没有使用文件大小。如果我发送文件,那么我会重新排列这些内容。

2- 我可以发送文本,浏览器会演示它,但浏览器无法理解新行。 如果文本文件包含(123\n456\n789),浏览器显示(123456789)。我认为我应该更改 Content-Type 标头,但我没有找到。

我不希望该浏览器演示文本文件。浏览器应该下载它。如何发送可下载的文件?

抱歉,我解释的一切都很复杂。

I want to write a server side code. It should work with popular browsers and wget. My server check that file exists or not, if exists then browser can download it. But I have some problems.
Honestly, I read lots of question-answer (for example: Send binary file in HTTP response using C sockets) but I didn't find out. My browser (Chrome) can get text. But I cannot send any binary data or images etc. I am changing header according to downloading files. But I cannot send a downloadable files yet.

I have some questions.

void *clientWorker(void * acceptSocket) {
     int newSocket = (int) acceptSocket;
     char okStatus[] = "HTTP/1.1 200 OK\r\n"
                       "Content-Type: text/html\r\n"
                       "Connection: close\r\n"
                       "Content-Length: 20\r\n"
                       "\r\n"
                       "s";
     writeLn(newSocket, okStatus);
     const char * fileName = "/home/tyra/Desktop/example.txt";
     sendF(newSocket, fileName);
}

1- If I wouldn't write "s" or something else inokStatus, my message cannot send. I don't understand anything of this.

This is writeLn function :

void writeLn(int acceptSocket, const char * buffer) {
    int n = write(acceptSocket, buffer, strlen(buffer) - 1);
    if (n < 0) {
        error("Error while writing");
    }
}

This is sendF function :

string buffer;
string line;
ifstream myfile(fileName);
struct stat filestatus;
stat(fileName, &filestatus);
int fsize = filestatus.st_size;
if (myfile.is_open()) {
    while (myfile.good()) {
        getline(myfile, line);
        buffer.append(line);
    }
    cout << buffer << endl;
}
writeLn(acceptSocket, buffer.c_str());
cout << fsize << " bytes\n";

A little messy. I haven't used file size yet. If I send a file, then I rearrange these things.

2- I can send text and browser demonstrates it but browser didn't understand new lines.
If text file contains (123\n456\n789), browser demonstrates (123456789). I think I should change Content-Type header, but I didn't find out.

I don't want that browser demonstrates text files. Browser should download it. How can I send downloadable files?

Sorry, I explain everything pretty complicated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你怎么敢 2024-11-16 07:55:23

关于您的第一个问题,您应该找出文件的确切大小并在 "Content-Length: xxxx\r\n" 标头中指定它。当然,你应该确保数据完全发送出去。

事实上,在您的 writeF 函数中,您使用 std::string 作为缓冲区:

string buffer;

这不适合二进制数据。您应该分配一个正确大小的原始 char 数组:

int fsize = file.tellg();
char* buffer = new char[fsize];
file.seekg (0, ios::beg);
file.read (buffer, size);
file.close();

对于第二点,当您的数据不是 HTML 时,指定为 Content-Type: text/plain;
否则,您的回车符应由
表示,而不是“\r\n”。

在二进制下载的情况下,要将数据下载为文件(并且不显示在浏览器中),您应该指定

Content-Type: application/octet-stream

As to your first question, you should find out the exact size of the file and specify it in your "Content-Length: xxxx\r\n" header. And, of course, you should ensure that the data is sent completely out.

Indeed, in your writeF function you use a std::string as a buffer:

string buffer;

this is not appropriate for binary data. You should allocate a raw char array of the right size:

int fsize = file.tellg();
char* buffer = new char[fsize];
file.seekg (0, ios::beg);
file.read (buffer, size);
file.close();

As to the second point, when your data is not HTML, specify as Content-Type: text/plain;
otherwise, your carriage return should be represented by <br> instead of "\r\n".

In case of binary downloads, to have the data download as a file (and not shown in the browser), you should specify

Content-Type: application/octet-stream
碍人泪离人颜 2024-11-16 07:55:23

问题是这里的strlenstrlen 在获得“\0”字符时终止。在二进制文件中,您将有许多“\0”字符。

读取文件时,您应该找出文件大小。此大小应在 int n = write(acceptSocket, buffer, strlen(buffer) - 1); 中代替 strlen

更改 writeLn(acceptSocket, buffer.c_str());writeLn(acceptSocket, buffer.c_str(), buffer.size()); 并尝试...

对于 123\ 的情况n456\n789 您需要发送

123\n456\n789

因为浏览器会将此文本解析为 html,而不是像操作系统解析并显示输出。您可以做的另一种方法是将所有 \n 替换为
...

The issue is strlen here. strlen terminates when it gets a '\0' character. In binary file you will have a number of '\0' characters.

While reading the file you should find out the file size. This size should be used in int n = write(acceptSocket, buffer, strlen(buffer) - 1); in place of strlen

Change the writeLn(acceptSocket, buffer.c_str()); to writeLn(acceptSocket, buffer.c_str(), buffer.size()); and try...

For the case of 123\n456\n789 you need to send <PRE>123\n456\n789</PRE> as browser will parse this text as html and not like the OS parses and shows the output. The other way you can do is replace all \n with <BR> ...

泅渡 2024-11-16 07:55:23

关于问题 1 - 如果您不想发回任何内容,请删除 okStatus 末尾的 s 并指定 Content-Length: 0\r标题中的 \n

Regarding question 1 - if you don't want to send any content back then remove the s from the end of okStatus and specify Content-Length: 0\r\n in the header

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文