C++ Winsock P2P

сценарий

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

Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ

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

2 ответа

Решение

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

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

С этого давайте начнем:

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

блокирующий или неблокирующий

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам