2012-07-25 99 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