【问题标题】:Receiving only necessary data with C++ Socket使用 C++ Socket 仅接收必要的数据
【发布时间】:2013-01-03 11:12:29
【问题描述】:

我只是想获取带有标题的页面内容...但似乎我的大小为 1024 的缓冲区对于通过的最后一个信息包来说太大或太小...我不知道不想得到太多或太少,如果这是有道理的。这是我的代码。它可以很好地打印出包含所有信息的页面,但我想确保它是正确的。

//Build HTTP Get Request
std::stringstream ss;
ss << "GET " << url << " HTTP/1.0\r\nHost: " << strHostName << "\r\n\r\n";
std::string req = ss.str();

// Send Request
send(hSocket, req.c_str(), strlen(req.c_str()), 0);

// Read from socket into buffer.
do
{
     nReadAmount = read(hSocket, pBuffer, sizeof pBuffer);
     printf("%s", pBuffer);

}
while(nReadAmount != 0);

【问题讨论】:

  • 您的问题是只显示页面的正文吗?你也想得到标题?
  • 我希望能够控制是否获得标题,是的。但此刻,我正在得到它们......
  • 您可以在收到页面后使用 html 解析器,将正文、头部等各个部分分开。
  • 我的问题是我不确定我的缓冲区是否正常工作或按应有的方式工作。为什么我会收到标题?这正常吗?
  • 在发送 HTTP get 请求后从套接字读取时,您期望什么行为?

标签: c++ sockets


【解决方案1】:

阅读 HTTP 回复的正确方法是阅读,直到收到完整的LF-delimited 行(有些服务器使用bare LF,即使官方规范说使用CRLF),其中包含响应代码和版本,然后继续阅读 LF 分隔的行,即标头,直到遇到 0 长度行,表示标头的结尾,然后您必须分析标头以找出剩余数据的编码方式您知道阅读它的正确方法并知道它是如何终止的。有几种不同的可能性,具体规则请参考RFC 2616 Section 4.4

也就是说,你的代码需要改用这种结构(伪代码):

// Send Request
send(hSocket, req.c_str(), req.length(), 0);

// Read Response
std::string line = ReadALineFromSocket(hSocket);
int rescode = ExtractResponseCode(line);
std::vector<std::string> headers;
do
{
     line = ReadALineFromSocket(hSocket);
     if (line.length() == 0) break;
     headers.push_back(line);
}
while (true);

if (
    ((rescode / 100) != 1) &&
    (rescode != 204) &&
    (rescode != 304) &&
    (request is not "HEAD")
)
{
    if ((headers has "Transfer-Encoding") && (Transfer-Encoding != "identity"))
    {
        // read chunks until a 0-length chunk is encountered.
        // refer to RFC 2616 Section 3.6 for the format of the chunks...
    }
    else if (headers has "Content-Length")
    {
       // read how many bytes the Content-Length header says...
    }
    else if ((headers has "Content-Type") && (Content-Type == "multipart/byteranges"))
    {
        // read until the terminating MIME boundary specified by Content-Type is encountered...
    }
    else
    {
        // read until the socket is disconnected...
    }
}

【讨论】:

  • 这肯定更好,但对于 HTTP 1.0 并不是绝对必要的。如果您没有另外指定,而他没有指定,则传输结束将通过连接关闭来指示。
【解决方案2】:
 nReadAmount = read(hSocket, pBuffer, sizeof pBuffer);
 printf("%s", pBuffer);

这个坏了。您只能将 %s 格式说明符用于 C 样式(以零结尾)字符串。 printf 应该如何知道要打印多少字节?该信息在nReadAmount 中,但您不使用它。

此外,即使read 失败,您也调用printf

最简单的解决方法:

 do
 {
     nReadAmount = read(hSocket, pBuffer, (sizeof pBuffer) - 1);
     if (nReadAmount <= 0)
         break;
     pBuffer[nReadAmount] = 0;
     printf("%s", pBuffer);
 } while(1);

【讨论】:

  • 您可以将读取的字节数作为额外参数传递给 printf():printf("%.*s", nReadAmount, pBuffer);
猜你喜欢
  • 2011-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多