2012-07-25 65 views
1

我正在寫一個bittorrent客戶端,需要通過tcp連接聯繫多個跟蹤器。爲了做到這一點,我寫了如下一個Winsock包裝類:Winsock發送失敗,錯誤10093

class trackerSocket{ 
public: 
    ~trackerSocket(); 

    int trackerInitialize(string address); 
    int trackerSend(string getParams); 
    int trackerRecv(); 

    be_node *responseDict; 
    bool working; 

private: 
    string address; 
    string port; 
    string protocol; 
    string page; 
    SOCKET ConnectSocket; 

    int parseAnnounce(string announce); 
    int parseTrackerResponse(string response); 
}; 

程序開始通過給一個變量分配一個新的trackerSocket類。 trackerInitialize函數在這個函數上被調用,如果成功的話,這個類被壓入一個向量來存儲所有工作的跟蹤器。這裏是trackerInitialize函數:

int trackerSocket::trackerInitialize(string announce){ 
    WSADATA wsaData; 
    int iResult; 

    working = true; 

    iResult = parseAnnounce(announce); 
    if(iResult != 0){ 
     working = false; 
     return iResult; 
    } 

    //Initialize Winsock 
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
    if(iResult != 0){ 
     return 1; 
    } 

    struct addrinfo *result = NULL, 
        *ptr = NULL, 
        hints; 

    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 

    //Resolve the server address and port 
    iResult = getaddrinfo(address.c_str(), port.c_str(), &hints, &result); 
    if(iResult != 0){ 
     WSACleanup(); 
     return 1; 
    } 

     ConnectSocket = INVALID_SOCKET; 

    //Attempt to connect to the first address returned by 
    //the call to getaddrinfo 
    ptr = result; 

    do{ 
     //Create a socket for connecting to the server 
     ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 
     if(ConnectSocket == INVALID_SOCKET){ 
      ptr = ptr->ai_next; 
      continue; 
     } 

     //Connect to server 
     iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); 
     if(iResult != SOCKET_ERROR){ 
      break; 
     } else { 
      closesocket(ConnectSocket); 
      ConnectSocket = INVALID_SOCKET; 
      ptr = ptr->ai_next; 
     } 
    } while(ptr != NULL); 

    freeaddrinfo(result); 
    if(ConnectSocket == INVALID_SOCKET){ 
     working = false; 
     WSACleanup(); 
     return 1; 
    } 

    return 0; 
} 

然後程序執行代碼來生成消息發送給跟蹤器。對於向量中的每個跟蹤器類是trackerSend函數被調用的消息,這裏是trackerSend功能:

int trackerSocket::trackerSend(string getParams){ 
    int iResult; 

    ostringstream os; 
    os << "GET " << page << getParams << " HTTP/1.1\r\n" 
     << "Host: " << address << "\r\n" 
     << "Accept: text/html\r\n" 
     << "\r\n"; 

    string sendBuf = os.str(); 

    //Send tracker request 
    iResult = send(ConnectSocket, sendBuf.c_str(), strlen(sendBuf.c_str()), 0); 
    if(iResult == SOCKET_ERROR){ 
     working = false; 
     closesocket(ConnectSocket); 
     WSACleanup(); 
     return 1; 
    } 

    return 0; 
} 

每次程序運行發送函數返回-1爲每一個跟蹤器。如果我調用WSAGetLastError()函數,則返回10093.此錯誤的msdn定義爲:

成功的WSAStartup尚未執行。 應用程序未調用WSAStartup或WSAStartup失敗。應用程序可能正在訪問當前活動任務不擁有的套接字(即試圖在任務之間共享套接字),或者WSACleanup被調用了太多次。

我看不到WSACleanup被調用的次數太多,所以我只能假定套接字不屬於當前活動任務(不知道這意味着什麼),任何人都可以看到問題嗎?

繼承人一些主程序代碼(我已如上所述)的:

