私は bittorrent クライアントを作成しており、tcp 接続を介して複数のトラッカーに接続する必要があります。これを行うために、以下に示す winsock ラッパー クラスを作成しました。
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;
}
プログラムが実行されるたびに、send 関数はトラッカーごとに -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());