[英]C++ Winsock P2P
有没有人在使用Winsock的C ++中有任何良好的点对点(p2p)网络示例? 对于特别需要使用这种技术的客户来说,这是一个要求(天知道为什么)。 我需要确定这是否可行。
任何帮助将不胜感激。
我想避免使用库,这样我就可以理解底层的源代码并进一步了解我的知识。
首先, 阅读 MSDN 的Winsock教程 。 这是连接,发送消息和断开连接的基本程序。 这对于了解套接字编程非常有用。
有了它,让我们开始:
首先,您需要确定是否需要阻止或非阻塞程序。 最大的区别是,如果你有一个GUI,你需要使用非阻塞或线程,以免冻结程序。 我做的方式,它是使用阻塞调用,但总是调用select
调用(在某些后来更多),该闭锁功能之前。 这样我就可以避免使用线程和互斥锁等但仍然使用基本的accept
, send
和receive
调用。
你对此也没有影响。 这是我遇到的最大问题,主要是因为网卡可以决定发送什么信息以及何时发送它。 我解决它的方法是创建一个networkPackageStruct
,其中包含size
和data
,其中size是该包中数据的总量。 请注意,您发送的邮件可以拆分为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
来检查是否有传入连接。 所以上面的代码就是设置套接字。 在程序循环中,检查socket中的新数据。
我解决它的方法是使用select
alot。 基本上你可以看到你的套接字上是否有任何需要回应的东西。 这是通过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:由对等方重置连接。 。 如果您只想在Microsoft Windows上实现P2P应用程序,可以尝试使用Windows对等网络
如果您想实现自己的新P2P协议,可以学习eMule协议和eMule源代码 。 如果你查看Shareaza源代码 ,你可以做更多,它做eMule / Guntella / Gnutella / BitTorrent。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.