gpt4 book ai didi

c++ - 通过 TLS 将 HTTP2 帧发送到服务器

转载 作者:搜寻专家 更新时间:2023-10-31 01:33:21 25 4
gpt4 key购买 nike

我正在尝试了解 HTTP2 协议(protocol)的工作原理。我看到 Apple 将它用于他们的推送通知服务器。我正在使用 Discover HTTP 中的框架规范.

作为测试,我编写了应该与该服务器通信的代码。但是,我不断收到错误消息,提示我缺少“设置”框架。

我的代码如下:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dlfcn.h>
#include <unistd.h>
#include <openssl/ssl.h>

#define SOCKET_ERROR -1

struct Frame //Represents and HTTP2 Frame.
{
char len[24];
char type[8];
char flags[8];
char identifier[31];
char payload[];
} __attribute__((packed));

void writeFrame(SSL* ssl)
{
//First thing after connecting is to send the PREFACE.
std::string preface = "PRI * HTTP/2.0\r\n\r\n";
preface += "SM\r\n\r\n";

SSL_write(ssl, preface.c_str(), preface.length());

//Now to send the first frame. Aka the SETTINGS frame.
Frame* frame = (Frame *)malloc(sizeof(Frame));
memset(frame, 0, sizeof(Frame));

int frameSize = 100;
memcpy(frame->len, &frameSize, sizeof(frameSize));
memcpy(frame->type, "SETTINGS", strlen("SETTINGS"));
memcpy(frame->identifier, "SETTINGS", strlen("SETTINGS"));

SSL_write(ssl, frame, sizeof(Frame));

//Read server response.
char buffer[10000];
memset(buffer, 0, sizeof(buffer));
int dataLen;
while ((dataLen = SSL_read(ssl, buffer, sizeof(buffer)) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
std::cout << buffer[i];
i += 1;
}
}

//The above gives me the error:
//First received frame was not SETTINGS.
//Hex dump for first 5 bytes: 6400000000

//Try to POST to the server now.
std::string payload = "POST /3/device HTTP/2.0\r\n";
payload += ":method:POST\r\n";
payload += ":scheme: https\r\n";
payload += "cache-control: no-cache\r\n";
payload += "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36\r\n";
payload += "content-type: text/plain;charset=UTF-8\r\n\r\n";

int sentBytes = SSL_write(ssl, payload.c_str(), payload.length());

if (sentBytes < payload.length() || sentBytes == SOCKET_ERROR)
{
return;
}

memset(buffer, 0, sizeof(buffer));
while ((dataLen = SSL_read(ssl, buffer, sizeof(buffer)) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
std::cout << buffer[i];
i += 1;
}
}
}

int main(int argc, const char * argv[]) {

SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();

std::string address = "api.development.push.apple.com";
struct addrinfo hints = {0};
struct addrinfo* result = nullptr;

hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

getaddrinfo(address.c_str(), nullptr, &hints, &result);

int sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock == -1)
{
return -1;
}

struct sockaddr_in sockAddr;
sockAddr.sin_addr = reinterpret_cast<struct sockaddr_in*>(result->ai_addr)->sin_addr;
sockAddr.sin_family = result->ai_family;
sockAddr.sin_port = htons(443);
freeaddrinfo(result);

if (connect(sock, reinterpret_cast<sockaddr *>(&sockAddr), sizeof(sockAddr)) == SOCKET_ERROR)
{
close(sock);
return -1;
}

SSL_CTX* ctx = SSL_CTX_new(TLSv1_2_method());
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
SSL_connect(ssl);

writeFrame(ssl);

SSL_CTX_free(ctx);
SSL_shutdown(ssl);
SSL_free(ssl);
close(sock);
return 0;
}

如何将SETTINGS 框架和其他框架发送到服务器?我错过了什么?

最佳答案

你有几个错误。

首先是Frame数据结构,其中数组字段的长度是错误的。您似乎以位为单位复制了它们的长度,但以字节为单位在 Frame 数据结构中报告了它们。你想要这个:

struct Frame {
char len[3];
char type;
char flags;
char identifier[4];
char payload[];
}

此外,框架的类型不是字符串,标识符也不是。

最后,请求的格式完全错误,类似HTTP/1.1,而HTTP/2格式完全不同,基于HPACK。

我建议你仔细阅读 HTTP/2 specification在编写进一步的代码之前。

关于c++ - 通过 TLS 将 HTTP2 帧发送到服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41539339/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com