C++ Winsock P2P

Сценарий

У кого-либо есть какие-либо хорошие примеры одноранговых (p2p), объединяющийся в сеть в использовании C++ Winsock? Это - требование, которое я имею для клиента, который конкретно должен использовать эту технологию (бог знает почему). Я должен определить, выполнимо ли это.

Любая справка значительно ценилась бы.

Править

И я хотел бы избегать использования библиотек так, чтобы я мог понять базовый исходный код и далее мое знание.

10
задан Goober 16 May 2010 в 10:42
поделиться

2 ответа

Поскольку я не знаю, какую информацию вы ищете, я попытаюсь описать, как настроить программу сокетов и с какими ловушками я столкнулся.

Для начала прочтите руководство по Winsock из MSDN. Это базовая программа для подключения, отправки сообщения и отключения. Это отлично подходит для знакомства с программированием сокетов.

Итак, приступим:

Соображения:

блокирующая или неблокирующая

Во-первых, вам нужно определить, хотите ли вы блокирующую или неблокирующую программу. Большая разница в том, что если у вас есть графический интерфейс, вам нужно будет использовать неблокирующую или поточную обработку, чтобы программа не зависала. Я использовал блокирующие вызовы, но всегда вызывал select перед вызовом блокирующих функций (подробнее о выборе позже).Таким образом, я избегаю потоков, мьютексов и прочего, но все же использую базовые вызовы accept , send и receive .

Вы не можете рассчитывать на то, что ваши посылки будут доставлены именно так, как вы их отправили!

Вы тоже не можете повлиять на это. Это была самая большая проблема, с которой я столкнулся, в основном потому, что сетевая карта может решать, какую информацию отправлять и когда ее отправлять. Я решил это сделать, создав networkPackageStruct , содержащий размер и данные , где размер - это общий объем данных в этом пакете. Обратите внимание, что отправляемое вами сообщение может быть разделено на 2 или более сообщений, а также может быть объединено с другим отправляемым вами сообщением.

Учтите следующее: Вы отправляете два сообщения

"Hello"
"World!"

Если вы отправляете эти два сообщения с помощью функции send , ваша функция recv может не получить их в таком виде. Это может выглядеть так:

"Hel"
"loWorld!"

или, возможно,

"HelloWorld!"

, какова бы ни была основная сеть…

Регистрируйте (почти) все!

Отладка сетевой программы трудна, потому что у вас нет полного контроля над ней (поскольку она находится на двух компьютерах). Если вы столкнетесь с операцией блокировки, вы ее тоже не увидите. Это также можно было бы назвать «Знайте свой код блокировки». Когда одна сторона отправляет что-то, вы не знаете, будет ли оно доставлено другой стороне, поэтому следите за тем, что отправлено и что получено.

Обратите внимание на ошибки сокета

функции winsock возвращают много информации. Знайте свою функцию WSAGetLastError () .Я не буду хранить его в примерах ниже, но учтите, что они, как правило, возвращают много информации. Каждый раз, когда вы получаете SOCKET_ERROR или INVALID_SOCKET , проверьте Сообщения об ошибках Winsock , чтобы найти его

Настройка соединения:

Поскольку вы этого не сделали нужен сервер, всем клиентам потребуется прослушивающий сокет для приема новых подключений. Самый простой:

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 великолепен - он фактически заставляет ваш сокет прослушивать все ваши сети, а не только один IP-адрес.

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

А вот и самое интересное. bind и listen не будут блокировать, но accept заблокирует. Уловка состоит в том, чтобы использовать выберите , чтобы проверить, есть ли входящее соединение. Таким образом, приведенный выше код предназначен только для настройки сокета. в вашем программном цикле вы проверяете наличие новых данных в сокете.

Обмен данными

Я решил, что нужно использовать select много раз. В основном вы видите, есть ли что-нибудь, на что вам нужно ответить на любом из ваших сокетов. Это делается с помощью функций 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

в newSocket теперь у вас есть новый узел. Так что это было для получения данных. Но обратите внимание! send тоже блокируется! Одна из полученных мною "ошибок чесания головы" заключалась в том, что send заблокировал меня. Однако это также было решено с помощью 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
 }

Завершение работы

Наконец, есть два способа завершить работу. Вы либо просто отключаетесь, закрыв вашу программу, либо вызываете функцию shutdown .

  • Вызов выключения заставит ваш партнер выбрать триггер . recv , однако, не получит никаких данных, а вместо этого вернет 0. Я не заметил другого случая, когда recv возвращает 0, поэтому (в некоторой степени) безопасно сказать, что это может считаться кодом выключения.Вызов shutdown - это самый приятный поступок.
  • Завершение соединения без вызова shutdown - это бессердечно, но, конечно, работает. Вам все равно нужно обработать ошибку, даже если вы используете shutdown , поскольку это может быть не ваша программа, которая закрывает соединение. Следует запомнить код ошибки 10054, который представляет собой WSAECONNRESET: сброс соединения одноранговым узлом. .
37
ответ дан 3 December 2019 в 13:54
поделиться

Если вы просто хотите реализовать приложение P2P в Microsoft Windows, вы можете попробовать Одноранговую сеть Windows

. Если вы хотите реализовать новый протокол P2P для самостоятельно, вы можете изучить протокол eMule и исходный код eMule . Вы можете сделать что-то еще, если посмотрите исходный код Shareaza , это eMule / Guntella / Gnutella / BitTorrent.

2
ответ дан 3 December 2019 в 13:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: