C++ LibCurl 从套接字获取

发布于 2024-10-03 13:01:26 字数 3429 浏览 3 评论 0原文

我想使用 LibCurl 将此代码(使用带有 Sockets 扩展的脚本语言)转换为 C++。我以前只使用过 LibCurl 一次,所以我对我还需要什么感到有点茫然。我的主要困惑点是我是否应该能够只使用curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);发送这个,或者如果我需要提取套接字,然后通过它发送它。

这是脚本中的相关片段...

public OnSocketConnected(Handle:socket, any:friendId) 
{
    decl String:CommunityId[32];
    FriendIDToCommunityId(friendId, CommunityId, sizeof(CommunityId));

    decl String:query[2048];
    decl String:cookieString[100];
    decl String:inviterString[32];
    decl String:groupString[32];

    GetConVarString(cookie, cookieString, sizeof(cookieString));
    GetConVarString(inviter, inviterString, sizeof(inviterString));
    GetConVarString(group, groupString, sizeof(groupString));


    Format(query, sizeof(query), "GET /actions/GroupInvite?type=groupInvite&inviter=%s&invitee=%s&group=%s HTTP/1.1\r\nHost: steamcommunity.com\r\nConnection: close\r\nCookie: steamLogin=%s\r\n\r\n", inviterString, CommunityId, groupString, cookieString);
    SocketSend(socket, query);
    LogMessage("%s", query);
}

这是到目前为止我在 C++ 中所拥有的内容。看起来我需要先提取套接字,但我不熟悉网络编码,所以我不确定我需要从这里去哪里。

void InviteToGroup(const char *szUserSteamID, const char *szInviterSteamID, const char *steamUser, const char *steamPass)
{
    CURL *curl;
    CURLcode res, result;
    //int sockfd; /* socket */
    char errorBuffer[CURL_ERROR_SIZE];

    const char *szUserID = GetCommunityID(szUserSteamID); // User's Steam Community ID
    const char *szInviterID = GetCommunityID(szInviterSteamID); // Inviter's Steam Community ID
    char *szGroupID = "";
    GetGroupCommunityID(1254745, &szGroupID); // Group Steam Community ID
    const char *szCookie = "76561198018111441%7C%7CC7D70E74A3F592F3E130CCF4CAACD4A7B9CAD993"; // Steam Community Login Cookie

    char *buffer = new char[512];

    // Create the GET request
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "GET /actions/GroupInvite?type=groupInvite&inviter=");
    snprintf(buffer, sizeof(buffer), "%s&invitee=%s&group=%s ", szInviterID, szUserID, szGroupID);
    headers = curl_slist_append(headers, buffer);
    headers = curl_slist_append(headers, "HTTP/1.1\r\nHost: steamcommunity.com\r\nConnection: close\r\nCookie: ");
    snprintf(buffer, sizeof(buffer), "steamLogin=%s\r\n\r\n", szCookie);
    headers = curl_slist_append(headers, buffer);

    delete buffer;

    // Init CURL
    curl = curl_easy_init();

    if(curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, "https://www.steamcommunity.com");
        curl_easy_setopt(curl, CURLOPT_PORT, 443); // Check this before using
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
        //curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); // No transfer, just extract the socket

        // Find out if we need to use Proxy stuff here

        char *userpass = new char[64];
        snprintf(userpass, sizeof(userpass), "%s:%s", steamUser, steamPass);
        curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        // Attempt to Connect the Steam Community Server
        res = curl_easy_perform(curl);

        if (res == CURLE_OK)
            Msg("Connected Successfully!\n");
        else
            Msg("Connection Failed! Error: %s\n", errorBuffer);

        // Close the connection
        curl_easy_cleanup(curl);
    }
}

I would like to convert this code (using a scripting language with a Sockets extension) over to C++ using LibCurl. I have only used LibCurl once previously, so I am at a bit of a loss as to what else I am going to need. My main point of confusing is wether I should be able to just use curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); to send this, or if I am going to need to extract the socket, then send it over that.

Here is the relevant snippet from the script...

public OnSocketConnected(Handle:socket, any:friendId) 
{
    decl String:CommunityId[32];
    FriendIDToCommunityId(friendId, CommunityId, sizeof(CommunityId));

    decl String:query[2048];
    decl String:cookieString[100];
    decl String:inviterString[32];
    decl String:groupString[32];

    GetConVarString(cookie, cookieString, sizeof(cookieString));
    GetConVarString(inviter, inviterString, sizeof(inviterString));
    GetConVarString(group, groupString, sizeof(groupString));


    Format(query, sizeof(query), "GET /actions/GroupInvite?type=groupInvite&inviter=%s&invitee=%s&group=%s HTTP/1.1\r\nHost: steamcommunity.com\r\nConnection: close\r\nCookie: steamLogin=%s\r\n\r\n", inviterString, CommunityId, groupString, cookieString);
    SocketSend(socket, query);
    LogMessage("%s", query);
}

