Websocket握手:不正确';Sec WebSocket接受';标题值 我正在用C++编写WebSoSk服务器,无法让握手工作。Chrome报告错误是由于错误的accept头,但我相信该值是正确的

Websocket握手:不正确';Sec WebSocket接受';标题值 我正在用C++编写WebSoSk服务器,无法让握手工作。Chrome报告错误是由于错误的accept头,但我相信该值是正确的,websocket,Websocket,作为exchange的一个示例,客户端发送以下密钥: Sec-WebSocket-Key: ypX0m2zum/pt80mxlVo8PA== 我的服务器会发回: Sec-WebSocket-Accept: Kl4mnqm5QA6bBmGf3EAN0nyGXws= 我已经根据RFC中的示例测试了我的服务器,并且它已经检查出来了。我不知道为什么不被接受。我的理论是,我必须做一些其他事情,产生与坏接受值相同的错误 以下是wireshark捕获的不同请求: Hypertext Transfer Pr

作为exchange的一个示例,客户端发送以下密钥:

Sec-WebSocket-Key: ypX0m2zum/pt80mxlVo8PA==
我的服务器会发回:

Sec-WebSocket-Accept: Kl4mnqm5QA6bBmGf3EAN0nyGXws=
我已经根据RFC中的示例测试了我的服务器,并且它已经检查出来了。我不知道为什么不被接受。我的理论是,我必须做一些其他事情,产生与坏接受值相同的错误

以下是wireshark捕获的不同请求:

Hypertext Transfer Protocol
    GET /websocket HTTP/1.1\r\n
    Host: 127.0.0.1:8443\r\n
    Connection: Upgrade\r\n
    Pragma: no-cache\r\n
    Cache-Control: no-cache\r\n
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Upgrade: websocket\r\n
    Origin: chrome-extension://eajaahbjpnhghjcdaclbkeamlkepinbl\r\n
    Sec-WebSocket-Version: 13\r\n
    Accept-Encoding: gzip, deflate, br\r\n
    Accept-Language: en-US,en;q=0.9\r\n
    Sec-WebSocket-Key: +zJ3/KI/Zrumgh+AjxopRQ==\r\n
    Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n
    \r\n
    [Full request URI: http://127.0.0.1:8443/websocket]
    [HTTP request 1/1]
    [Response in frame: 6]
以下是回应:

Hypertext Transfer Protocol
    HTTP/1.1 101 Switching Protocols\r\n
    Upgrade: websocket\r\n
    Connection: Upgrade\r\n
    Sec-WebSocket-Accept: anTEIFyI/gTepr8Q3okBj81M2/4=\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.000245010 seconds]
    [Request in frame: 4]
有人能告诉我这个回答有什么问题吗?我的接受值是否不正确

编辑1:

我用来创建响应值的代码。在此之前,会从请求中获取websocket_密钥

    const char *magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    int pre_hash_size = 36 + websocket_key.size();
    char pre_hash[pre_hash_size];

    memcpy(pre_hash, websocket_key.c_str(), websocket_key.size());
    memcpy(pre_hash + websocket_key.size(), magic_string, 36);

    unique_ptr<Botan::HashFunction> hash1(Botan::HashFunction::create("SHA-1"));
    Botan::secure_vector<uint8_t> post_hash = hash1->process(reinterpret_cast<const uint8_t *>(pre_hash), pre_hash_size);

    string accept_response = base64_encode(post_hash.data(), post_hash.size());
