2014-01-27 31 views
0

現在我開始研究套接字了。但是我的雙手無法正常工作。我有很酷的登錄方法: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)

請幫忙,謝謝。

回答

2
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,但你聲稱你是這樣做的。遲早會導致很多很多的痛苦。

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 –