[英]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.