and here is what I have in C++ so far. It is looking like I am going to need to extract the socket first, but I am not proficient with network coding, so I am not exactly sure where I need to go from here.

void InviteToGroup(const char *szUserSteamID, const char *szInviterSteamID, const char *steamUser, const char *steamPass)
{
    CURL *curl;
    CURLcode res, result;
    //int sockfd; /* socket */
    char errorBuffer[CURL_ERROR_SIZE];

    const char *szUserID = GetCommunityID(szUserSteamID); // User's Steam Community ID
    const char *szInviterID = GetCommunityID(szInviterSteamID); // Inviter's Steam Community ID
    char *szGroupID = "";
    GetGroupCommunityID(1254745, &szGroupID); // Group Steam Community ID
    const char *szCookie = "76561198018111441%7C%7CC7D70E74A3F592F3E130CCF4CAACD4A7B9CAD993"; // Steam Community Login Cookie

    char *buffer = new char[512];

    // Create the GET request
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "GET /actions/GroupInvite?type=groupInvite&inviter=");
    snprintf(buffer, sizeof(buffer), "%s&invitee=%s&group=%s ", szInviterID, szUserID, szGroupID);
    headers = curl_slist_append(headers, buffer);
    headers = curl_slist_append(headers, "HTTP/1.1\r\nHost: steamcommunity.com\r\nConnection: close\r\nCookie: ");
    snprintf(buffer, sizeof(buffer), "steamLogin=%s\r\n\r\n", szCookie);
    headers = curl_slist_append(headers, buffer);

    delete buffer;

    // Init CURL
    curl = curl_easy_init();

    if(curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, "https://www.steamcommunity.com");
        curl_easy_setopt(curl, CURLOPT_PORT, 443); // Check this before using
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
        //curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); // No transfer, just extract the socket

        // Find out if we need to use Proxy stuff here

        char *userpass = new char[64];
        snprintf(userpass, sizeof(userpass), "%s:%s", steamUser, steamPass);
        curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

        // Attempt to Connect the Steam Community Server
        res = curl_easy_perform(curl);

        if (res == CURLE_OK)
            Msg("Connected Successfully!\n");
        else
            Msg("Connection Failed! Error: %s\n", errorBuffer);

        // Close the connection
        curl_easy_cleanup(curl);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

铁轨上的流浪者 2024-10-10 13:01:26

因此,请更正此处,因为您的 C++ 不正确,这意味着您的代码将无法工作。

sizeof( char * ) 是指针的大小,而不是字符串的长度。因此,您的 snprintf 将在 32 位系统上打印最多 4 个字符,其中包括空终止符,因此您实际上只会得到长度为 3 的字符串。

如果您打算使用“应该足够大”的缓冲区,则不要分配它与新的。如果要使用 snprintf,可以使用 std::vector,然后检查 snprintf 的返回值,即要写入的实际字符串的长度,然后根据需要增加缓冲区大小(到返回值 + 1)。

vector<char> buffer;
size_t required = 511; 
do 
{ 
    buffer.resize( required + 1 );
    required = snprintf( &buffer[0], buffer.size(), formatstr, ... );
}
while( required >= buffer.size() );

不需要在最后“释放”缓冲区(顺便说一句,你做错了),因为矢量会自动执行此操作。

现在,您将 &buffer[0] 传递给该函数,它将指向一个以 null 结尾的字符串,并且如果 API 需要 char* 而不是 const char*,则该字符串是可写的。 (libcurl 虽然将 ... 作为curl_easy_setopt 的第三个参数,因此您可以传入“任何内容”。因此,您必须小心,因为如果您不小心传入 std::string 或std::向量)。

So corrections here as your C++ is incorrect which will mean your code won't work.

sizeof( char * ) is the size of a pointer, not the length of the string. So your snprintf will print up to 4 characters on a 32-bit system which will include the null terminator so you will actually get only a string of length 3.

If you are going to use a "should be big enough" buffer do not allocate it with new. You could use std::vector if you want to use snprintf, then check the return value of snprintf which is the length of the actual string that would be written and then increase the buffer size if necessary (to the return value + 1).

vector<char> buffer;
size_t required = 511; 
do 
{ 
    buffer.resize( required + 1 );
    required = snprintf( &buffer[0], buffer.size(), formatstr, ... );
}
while( required >= buffer.size() );

There is no need to "free" the buffer at the end (which incidentally you did incorrectly) as vector will do that automatically.

You now pass &buffer[0] to the function, it will point to a null-terminated string and will be writable if the API requires a char* rather than a const char*. (libcurl though takes ... as the 3rd parameter to curl_easy_setopt so you can pass in "anything". You therefore do have to be careful as you won't get warned by the compiler if you accidentally pass in a std::string or std::vector).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文