C++ Winsock P2P

Goo*_*ber 10 c++ p2p winsock distributed-computing winsockets

脚本

有没有人在使用Winsock的C++中有任何良好的点对点(p2p)网络示例?对于特别需要使用这种技术的客户来说,这是一个要求(天知道为什么).我需要确定这是否可行.

任何帮助将不胜感激.

编辑

我想避免使用库,这样我就可以理解底层的源代码并进一步了解我的知识.

Def*_*ult 37

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

首先,阅读 MSDN Winsock教程.这是连接,发送消息和断开连接的基本程序.这对于了解套接字编程非常有用.

有了它,让我们开始:

注意事项:

阻止或非阻塞

首先,您需要确定是否需要阻止或非阻塞程序.最大的区别是,如果你有一个GUI,你需要使用非阻塞或线程,以免冻结程序.我这样做的方法是使用阻塞调用,但select在调用阻塞函数之前总是调用(稍后再选择).这样,我避免线程和互斥的和诸如此类的东西,但仍使用基本的accept,sendreceive 电话.

您不能依赖于您的包裹将以您发送的方式到达!

你对此也没有影响.这是我遇到的最大问题,主要是因为网卡可以决定发送什么信息以及何时发送.我解决它的方法是使一networkPackageStruct,含有sizedata,其中大小是在该包数据的总amound.请注意,您发送的邮件可以拆分为2条或更多邮件,也可以与您发送的其他邮件合并.

请考虑以下事项:您发送两条消息

"Hello"
"World!"
Run Code Online (Sandbox Code Playgroud)

当您使用该send功能发送这两条消息时,您的recv功能可能不会像这样.它可能看起来像这样:

"Hel"
"loWorld!"
Run Code Online (Sandbox Code Playgroud)

也许

"HelloWorld!"
Run Code Online (Sandbox Code Playgroud)

无论底层网络是什么感觉..

记录(几乎)一切!

调试网络程序很难,因为你没有完全控制它(因为它在两台计算机上).如果你遇到阻塞操作,你也看不到它.这也可以称为"了解你的阻止代码".当一方发送的东西你不知道它是否会到达另一方时,所以要跟踪发送的内容和收到的内容.

注意套接字错误

winsock函数返回很多信息.了解你的WSAGetLastError()功能.我将不会在下面的示例中保留它,但请注意它们往往会返回很多信息.每次你得到SOCKET_ERRORINVALID_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;
Run Code Online (Sandbox Code Playgroud)

INADDR_ANY很棒 - 它实际上让你的套接字监听所有网络,而不只是一个ipaddress.

bind(s, (SOCKADDR*)&localAddress, sizeof(localAddress));
listen(s, SOMAXCONN);
Run Code Online (Sandbox Code Playgroud)

这是有趣的部分.bind并且listen不会阻止但是accept会.诀窍是用来select检查是否有传入连接.所以上面的代码就是设置套接字.在程序循环中,检查socket中的新数据.

交换数据

我解决它的方法是使用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
Run Code Online (Sandbox Code Playgroud)

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
 }
Run Code Online (Sandbox Code Playgroud)

关机

最后,有两种方法可以关闭.您可以通过关闭程序来断开连接,也可以调用该shutdown功能.

  • 调用shutdown将使您的对等select触发器.recv然而,它将不会收到任何数据,但会返回0.我没有注意到任何其他recv返回0的情况,所以可以(有点)安全地说这可以被视为关闭代码.打电话shutdown是最好的事情..
  • 在不调用关机的情况下关闭连接只是冷酷无情,但当然有效.即使您使用shutdown,仍然需要处理错误,因为它可能不是您的程序关闭连接.要记住的好错误代码是10054,即WSAECONNRESET:由对等方重置连接..