【问题标题】:How to send a file with http with c++如何使用 C++ 发送带有 http 的文件
【发布时间】:2011-09-01 16:01:00
【问题描述】:

我想写一个服务器端代码。它应该适用于流行的浏览器和 wget。我的服务器检查文件是否存在,如果存在则浏览器可以下载它。但我有一些问题。 老实说,我读了很多问答(例如:Send binary file in HTTP response using C sockets)但我没有找到。我的浏览器(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 标头,但我没有发现。

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

对不起,我解释的都很复杂。

【问题讨论】:

  • 我认为问题之一是okStatus[] 末尾没有零终止字符。尝试将其添加到末尾,而不是 's'
  • @Tony The Tiger 感谢您的帮助。我试过了,还是不行。
  • @Tony The Tiger Literal 字符串自动以空值结尾
  • 我不知道它是否相关,但okStatusConnection: close 部分仅后跟\n。后面应该跟\r\n
  • @Andy,嗯,我不太确定。

标签: c++ http download


【解决方案1】:

这里的问题是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,您需要发送&lt;PRE&gt;123\n456\n789&lt;/PRE&gt;,因为浏览器会将此文本解析为html,而不是像操作系统那样解析并显示输出。您可以做的另一种方法是将所有\n 替换为&lt;BR&gt; ...

【讨论】:

  • 你好。感谢您的回答。我的第一个问题是通过您的帮助解决的。我改变了它并且它有效。关于我的第二个问题,我不想演示文本,浏览器应该下载它。我想我应该更改 Content-Type 并以正确的方式发送(不是 getline),我不知道。
  • @Thom 如果浏览器能够解析 mime "text/html",他很可能会这样做,因为这样更方便。但有一种解决方法:使用标题表明您希望通过Content-Disposition: attachment;filename="test.jpg" 下载。有关详细信息,请参阅apptools.com/phptools/force-download.php。它是 php,但主要的 http 概念仍然适用。
  • 我不确定我是否得到它。我假设您希望下载的文本文件不显示在浏览器上。在这种情况下,正如@RedX 建议的那样,您需要使用Content-Disposition: attachment;filename="test.txt".
  • @Thorn:你可以看看这篇文章Content-Type。这是一个很好的阅读
  • @RedX 谢谢你的建议。有用。你的链接很有帮助。 @Mayank 正是:)
【解决方案2】:

关于您的第一个问题,您应该找出文件的确切大小并在 "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; 否则,您的回车应由&lt;br&gt; 表示,而不是“\r\n”。

如果是二进制下载,要将数据下载为文件(而不显示在浏览器中),您应该指定

Content-Type: application/octet-stream

【讨论】:

  • 你好塞尔吉奥。如果我发送二进制数据,chrome或firefox会自动下载吗?
  • 您好 Thorn,请参阅我的编辑。你需要Content-Type: application/octet-stream
  • 我可以通过仅更改 Content-Type 以相同的方法 (getline()) 发送 rar 文件或其他内容吗?
  • Thorn,确定你可以发送 rar 文件。无论如何,getline 方法并不是最好的。请参阅我对二进制数据特定的代码 sn-p 的编辑。
  • 如果我想发送一个可下载的文件,我应该以二进制形式发送,对吗?这样,我们就可以在服务器上得到一个与它相同的文件了? (不丢失'\n')
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多