簡體   English   中英

C ++ Winsock P2P

[英]C++ Winsock P2P

腳本

有沒有人在使用Winsock的C ++中有任何良好的點對點(p2p)網絡示例? 對於特別需要使用這種技術的客戶來說,這是一個要求(天知道為什么)。 我需要確定這是否可行。

任何幫助將不勝感激。

編輯

我想避免使用庫,這樣我就可以理解底層的源代碼並進一步了解我的知識。

由於我不知道您正在尋找什么信息,我將嘗試描述如何設置套接字程序以及我遇到的陷阱。

首先, 閱讀 MSDN Winsock教程 這是連接,發送消息和斷開連接的基本程序。 這對於了解套接字編程非常有用。

有了它,讓我們開始:

注意事項:

阻止或非阻塞

首先,您需要確定是否需要阻止或非阻塞程序。 最大的區別是,如果你有一個GUI,你需要使用非阻塞或線程,以免凍結程序。 我做的方式,它是使用阻塞調用,但總是調用select調用(在某些后來更多),該閉鎖功能之前。 這樣我就可以避免使用線程和互斥鎖等但仍然使用基本的acceptsendreceive調用。

您不能依賴於您的包裹將以您發送的方式到達!

你對此也沒有影響。 這是我遇到的最大問題,主要是因為網卡可以決定發送什么信息以及何時發送它。 我解決它的方法是創建一個networkPackageStruct ,其中包含sizedata ,其中size是該包中數據的總量。 請注意,您發送的郵件可以拆分為2條或更多郵件,也可以與您發送的其他郵件合並。

請考慮以下事項:您發送兩條消息

"Hello"
"World!"

當您使用send函數發送這兩條消息時,您的recv函數可能不會像這樣得到它們。 它可能看起來像這樣:

"Hel"
"loWorld!"

也許

"HelloWorld!"

無論底層網絡是什么感覺..

記錄(幾乎)一切!

調試網絡程序很難,因為你沒有完全控制它(因為它在兩台計算機上)。 如果你遇到阻塞操作,你也看不到它。 這也可以稱為“了解你的阻止代碼”。當一方發送的東西你不知道它是否會到達另一方時,所以要跟蹤發送的內容和收到的內容。

注意套接字錯誤

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;

INADDR_ANY很棒 - 它實際上讓你的套接字監聽所有網絡,而不只是一個ipaddress。

bind(s, (SOCKADDR*)&localAddress, sizeof(localAddress));
listen(s, SOMAXCONN);

這是有趣的部分。 bindlisten不會阻止但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功能。

  • 調用shutdown將使您的peer 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM