MsQuick编译和使用

发布于:2025-05-01 ⋅ 阅读:(40) ⋅ 点赞:(0)

编译

克隆代码

git clone --recurse-submodules https://github.com/microsoft/msquic.git

在这里插入图片描述

使用cmake+vs2022编译

在这里插入图片描述
然后直接configure之后Generate然后打开vs工程编译即可生成动态库
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "msquic.h"

#define DEFAULT_PORT 4567
#define BUFFER_SIZE 1024

const QUIC_REGISTRATION_CONFIG RegConfig = { "quicecho", QUIC_EXECUTION_PROFILE_LOW_LATENCY };
const QUIC_BUFFER Alpn = { sizeof("sample") - 1, (uint8_t*)"sample" };
const uint32_t IdleTimeoutMs = 1000;

const QUIC_API_TABLE* MsQuic = nullptr;
HQUIC Registration = nullptr;
HQUIC ServerConfiguration = nullptr;
HQUIC ClientConfiguration = nullptr;
HQUIC Listener = nullptr;

// 服务器回调函数
QUIC_STATUS QUIC_API ServerStreamCallback(
    HQUIC Stream,
    void* Context,
    QUIC_STREAM_EVENT* Event
) {
    UNREFERENCED_PARAMETER(Context);
    switch (Event->Type) {
    case QUIC_STREAM_EVENT_SEND_COMPLETE:
        free(Event->SEND_COMPLETE.ClientContext);
        printf("[流][%p] 数据已发送\n", Stream);
        break;
    case QUIC_STREAM_EVENT_RECEIVE:
        if (Event->RECEIVE.TotalBufferLength > 0) {
            char* buffer = (char*)malloc(Event->RECEIVE.TotalBufferLength + 1);
            uint32_t offset = 0;
            for (uint32_t i = 0; i < Event->RECEIVE.BufferCount; ++i) {
                memcpy(buffer + offset,
                    Event->RECEIVE.Buffers[i].Buffer,
                    Event->RECEIVE.Buffers[i].Length);
                offset += Event->RECEIVE.Buffers[i].Length;
            }
            buffer[Event->RECEIVE.TotalBufferLength] = '\0';

            printf("收到消息: %s\n", buffer);

            // 回显给客户端
            void* SendBufferRaw = malloc(sizeof(QUIC_BUFFER) + Event->RECEIVE.TotalBufferLength);
            if (SendBufferRaw != NULL) {
                QUIC_BUFFER* SendBuffer = (QUIC_BUFFER*)SendBufferRaw;
                SendBuffer->Buffer = (uint8_t*)SendBufferRaw + sizeof(QUIC_BUFFER);
                SendBuffer->Length = Event->RECEIVE.TotalBufferLength;
                memcpy(SendBuffer->Buffer, buffer, Event->RECEIVE.TotalBufferLength);

                MsQuic->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_NONE, SendBuffer);
            }

            free(buffer);
        }
        break;
    case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN:
        printf("[流][%p] 对端关闭发送\n", Stream);
        break;
    case QUIC_STREAM_EVENT_PEER_SEND_ABORTED:
        printf("[流][%p] 对端中止发送\n", Stream);
        MsQuic->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0);
        break;
    case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE:
        printf("[流][%p] 流已关闭\n", Stream);
        MsQuic->StreamClose(Stream);
        break;
    default:
        break;
    }
    return QUIC_STATUS_SUCCESS;
}

QUIC_STATUS QUIC_API ServerConnectionCallback(
    HQUIC Connection,
    void* Context,
    QUIC_CONNECTION_EVENT* Event
) {
    UNREFERENCED_PARAMETER(Context);
    switch (Event->Type) {
    case QUIC_CONNECTION_EVENT_CONNECTED:
        printf("[连接][%p] 已连接\n", Connection);
        MsQuic->ConnectionSendResumptionTicket(Connection, QUIC_SEND_RESUMPTION_FLAG_NONE, 0, NULL);
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT:
        if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) {
            printf("[连接][%p] 空闲超时关闭\n", Connection);
        }
        else {
            printf("[连接][%p] 传输层关闭,错误码: 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
        }
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER:
        printf("[连接][%p] 对端关闭,错误码: 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE:
        printf("[连接][%p] 连接已关闭\n", Connection);
        MsQuic->ConnectionClose(Connection);
        break;
    case QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED:
        printf("[流][%p] 对端创建新流\n", Event->PEER_STREAM_STARTED.Stream);
        MsQuic->SetCallbackHandler(Event->PEER_STREAM_STARTED.Stream, (void*)ServerStreamCallback, nullptr);
        break;
    case QUIC_CONNECTION_EVENT_RESUMED:
        printf("[连接][%p] 连接已恢复\n", Connection);
        break;
    default:
        break;
    }
    return QUIC_STATUS_SUCCESS;
}

QUIC_STATUS QUIC_API ServerListenerCallback(
    HQUIC Listener,
    void* Context,
    QUIC_LISTENER_EVENT* Event
) {
    UNREFERENCED_PARAMETER(Context);
    QUIC_STATUS Status = QUIC_STATUS_NOT_SUPPORTED;
    switch (Event->Type) {
    case QUIC_LISTENER_EVENT_NEW_CONNECTION:
        MsQuic->SetCallbackHandler(Event->NEW_CONNECTION.Connection, (void*)ServerConnectionCallback, nullptr);
        Status = MsQuic->ConnectionSetConfiguration(Event->NEW_CONNECTION.Connection, ServerConfiguration);
        break;
    default:
        break;
    }
    return Status;
}

// 客户端回调函数
QUIC_STATUS QUIC_API ClientStreamCallback(
    HQUIC Stream,
    void* Context,
    QUIC_STREAM_EVENT* Event
) {
    UNREFERENCED_PARAMETER(Context);
    switch (Event->Type) {
    case QUIC_STREAM_EVENT_SEND_COMPLETE:
        free(Event->SEND_COMPLETE.ClientContext);
        printf("[流][%p] 数据已发送\n", Stream);
        break;
    case QUIC_STREAM_EVENT_RECEIVE:
        if (Event->RECEIVE.TotalBufferLength > 0) {
            char* buffer = (char*)malloc(Event->RECEIVE.TotalBufferLength + 1);
            uint32_t offset = 0;
            for (uint32_t i = 0; i < Event->RECEIVE.BufferCount; ++i) {
                memcpy(buffer + offset,
                    Event->RECEIVE.Buffers[i].Buffer,
                    Event->RECEIVE.Buffers[i].Length);
                offset += Event->RECEIVE.Buffers[i].Length;
            }
            buffer[Event->RECEIVE.TotalBufferLength] = '\0';
            printf("收到服务器回显: %s\n", buffer);
            free(buffer);
        }
        break;
    case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN:
        printf("[流][%p] 对端关闭发送\n", Stream);
        break;
    case QUIC_STREAM_EVENT_PEER_SEND_ABORTED:
        printf("[流][%p] 对端中止发送\n", Stream);
        break;
    case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE:
        printf("[流][%p] 流已关闭\n", Stream);
        MsQuic->StreamClose(Stream);
        break;
    default:
        break;
    }
    return QUIC_STATUS_SUCCESS;
}

QUIC_STATUS QUIC_API ClientConnectionCallback(
    HQUIC Connection,
    void* Context,
    QUIC_CONNECTION_EVENT* Event
) {
    UNREFERENCED_PARAMETER(Context);
    switch (Event->Type) {
    case QUIC_CONNECTION_EVENT_CONNECTED:
        printf("[连接][%p] 已连接\n", Connection);
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT:
        if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) {
            printf("[连接][%p] 空闲超时关闭\n", Connection);
        }
        else {
            printf("[连接][%p] 传输层关闭,错误码: 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
        }
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER:
        printf("[连接][%p] 对端关闭,错误码: 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
        break;
    case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE:
        printf("[连接][%p] 连接已关闭\n", Connection);
        MsQuic->ConnectionClose(Connection);
        break;
    default:
        break;
    }
    return QUIC_STATUS_SUCCESS;
}

bool LoadServerConfiguration() {
    QUIC_CREDENTIAL_CONFIG CredConfig;
    memset(&CredConfig, 0, sizeof(CredConfig));

    CredConfig.Flags = QUIC_CREDENTIAL_FLAG_NONE;
    CredConfig.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE;

    QUIC_CERTIFICATE_FILE CertFile;
    memset(&CertFile, 0, sizeof(CertFile));
    CertFile.CertificateFile = "server.cert";
    CertFile.PrivateKeyFile = "server.key";

    CredConfig.CertificateFile = &CertFile;

    printf("正在从 %s 加载证书\n", CertFile.CertificateFile);
    printf("正在从 %s 加载私钥\n", CertFile.PrivateKeyFile);

    QUIC_STATUS Status = MsQuic->ConfigurationLoadCredential(
        ServerConfiguration,
        &CredConfig);

    if (QUIC_FAILED(Status)) {
        printf("加载证书失败,错误码: %d\n", Status);
        return false;
    }

    printf("证书加载成功\n");
    return true;
}

bool LoadClientConfiguration() {
    QUIC_SETTINGS Settings = { 0 };
    Settings.IdleTimeoutMs = IdleTimeoutMs;
    Settings.IsSet.IdleTimeoutMs = TRUE;

    QUIC_CREDENTIAL_CONFIG CredConfig;
    memset(&CredConfig, 0, sizeof(CredConfig));
    CredConfig.Type = QUIC_CREDENTIAL_TYPE_NONE;
    CredConfig.Flags = QUIC_CREDENTIAL_FLAG_CLIENT |
        QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION;

    QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
    if (QUIC_FAILED(Status = MsQuic->ConfigurationOpen(
        Registration,
        &Alpn,
        1,
        &Settings,
        sizeof(Settings),
        NULL,
        &ClientConfiguration))) {
        printf("打开客户端配置失败,错误码: %d\n", Status);
        return false;
    }

    if (QUIC_FAILED(Status = MsQuic->ConfigurationLoadCredential(
        ClientConfiguration,
        &CredConfig))) {
        printf("加载客户端凭证失败,错误码: %d\n", Status);
        return false;
    }

    return true;
}

void StartServer() {
    QUIC_STATUS Status;
    QUIC_SETTINGS Settings = { 0 };
    QUIC_ADDR Address = { 0 };

    Settings.IdleTimeoutMs = IdleTimeoutMs;
    Settings.IsSet.IdleTimeoutMs = TRUE;
    Settings.PeerBidiStreamCount = 100;
    Settings.IsSet.PeerBidiStreamCount = TRUE;
    Settings.PeerUnidiStreamCount = 100;
    Settings.IsSet.PeerUnidiStreamCount = TRUE;
    Settings.SendBufferingEnabled = FALSE;
    Settings.IsSet.SendBufferingEnabled = TRUE;

    QuicAddrSetFamily(&Address, QUIC_ADDRESS_FAMILY_INET);
    QuicAddrSetPort(&Address, DEFAULT_PORT);

    if (QUIC_FAILED(Status = MsQuic->ConfigurationOpen(
        Registration,
        &Alpn,
        1,
        &Settings,
        sizeof(Settings),
        NULL,
        &ServerConfiguration))) {
        printf("打开服务器配置失败,错误码: %d\n", Status);
        return;
    }

    if (!LoadServerConfiguration()) {
        return;
    }

    if (QUIC_FAILED(Status = MsQuic->ListenerOpen(
        Registration,
        ServerListenerCallback,
        NULL,
        &Listener))) {
        printf("打开监听器失败,错误码: %d\n", Status);
        return;
    }

    if (QUIC_FAILED(Status = MsQuic->ListenerStart(
        Listener,
        &Alpn,
        1,
        &Address))) {
        printf("启动监听器失败,错误码: %d\n", Status);
        return;
    }

    printf("服务器正在监听端口 %d\n", DEFAULT_PORT);
}

void ClientSend(HQUIC Connection, const char* message) {
    QUIC_STATUS Status;
    HQUIC Stream = NULL;

    if (QUIC_FAILED(Status = MsQuic->StreamOpen(
        Connection,
        QUIC_STREAM_OPEN_FLAG_NONE,
        ClientStreamCallback,
        NULL,
        &Stream))) {
        printf("创建流失败,错误码: %d\n", Status);
        return;
    }

    printf("[流][%p] 正在启动...\n", Stream);

    if (QUIC_FAILED(Status = MsQuic->StreamStart(
        Stream,
        QUIC_STREAM_START_FLAG_NONE))) {
        printf("启动流失败,错误码: %d\n", Status);
        MsQuic->StreamClose(Stream);
        return;
    }

    void* SendBufferRaw = malloc(sizeof(QUIC_BUFFER) + strlen(message));
    if (SendBufferRaw == NULL) {
        printf("发送缓冲区分配失败!\n");
        MsQuic->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0);
        return;
    }

    QUIC_BUFFER* SendBuffer = (QUIC_BUFFER*)SendBufferRaw;
    SendBuffer->Buffer = (uint8_t*)SendBufferRaw + sizeof(QUIC_BUFFER);
    SendBuffer->Length = (uint32_t)strlen(message);
    memcpy(SendBuffer->Buffer, message, strlen(message));

    printf("[流][%p] 正在发送数据...\n", Stream);

    if (QUIC_FAILED(Status = MsQuic->StreamSend(
        Stream,
        SendBuffer,
        1,
        QUIC_SEND_FLAG_NONE,
        SendBuffer))) {
        printf("发送数据失败,错误码: %d\n", Status);
        free(SendBufferRaw);
        MsQuic->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0);
    }
}

void ClientConnect(const char* message) {
    if (!LoadClientConfiguration()) {
        return;
    }

    QUIC_STATUS Status;
    HQUIC Connection = NULL;

    if (QUIC_FAILED(Status = MsQuic->ConnectionOpen(
        Registration,
        ClientConnectionCallback,
        NULL,
        &Connection))) {
        printf("创建连接失败,错误码: %d\n", Status);
        return;
    }

    printf("[连接][%p] 正在连接...\n", Connection);

    if (QUIC_FAILED(Status = MsQuic->ConnectionStart(
        Connection,
        ClientConfiguration,
        QUIC_ADDRESS_FAMILY_INET,
        "localhost",
        DEFAULT_PORT))) {
        printf("启动连接失败,错误码: %d\n", Status);
        MsQuic->ConnectionClose(Connection);
        return;
    }

    // 等待连接建立
    Sleep(100);

    // 发送消息
    ClientSend(Connection, message);

    // 等待响应
    Sleep(100);

    // 关闭连接
    MsQuic->ConnectionClose(Connection);
}

int main() {
    QUIC_STATUS Status;

    if (QUIC_FAILED(Status = MsQuicOpen2(&MsQuic))) {
        printf("MsQuicOpen2 失败,错误码: %d\n", Status);
        return -1;
    }

    if (QUIC_FAILED(Status = MsQuic->RegistrationOpen(&RegConfig, &Registration))) {
        printf("RegistrationOpen 失败,错误码: %d\n", Status);
        return -1;
    }

    // 启动服务器
    StartServer();

    printf("MsQuic 回显服务器控制台\n");
    printf("输入 'exit' 退出程序\n");

    char input[BUFFER_SIZE];
    while (true) {
        printf("请输入要发送的消息: ");
        if (fgets(input, BUFFER_SIZE, stdin) == NULL) {
            break;
        }

        // 移除换行符
        input[strcspn(input, "\n")] = 0;

        if (strcmp(input, "exit") == 0) {
            break;
        }

        // 发送消息
        ClientConnect(input);
    }

    // 清理资源
    if (Listener != NULL) {
        MsQuic->ListenerClose(Listener);
    }
    if (ServerConfiguration != NULL) {
        MsQuic->ConfigurationClose(ServerConfiguration);
    }
    if (ClientConfiguration != NULL) {
        MsQuic->ConfigurationClose(ClientConfiguration);
    }
    if (Registration != NULL) {
        MsQuic->RegistrationClose(Registration);
    }
    if (MsQuic != NULL) {
        MsQuicClose(MsQuic);
    }

    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到