C ++ Winsock P2P

问题描述 投票:10回答:3

场景

有人使用Winsock在C ++中有任何很好的对等(p2p)网络示例吗?对于有特殊需要使用此技术的客户,这是我的要求(上帝知道原因)。我需要确定这是否可行。

任何帮助将不胜感激。

编辑

而且我想避免使用库,以便我可以理解底层的源代码并进一步了解我的知识。

c++ winsock p2p distributed-computing winsockets
3个回答
37
投票

由于我不知道您要寻找什么信息,所以我将尝试描述如何设置套接字程序以及遇到的陷阱。

首先,从MSDN 读取Winsock tutorial。这是连接,发送消息和断开连接的基本程序。很好地了解套接字编程。

有了,让我们开始:

注意事项:

阻止或不阻止

首先,您需要确定是要阻止程序还是非阻止程序。最大的区别是,如果您具有GUI,则需要使用非阻塞或线程化方式才能冻结程序。我这样做的方法是使用阻塞调用,但是总是在调用阻塞函数之前先调用select(稍后会详细介绍)。这样,我避免使用线程和互斥锁,但仍然使用基本的acceptsendreceive调用。

您不能依靠您的包裹会以您发送包裹的方式到达!

您对此也没有影响。这是我遇到的最大问题,基本上是因为网卡可以决定发送什么信息以及何时发送信息。我解决的方法是制作一个networkPackageStruct,其中包含sizedata,其中size是该程序包中数据的总量。请注意,您发送的一条消息可以分为2条或更多条消息,也可以与您发送的另一条消息合并。

请考虑以下内容:您发送了两条消息

"Hello"
"World!"

[使用send功能发送这两条消息时,recv功能可能不会像这样得到它们。它可能看起来像这样:

"Hel"
"loWorld!"

或者也许

"HelloWorld!"

基础网络的感觉如何。.

记录(几乎)所有内容!

调试网络程序很困难,因为您不能完全控制它(因为它在两台计算机上)。如果您遇到阻止操作,您也将看不到它。这也可以称为“知道您的阻止代码”。当一侧发送某些消息时,您不知道它是否会到达另一侧,因此请跟踪发送的内容和接收的内容。

请注意套接字错误

winsock函数返回大量信息。了解您的WSAGetLastError()功能。我不会在下面的示例中保留它,但是请注意,它们倾向于返回大量信息。每当您收到SOCKET_ERRORINVALID_SOCKET时,请检查Winsock Error Messages进行查找

建立连接:

由于您不需要服务器,因此所有客户端都需要一个侦听套接字来接受新连接。最简单的是:

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);

这里是有趣的部分。 bindlisten不会阻止,但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:对等方重置连接。

2
投票

如果只想在Microsoft Windows上实现P2P应用程序,则可以尝试使用Windows Peer-to-Peer Networking

如果要实现自己的新P2P协议,则可以研究eMule协议,然后单击eMule source code。如果您查看Shareaza source code,则可以做进一步的工作,它可以执行eMule / Guntella / Gnutella / BitTorrent。


0
投票

我正在使用Visual Studio 19,每当我运行winsock教程中的服务器文件时,命令行完全空白,并且不执行任何操作。客户端可以工作,但是无法连接。帮助使其正常工作?

© www.soinside.com 2019 - 2024. All rights reserved.