Goo*_*ber 10 c++ p2p winsock distributed-computing winsockets
有没有人在使用Winsock的C++中有任何良好的点对点(p2p)网络示例?对于特别需要使用这种技术的客户来说,这是一个要求(天知道为什么).我需要确定这是否可行.
任何帮助将不胜感激.
我想避免使用库,这样我就可以理解底层的源代码并进一步了解我的知识.
Def*_*ult 37
首先,阅读 MSDN 的Winsock教程.这是连接,发送消息和断开连接的基本程序.这对于了解套接字编程非常有用.
有了它,让我们开始:
首先,您需要确定是否需要阻止或非阻塞程序.最大的区别是,如果你有一个GUI,你需要使用非阻塞或线程,以免冻结程序.我这样做的方法是使用阻塞调用,但select在调用阻塞函数之前总是调用(稍后再选择).这样,我避免线程和互斥的和诸如此类的东西,但仍使用基本的accept,send和receive 电话.
你对此也没有影响.这是我遇到的最大问题,主要是因为网卡可以决定发送什么信息以及何时发送.我解决它的方法是使一networkPackageStruct,含有size和data,其中大小是在该包数据的总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_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;
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功能.
select触发器.recv然而,它将不会收到任何数据,但会返回0.我没有注意到任何其他recv返回0的情况,所以可以(有点)安全地说这可以被视为关闭代码.打电话shutdown是最好的事情..shutdown,仍然需要处理错误,因为它可能不是您的程序关闭连接.要记住的好错误代码是10054,即WSAECONNRESET:由对等方重置连接..