C++ Winsock P2P

Scenariusz

Czy ktoś ma jakieś dobre przykłady sieci peer-to-peer (p2p) w C++ używając Winsock? Jest to wymóg, który mam dla klienta, który konkretnie musi korzystać z tej technologii (Bóg wie dlaczego). Muszę ustalić, czy jest to wykonalne.

Każda pomoc będzie bardzo mile widziana.

EDIT

I chciałbym unikać używania bibliotek, aby zrozumieć podstawowy kod źródłowy i poszerzyć swoją wiedzę.

Author: Goober, 2010-05-16

2 answers

Ponieważ Nie wiem, jakich informacji szukasz, postaram się opisać, jak skonfigurować program socket i jakie pułapki napotkałem.

Na początek, przeczytaj Winsock tutorial Z MSDN. Jest to podstawowy program do łączenia, wysyłania wiadomości i rozłączania. Świetnie nadaje się do programowania gniazd.

Z tym, zacznijmy:

Rozważania:

Blokowanie lub nie blokowanie

Po pierwsze, ty byś musisz określić, czy chcesz program blokujący lub nieblokujący. Duża różnica polega na tym, że jeśli masz GUI, musisz użyć nieblokującego lub wątkowego, aby nie zamrozić programu. Sposób, w jaki to zrobiłem, polegał na użyciu połączeń blokujących, ale zawsze wywołanie select przed wywołaniem funkcji blokujących(więcej na select później). W ten sposób unikam threadingu i mutex ' a i tak dalej, ale nadal używam podstawowego accept, send i receive Telefony.

Nie możesz polegać na tym, że twoje pakiety będą przyjedź tak, jak je wysyłasz!

Na to też nie masz wpływu. To był największy problem, na który natknąłem się, w zasadzie dlatego, że karta sieciowa może zdecydować, jakie informacje wysłać i kiedy ją wysłać. Sposób, w jaki go rozwiązałem, polegał na stworzeniu networkPackageStruct, zawierającego size i data, gdzie size jest całkowitą ilością danych w tym pakiecie. Należy pamiętać, że wysyłaną wiadomość można podzielić na 2 lub więcej wiadomości i można ją również połączyć z inną wysyłaną wiadomością.

Rozważmy po: Wysyłasz dwie wiadomości

"Hello"
"World!"

Kiedy wyślesz te dwie wiadomości za pomocą funkcji send, twoja funkcja recv może ich nie otrzymać w ten sposób. Może to wyglądać tak:

"Hel"
"loWorld!"

A może

"HelloWorld!"

Niezależnie od tego, jak się czuje sieć bazowa..

Zaloguj (prawie) wszystko!

Debugowanie programu sieciowego jest trudne, ponieważ nie masz nad nim pełnej kontroli (ponieważ jest na dwóch komputerach). Jeśli napotkasz operację blokowania, nie możesz jej zobaczyć ani jedno, ani drugie. Równie dobrze można to nazwać "Poznaj swój kod blokujący".. Kiedy jedna strona wysyła coś, nie wiesz, czy dotrze po drugiej stronie, więc śledź to, co jest wysyłane i co jest odbierane.

Zwróć uwagę na błędy gniazd

Funkcje Winsock zwracają wiele informacji. Poznaj swoją WSAGetLastError() funkcję. Nie będę go przechowywać w poniższych przykładach, ale zauważ, że mają tendencję do zwracania wielu informacji. Za każdym razem, gdy pojawi się SOCKET_ERROR lub INVALID_SOCKET sprawdź błąd Winsock Wiadomości aby to sprawdzić

Konfiguracja połączenia:

Ponieważ nie chcesz serwera, wszyscy klienci potrzebowaliby gniazda nasłuchowego, aby akceptować nowe połączenia. Najprostszym jest:

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in localAddress;
localAddress.sinfamily = AF_INET;
localAddress.sin_port = htons(10000);  // or whatever port you'd like to listen to
localAddress.sin_addr.s_addr = INADDR_ANY;

INADDR_ANY jest świetny - w rzeczywistości sprawia, że twoje gniazdo nasłuchuje we wszystkich sieciach, zamiast tylko jednego ipaddress.

bind(s, (SOCKADDR*)&localAddress, sizeof(localAddress));
listen(s, SOMAXCONN);

Nadchodzi interesująca część. bind i listen nie będą blokować, ale accept będą. Sztuczka polega na użyciu select, aby sprawdzić, czy nadchodzi połączenie. Powyższy kod służy tylko do Ustawienia gniazda. w pętli programu sprawdzasz nowe dane w socket.

Wymiana danych

Sposób, w jaki to rozwiązałem, polegał na użyciu select dużo. Zasadniczo widzisz, czy jest coś, na co musisz odpowiedzieć na którymś z gniazd. Odbywa się to za pomocą funkcji FD_xxx.

// receiving data
fd_set mySet;
FD_ZERO(&mySet);
FD_SET(s, &mySet);
// loop all your sockets and add to the mySet like the call above
timeval zero = { 0, 0 };
int sel = select(0, &mySet, NULL, NULL, &zero);
if (FD_ISSET(s, &mySet)){
     // you have a new caller
     sockaddr_in remote;
     SOCKET newSocket = accept(s, (SOCKADDR*)&remote, sizeof(remote));
 }
 // loop through your sockets and check if they have the FD_ISSET() set

W newSocket masz teraz nowego partnera. Więc to było do odbierania danych. ale uwaga! send blokuje też! Jeden z "drapanie głowy błędy " dostałem, że send zablokował mnie. Zostało to jednak również rozwiązane za pomocą select.

 // sending data
 // in: SOCKET sender
 fd_set mySet;
 FD_ZERO(&mySet);
 FD_SET(sender, &mySet);
 timeval zero = { 0, 0 };
 int sel = select(0, NULL, mySet, NULL, &zero);
 if (FD_ISSET(sender, &mySet)){
      // ok to send data
 }

Zamykanie

Wreszcie, są dwa sposoby wyłączenia. Albo po prostu się rozłączasz, zamykając swój program, albo wywołujesz funkcję shutdown.

    Wywołanie shutdown spowoduje, że twój partner uruchomi się. recv nie otrzyma żadnych danych, lecz zwróci 0. Nie zauważyłem żadnego innego przypadku, w którym recv zwraca 0, więc można (nieco) bezpiecznie powiedzieć, że to można uznać za Kod zamykający. wołanie jest najmilszą rzeczą do zrobienia..
  • wyłączenie połączenia bez wywołania shutdown jest bezduszne, ale oczywiście działa. Nadal musisz obsłużyć błąd, nawet jeśli używasz shutdown, ponieważ może to nie twój program zamyka połączenie. Dobrym kodem błędu do zapamiętania jest 10054, który jest WSAECONNRESET: reset połączenia przez peera..
 36
Author: Default,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-02 09:16:29

Jeśli chcesz zaimplementować aplikację P2P na Microsoft Windows, możesz spróbować z Windows Peer-to-Peer Networking

Jeśli chcesz zaimplementować nowy protokół P2P, możesz przestudiować protokół eMule oraz kod źródłowy eMule . Możesz zrobić więcej, jeśli spojrzysz na kod źródłowy Shareaza , robi to eMule/Guntella/Gnutella / BitTorrent.

 2
Author: Yi Zhao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-18 06:02:32