const char*magic_string=“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”;
int pre_hash_size=36+websocket_key.size();
char pre_hash[pre_hash_size];
memcpy(pre_hash,websocket_key.c_str(),websocket_key.size());
memcpy(pre_hash+websocket_key.size(),magic_string,36);
唯一的(Botan::HashFunction::create(“SHA-1”);
Botan::secure\u vector post\u hash=hash1->process(重新解释强制转换(pre\u hash)、pre\u hash\u size);
字符串accept_response=base64_encode(post_hash.data(),post_hash.size());
下面是base 64函数:

/* 
   base64.cpp and base64.h
   base64 encoding and decoding with C++.
   Version: 1.01.00
   Copyright (C) 2004-2017 René Nyffenegger
   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.
   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:
   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.
   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.
   3. This notice may not be removed or altered from any source distribution.
   René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/

static const std::string base64_chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789+/";

std::string base64_encode(unsigned char const *bytes_to_encode, unsigned int in_len)
{
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (in_len--)
  {
    char_array_3[i++] = *(bytes_to_encode++);
    if (i == 3)
    {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;

      for (i = 0; (i < 4); i++)
        ret += base64_chars[char_array_4[i]];
      i = 0;
    }
  }

  if (i)
  {
    for (j = i; j < 3; j++)
      char_array_3[j] = '\0';

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);

    for (j = 0; (j < i + 1); j++)
      ret += base64_chars[char_array_4[j]];

    while ((i++ < 3))
      ret += '=';
  }

  return ret;
}
/*
base64.cpp和base64.h
Base64编码和解码用C++实现。
版本:1.01.00
版权所有(C)2004-2017勒内·尼弗内格
此源代码按“原样”提供,没有任何明示或暗示
担保在任何情况下,提交人都不对任何损害负责
由于使用本软件而产生的。
允许任何人出于任何目的使用本软件,
包括商业应用程序,并对其进行修改和重新发布
自由,受以下限制:
1.不得歪曲本源代码的来源;你不能
声称您编写了原始源代码。如果您使用此源代码
在产品中,产品文档中的确认是
感谢,但不是必需的。
2.更改后的源版本必须清楚地标记为这样,并且不得更改
被误传为原始源代码。
3.不得从任何源分发中删除或更改此通知。
雷内·尼弗内格·雷内。nyffenegger@adp-股份有限公司
*/
静态常量std::字符串base64_字符=
“ABCDEFGHIJKLMNOPQRSTUVWXYZ”
“abcdefghijklmnopqrstuvwxyz”
"0123456789+/";
std::string base64_encode(无符号字符常量*bytes_to_encode,无符号整数in_len)
{
std::字符串ret;
int i=0;
int j=0;
无符号字符数组3[3];
无符号字符数组4[4];
而(在_len--)
{
字符数组3[i++]=*(字节到编码++);
如果(i==3)
{
char_数组_4[0]=(char_数组_3[0]&0xfc)>>2;
char_数组_4[1]=((char_数组_3[0]&0x03)>4);
char_数组_4[2]=((char_数组_3[1]&0x0f)>6);
char_数组_4[3]=char_数组_3[2]&0x3f;
对于(i=0;(i<4);i++)
ret+=base64_字符[char_数组_4[i];
i=0;
}
}
如果(i)
{
对于(j=i;j<3;j++)
字符数组_3[j]='\0';
char_数组_4[0]=(char_数组_3[0]&0xfc)>>2;
char_数组_4[1]=((char_数组_3[0]&0x03)>4);
char_数组_4[2]=((char_数组_3[1]&0x0f)>6);
对于(j=0;(j
问题在于,当我从websocket键(由客户端发送)连接pre_散列字符串和魔术字符串(常量)时,我没有考虑size()函数在其计数中包含的空终止符。我在解析请求头时无意中添加了一个额外的空间


记住,C++的字符串是null结尾的,并且(si/e)反映了.< /p>你也可以显示你用来生成值的代码吗?@ FryByGuy编辑添加。C++字符串不是空的终止(但你可以从一个<代码> STD::String 如果需要的话,得到一个空的终止的C字符串),和<代码> STD::String::在字符串数据之后不包含任何空终止符,但它会在字符串数据中包含任何嵌入的空值,这在这种情况下是错误的,因为不应该存在任何空值。如果有,那么在填充

std::string
s.Lol时,您正在做一些错误的事情,您应该查找它。谢谢@RemyLebeau的关注。我用真正的原因更新了答案。