POST Winsock trouble

POST Winsock trouble

本文关键字:trouble Winsock POST      更新时间:2023-10-16

现在我开始研究插座。但这无法与我的手一起正常工作。我有登录的酷方法:

int LogIn(const string &name, const string &password)
{
char Buffer[1024];
string data = "login=" + name + "&password=" + password;
sprintf(Buffer, "POST /Test/login_cl.php HTTP/1.1r
"nContent-Length: %dr"
"nConnection: Keep-Aliver"
"nAccept-Encoding: gzipr"
"nAccept-Language: ru-RU,en,*r"
"nUser-Agent: Mozilla/5.0r"
"nHost: 127.0.0.1r"
"nContent-Type: application/x-www-form-urlencodedrnrn"    
"login=%s&"
"password=%s&", data.length(), name.c_str(), password.c_str());
int BytesSent = send(MySocket, Buffer, sizeof(Buffer), 0);
string test;
char ans;
while (recv(MySocket, &ans, 1, 0))
test.push_back(ans);
cout << test << endl;
return 0;
}

问题是我只能调用此方法一次。其他通话或注销方法的调用不起作用,例如:

int result = LogIn(logn, paswd);
int result = LogIn(logn, paswd);

不起作用,我只收到一个答案(第二个是空的,recv返回-1)

请帮忙,谢谢。

int BytesSent = send(MySocket, Buffer, sizeof(Buffer), 0);

这发送了太多的字节数据,在请求结束时,它认为它是下一个请求的一部分。

string data = "login=" + name + "&password=" + password;

最终没有&的查询。

"password=%s&", data.length(), name.c_str(), password.c_str());

这将&放在查询末端。好吧,是什么?

您需要修复两件事:

  1. 在查询末尾对&保持一致。(为什么无论如何都要两次撰写查询字符串?)

  2. 使用strlen(Buffer)代替sizeof(Buffer)

实际上,您应该使用实际协议规范的实现,而不是这样的代码。例如,如果密码中有&,会发生什么?如果服务器决定在答复中使用块编码,会发生什么?您实际上并未实施HTTP 1.1,但您声称自己这样做。这将迟早会导致很多痛苦。

您发送的字节太多,您没有正确地格式化消息的主体,也无法正确阅读响应。

如果您要使用C 进行某些字符串处理,则应将C 用于所有字符串处理,请避免使用C String Crestling。

尝试更多这样的东西:

const string SafeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*-._";
string Urlencode(const string &str)
{
    if (str.length() == 0)
        return string();
    ostringstream buffer;
    for (int I = 0; I < ASrc.length(); ++I)
    {
        char ch = ASrc[I];
        if (ch == ' ')
            buffer << '+';
        else if (SafeChars.find(ch) != string::npos)
            buffer << ch;
        else
            buffer << '%' << setw(2) << fillchar('0') << hex << ch;
    }
    return buffer.str();
}
int LogIn(const string &name, const string &password)
{
    string data = "login=" + Urlencode(name) + "&password=" + Urlencode(password);
    ostringstream buffer;
    buffer << "POST /Test/login_cl.php HTTP/1.1rn"
        << "Content-Length: " << data.length() << "rn"
        << "Connection: Keep-Alivern"
        << "Accept-Encoding: gziprn"
        << "Accept-Language: ru-RU,en,*rn"
        << "User-Agent: Mozilla/5.0rn"
        << "Host: 127.0.0.1rn"
        << "Content-Type: application/x-www-form-urlencodedrn"
        << "rn"    
        << data;
    string request = buffer.str(); 
    const char *req = request.c_str();
    int reqlen = request.length();
    do
    {
        int BytesSent = send(MySocket, request.c_str(), request.length(), 0);
        if (BytesSent <= 0)
            return -1;
        req += BytesSent;
        reqlen -= BytesSent;
    }
    while (reqlen > 0);
    // you REALLY need to flesh out this reading logic!
    // See RFC 2616 Section 4.4 for details
    string response;
    char ch;
    while (recv(MySocket, &ch, 1, 0) > 0)
        response += ch;
    cout << response << endl;
    return 0;
}

我将其作为一种练习,让您学习读取HTTP响应的正确方法(提示:它是一个 lot 更难的想法 - 尤其是因为您包括Accept-Encoding: gzipConnection: Keep-Alive标头,对响应处理有很大影响。阅读RFC 2616第4.4节,以获取详细信息如何确定响应长度和格式)。

话虽如此,http不是手工实现的琐碎协议,因此您确实应该使用预制的http库,例如libcurl,或使用Microsoft自己的WinInet或Winhttp Apis。