POST Winsock麻烦

问题描述:

现在我开始研究套接字了。但是我的双手无法正常工作。我有很酷的登录方法:POST Winsock麻烦

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.1\r 
"\nContent-Length: %d\r" 
"\nConnection: Keep-Alive\r" 
"\nAccept-Encoding: gzip\r" 
"\nAccept-Language: ru-RU,en,*\r" 
"\nUser-Agent: Mozilla/5.0\r" 
"\nHost: 127.0.0.1\r" 
"\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"  
"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,但你声称你是这样做的。迟早会导致很多很多的痛苦。

您发送的字节太多,您没有正确格式化POST消息的正文,而且您根本没有正确读取响应。

如果您打算使用C++进行某些字符串处理,那么您应该使用C++来处理所有字符串,避免混淆C字符串处理。

尝试一些更喜欢这个:

const string SafeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-._"; 

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.1\r\n" 
     << "Content-Length: " << data.length() << "\r\n" 
     << "Connection: Keep-Alive\r\n" 
     << "Accept-Encoding: gzip\r\n" 
     << "Accept-Language: ru-RU,en,*\r\n" 
     << "User-Agent: Mozilla/5.0\r\n" 
     << "Host: 127.0.0.1\r\n" 
     << "Content-Type: application/x-www-form-urlencoded\r\n" 
     << "\r\n"  
     << 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响应(提示的正确方法:it is a LOT harder then you think - 尤其是因为你是包括Accept-Encoding: gzipConnection: Keep-Alive这对响应处理有很大影响,请参阅RFC 2616 Section 4.4了解如何确定响应长度和格式)。这就是说,HTTP并不是一个手工实现的简单协议,所以你应该使用一个预制的HTTP库,比如libcurl,或者使用微软自己的WinInet或者WinHTTP APIs。

+0

谢谢,现在试图使用winhttp –