//Store tracker URL's in vector 
vector<trackerSocket> trackers; 
trackerSocket *temptracker = new trackerSocket(); 
iResult = temptracker->trackerInitialize(announce); 
if(iResult == 0){ 
    trackers.push_back(*temptracker); 
} 
if(announcelist != NULL){ 
    i = 0; 
    while(announcelist[i]){ 
     if(strcmp(announcelist[i]->val.l[0]->val.s, announce.c_str()) != 0){ 
      temptracker = new trackerSocket(); 
      iResult = temptracker->trackerInitialize(announcelist[i]->val.l[0]->val.s); 
      if(iResult == 0){ 
       trackers.push_back(*temptracker); 
      } 
     } 
     i++; 
    } 
} 

//Check that at least one of the tracker URL's was valid 
if(trackers.size() == 0){ 
    printf("None of the tracker URL's provided were valid.\n"); 
    return 1; 
} 

//Generate some required values 
string peerid = genPeerID(); 
string peerport = "12345"; 
int uploaded = 0; 
int downloaded = 0; 

//Work out how many bytes are left to download 
int left = 0; 
if(singlefile){ 
    left = length; 
} else { 
    for(i = 0; i < filesinfo.size(); i++){ 
     left += filesinfo[i].length; 
    } 
} 

//Send GET Request to tracker 
i = 0; 
ostringstream os; 
string getParams; 
string response; 
os << "info_hash=" << infohash << "&peer_id=" << peerid << "&port=" << peerport << 
    "&uploaded=" << uploaded << "&downloaded=" << downloaded << "&event=started"; 

getParams = os.str(); 
do{  
    iResult = trackers[i].trackerSend(getParams); 
    if(iResult != 0){ 
     printf("trackerSend %d failed: %d\n", i, iResult); 
     i++; 
     continue; 
    } 
} while(i < trackers.size()); 
+0

有沒有什麼辦法可以凝聚你的問題是它的1/4是當前長度?它現在的方式似乎有太多的信息(我厭倦了閱讀它...) – YePhIcK 2012-07-25 12:06:03

+0

我以爲有人可能會說:(不幸的是,我不知道程序中的錯誤所在,所以我必須包括我認爲可能包含的所有代碼,我盡我所能包含了我認爲最相關的代碼 – brnby 2012-07-25 12:30:00

回答

0

我已經設法從代碼中休息一下後發現問題。我認爲,問題出在這太問題描述和回答:

C++ vector of objects vs. vector of pointers to objects

你必須知道關於C++的載體是什麼,他們必須使用類的對象的複製經營者是能夠將它們輸入到矢量中。如果在這些對象中有內存分配,當調用析構函數時會自動解除分配,這可以解釋您的問題:將對象複製到向量中然後銷燬。

如果在對象類中有一個指向分配緩衝區的指針,此對象的副本將指向同一個緩衝區(如果使用默認的複製操作符)。如果析構函數解除分配緩衝區,那麼當複製析構函數被調用時,原始緩衝區將被解除分配,因此您的數據將不再可用。

如果您使用指針,因爲您通過new/destroy控制元素的生命期,並且矢量函數僅將複製指針指向您的元素,則不會發生此問題。

將矢量更改爲存儲指向trackerSocket類的指針,而不是隻存儲trackerSocket類的副本,並更改​​對矢量(.to - >)中trackerSocket函數的調用後,問題已成功解決。下面是我所做的更改:

老:

vector<trackerSocket> trackers; 
trackers.push_back(*temptracker); 
trackers[i].trackerSend(getParams); 

新:

vector<trackerSocket*> trackers; 
trackers.push_back(temptracker); 
trackers[i]->trackerSend(getParams); 
2

從你的代碼不應該調用WSACleanup上發送,如果一個跟蹤無法發送,您將會減少內部計數器,如果它達到0,系統將需要一個新的WSAStartup,你沒有調用...

我建議你只打一次WSAStartup(例如在應用程序的開始處),只有一個時間WSACleanup。 (例如應用程序結束)

+0

但是,trackerInitialize函數在每次調用時調用WSAStartup,對於每個我相信的跟蹤器和WSACleanup我認爲WSACleanup被調用的次數不會超過WSAStartup,但我可能是錯誤的 – brnby 2012-07-25 13:34:23

+0

您可以在do {...}中發佈while條件嗎? – 2012-07-25 13:45:03

+0

代碼調用WSACleanup的次數太多。它類WSAStartup一次,但調用WSACleanup每個連接一次。 – 2012-07-25 13:48:46