UDP打洞程序包的源碼

C#實現UDP打洞

轉自:http://hi.baidu.com/sdfiyon/blog/item/63a6e039155e02f23a87ceb1.html

下面是UDP打洞程序包的源碼:
//WellKnown公用庫
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net ;
using System.Net .Sockets ;
using System.Collections ;

namespace P2PWellKnown
{
/// <summary>
?????? /// UDP用戶登錄事件委托
/// </summary>
/// <param name="sender">事件源對象</param>
/// <param name="e">事件實體</param>
public delegate void UdpUserLogInDelegate(object sender,UDPSockEventArgs e);

?????? /// <summary>
?????? /// 一般UDP消息事件委托
?????? /// </summary>
?????? /// <param name="sender">事件源對象</param>
?????? /// <param name="e">事件實體</param>
?????? public delegate void UdpMessageDelegate(object sender,UDPSockEventArgs e);

?????? /// <summary>
?????? /// 初始化一個新連接的事件委托
?????? /// </summary>
?????? /// <param name="sender">事件源對象</param>
?????? /// <param name="e">事件實體</param>
?????? public delegate void UdpNewConnectDelegate(object sender,UDPSockEventArgs e);

/// <summary>
/// P2P共享數據類
/// </summary>
public class P2PConsts
{
???? /// <summary>
???? /// UDP服務器監聽端口
???? /// </summary>
???? public const int UDP_SRV_PORT???? = 2280;

???? /// <summary>
???? ///TCP服務器監聽端口
???? /// </summary>
???? public const int TCP_SRV_PORT =2000;
}

???

/// <summary>
/// FormatterHelper 序列化,反序列化消息的幫助類
/// </summary>
public class FormatterHelper

{

???? public static byte[] Serialize(object obj)

???? {

????? BinaryFormatter binaryF = new BinaryFormatter();

????? MemoryStream ms = new MemoryStream(1024*10);

????? binaryF.Serialize(ms, obj);

????? ms.Seek(0, SeekOrigin.Begin);

????? byte[] buffer = new byte[(int)ms.Length];

????? ms.Read(buffer, 0, buffer.Length);

????? ms.Close();

????? return buffer;

???? }

?

???? public static object Deserialize(byte[] buffer)

???? {

????? BinaryFormatter binaryF = new BinaryFormatter();

????? MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length, false);

????? object obj = binaryF.Deserialize(ms);

????? ms.Close();

????? return obj;

???? }

}

?

/// <summary>
/// 用于承載UDPSock信息的事件類
/// </summary>
public class UDPSockEventArgs:EventArgs
{
???? /// <summary>
???? /// 要承載的消息
???? /// </summary>
???? private string m_strMsg;

???? /// <summary>
???? /// 用戶信息
???? /// </summary>
???? private string m_strUserName;


?????????? /// <summary>
?????????? /// 觸發該事件的公共終端
?????????? /// </summary>
?????????? private IPEndPoint m_EndPoint;


???? /// <summary>
???? /// 初始化UDPSock事件
???? /// </summary>
???? /// <param name="sMsg">用戶發送的信息</param>
???? public UDPSockEventArgs(string sMsg):base()
???? {
????? this.m_strMsg =sMsg;
???? }

???? /// <summary>
???? /// 遠端用戶名
???? /// </summary>
???? public string RemoteUserName
???? {
????? get
????? {
?????? return m_strUserName;
????? }
????? set
????? {
?????? m_strUserName=value;
????? }
???? }


?????????? /// <summary>
?????????? /// 一般套接字消息
?????????? /// </summary>
?????????? public string SockMessage
?????????? {
?????????????? get
?????????????? {
?????????????????? return m_strMsg;
?????????????? }
?????????????? set
?????????????? {
?????????????????? m_strMsg = value;
?????????????? }
?????????? }


?????????? /// <summary>
?????????? /// 公共遠端節點
?????????? /// </summary>
?????????? public IPEndPoint RemoteEndPoint
?????????? {
?????????????? get
?????????????? {
?????????????????? return m_EndPoint;
?????????????? }
?????????????? set
?????????????? {
?????????????????? m_EndPoint = value;
?????????????? }
?????????? }
}
}

?

//UDPP2PSock.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using P2PWellKnown;

namespace UDPP2P
{
?????? /// <summary>
?????? /// UDPP2P套接字管理類
?????? /// </summary>
?????? public class UDPP2PSock
?????? {
?????????? /// <summary>
?????????? /// 用戶登錄事件
?????????? /// </summary>
?????????? public event UdpUserLogInDelegate OnUserLogInU;

?????????? /// <summary>
?????????? /// 一般UDP消息事件
?????????? /// </summary>
?????????? public event UdpMessageDelegate OnSockMessageU;

?????????? /// <summary>
?????????? /// 初始化一個新連接事件
?????????? /// </summary>
?????????? public event UdpNewConnectDelegate OnNewConnectU;

?????????? /// <summary>
?????????? /// UDP服務器
?????????? /// </summary>
?????????? private UdpClient m_udpServer;

?????????? /// <summary>
?????????? /// UDP客戶端
?????????? /// </summary>
?????????? private UdpClient m_udpClient;

?????????? /// <summary>
?????????? /// 服務器實際上在本地機器上監聽的
?????????? /// 端口,用于當一臺計算機上同時啟
?????????? /// 動兩個可兩以上服務器進程時,標
?????????? /// 識不同的服務器進程
?????????? /// </summary>
?????????? private int m_iMyServerPort;

?????????? /// <summary>
?????????? /// 客戶端在本地機器上實際使用的端口,
?????????? /// 用于當一臺計算機上同時有兩個或兩
?????????? /// 個以上客戶端進程在運行時,標識不
?????????? /// 同的客戶端進程
?????????? /// </summary>
?????????? private int m_iMyClientPort;

?????????? /// <summary>
?????????? /// 標識是否已成功創服務器
?????????? /// </summary>
?????????? private bool m_bServerCreated;

?????????? /// <summary>
?????????? /// 標識是否已成功創建客戶端
?????????? /// </summary>
?????????? private bool m_bClientCreated;

?????????? /// <summary>
?????????? /// 服務器使用的線程
?????????? /// </summary>
?????????? private Thread m_serverThread;

?????????? /// <summary>
?????????? /// 客戶端使用的線程
?????????? /// </summary>
?????????? private Thread m_clientThread;

?????????? /// <summary>
?????????? /// 打洞線程
?????????? /// </summary>
?????????? //private Thread m_burrowThread;

?????????? /// <summary>
?????????? /// 遠端節點
?????????? /// </summary>
?????????? private IPEndPoint m_remotePoint;

?????????? /// <summary>
?????????? /// 當前進程作為客戶端的公共終端
?????????? /// </summary>
?????????? private string m_strMyPublicEndPoint;

?????????? /// <summary>
?????????? /// 當前進程作為客戶端的私有終端
?????????? /// </summary>
?????????? private string m_strMyPrivateEndPoint;

?????????? /// <summary>
?????????? /// 用于接受信息的StringBuilder實例
?????????? /// </summary>
?????????? private StringBuilder m_sbResponse = new StringBuilder();

?????????? /// <summary>
?????????? /// P2P打洞時標識是否收到回應消息
?????????? /// </summary>
?????????? private bool m_bRecvAck=false ;

?????????? /// <summary>
?????????? /// 請求向其方向打洞的私有終端
?????????? /// </summary>
?????????? private IPEndPoint m_requestPrivateEndPoint;

?????????? /// <summary>
?????????? /// 請求向其方向打洞的公共終端
?????????? /// </summary>
?????????? private IPEndPoint m_requestPublicEndPoint;

?????????? /// <summary>
?????????? /// 打洞消息要發向的節點
?????????? /// </summary>
?????????? private ToEndPoint m_toEndPoint;

?????????? /// <summary>
?????????? /// 用于標識是否已經和請求客戶端建立點對連接
?????????? /// </summary>
?????????? //private bool m_bHasConnected=false ;

?????????? /// <summary>
?????????? /// 創建服務器或客戶端的最大嘗試
?????????? /// 次數,為(65536-60000),防止
?????????? /// 因不能創建而限入死循環或使用
?????????? /// 無效端口
?????????? /// </summary>
?????????? private const int MAX_CREATE_TRY = 5536;

?????????? /// <summary>
?????????? /// 打洞時嘗試連接的最大嘗試次數
?????????? /// </summary>
?????????? private const int MAX_CONNECT_TRY = 10;


?????????? /// <summary>
?????????? /// 構造函數,初始化UDPP2P實例
?????????? /// </summary>
?????????? public UDPP2PSock()
?????????? {
?????????????? m_iMyServerPort = P2PConsts.UDP_SRV_PORT;
?????????????? m_iMyClientPort = 60000;
?????????????? m_bClientCreated = false;
?????????????? m_bServerCreated = false;
?????????????? m_toEndPoint = new ToEndPoint();
?????????????? m_serverThread = new Thread(new ThreadStart(RunUDPServer ));
?????????????? m_clientThread = new Thread(new ThreadStart(RunUDPClient ));
?????????????? //m_burrowThread = new Thread(new ThreadStart(BurrowProc));
?????????? }

?????????? /// <summary>
?????????? /// 創建UDP服務器
?????????? /// </summary>
?????????? public void CreateUDPSever()
?????????? {
?????????????? int iTryNum=0;

?????????????? //開始嘗試創建服務器
?????????????? while (!m_bServerCreated && iTryNum < MAX_CREATE_TRY)
?????????????? {
?????????????????? try
?????????????????? {
?????????????????????? m_udpServer = new UdpClient(m_iMyServerPort);
?????????????????????? m_bServerCreated = true;
?????????????????? }
?????????????????? catch
?????????????????? {
?????????????????????? m_iMyServerPort++;
?????????????????????? iTryNum++;
?????????????????? }
?????????????? }

?????????????? //創建失敗,拋出異常
?????????????? if (!m_bServerCreated && iTryNum == MAX_CREATE_TRY)
?????????????? {
?????????????????? throw new Exception ("創建服務器嘗試失敗!");
?????????????? }
?????????????? m_serverThread.Start();
????????????
?????????? }

?????????? /// <summary>
?????????? /// 創建UDP客戶端
?????????? /// </summary>
?????????? /// <param name="strServerIP">服務器IP</param>
?????????? /// <param name="iServerPort">服務器端口</param>
?????????? public void CreateUDPClient(string strServerIP,int iServerPort)
?????????? {
?????????????? int iTryNum = 0;

?????????????? //開始嘗試創建服務器
?????????????? while (!m_bClientCreated???? && iTryNum < MAX_CREATE_TRY)
?????????????? {
?????????????????? try
?????????????????? {
?????????????????????? m_udpClient???? = new UdpClient(m_iMyClientPort );
?????????????????????? m_bClientCreated???? = true;
?????????????????????? string strIPAddress = (System.Net.Dns.GetHostAddresses("localhost")[0]).ToString();
?????????????????????? m_strMyPrivateEndPoint = strIPAddress + ":" + m_iMyClientPort.ToString();
?????????????????? }
?????????????????? catch
?????????????????? {
?????????????????????? m_iMyClientPort ++;
?????????????????????? iTryNum++;
?????????????????? }
?????????????? }

?????????????? //創建失敗,拋出異常
?????????????? if (!m_bClientCreated???? && iTryNum == MAX_CREATE_TRY)
?????????????? {
?????????????????? throw new Exception ("創建客戶端嘗試失敗!");
?????????????? }

?????????????? IPEndPoint hostPoint = new IPEndPoint(IPAddress.Parse(strServerIP), iServerPort);
?????????????? string strLocalIP = (System.Net.Dns.GetHostAddresses("localhost"))[0].ToString();
?????????????? SendLocalPoint(strLocalIP, m_iMyClientPort, hostPoint);
?????????????? m_clientThread .Start();
?????????? }


?????????? /// <summary>
?????????? /// 運行UDP服務器
?????????? /// </summary>
?????????? private void RunUDPServer()
?????????? {
?????????????? while (true)
?????????????? {
?????????????????? byte[] msgBuffer =m_udpServer .Receive(ref m_remotePoint);
?????????????????? m_sbResponse.Append(System.Text.Encoding.Default.GetString(msgBuffer));
?????????????????? CheckCommand();
?????????????????? Thread.Sleep(10);
?????????????? }
?????????? }


?????????? /// <summary>
?????????? /// 運行UDP客戶端
?????????? /// </summary>
?????????? private void RunUDPClient()
?????????? {
?????????????? while (true)
?????????????? {
?????????????????? byte[] msgBuffer = m_udpClient.Receive(ref m_remotePoint);
?????????????????? m_sbResponse.Append(System.Text.Encoding.Default.GetString(msgBuffer));
?????????????????? CheckCommand();
?????????????????? Thread.Sleep(10);
?????????????? }
?????????? }


?????????? /// <summary>
?????????? /// 銷毀UDP服務器
?????????? /// </summary>
?????????? public void DisposeUDPServer()
?????????? {
?????????????? m_serverThread.Abort();
?????????????? m_udpServer.Close();
?????????? }

?????????? /// <summary>
?????????? /// 銷毀UDP客房端
?????????? /// </summary>
?????????? public void DisposeUDPClient()
?????????? {
?????????????? m_clientThread.Abort();
?????????????? m_udpClient.Close();
?????????? }

?????????? /// <summary>
?????????? /// 發送消息
?????????? /// </summary>
?????????? /// <param name="strMsg">消息內容</param>
?????????? /// <param name="REP">接收節點</param>
?????????? public void SendData(string strMsg,IPEndPoint REP)
?????????? {
?????????????? byte[] byMsg = System.Text.Encoding.Default.GetBytes(strMsg.ToCharArray());
?????????????? m_udpClient.Send(byMsg, byMsg.Length, REP);
?????????? }


?????????? /// <summary>
?????????? /// 發送消息,服務器專用
?????????? /// </summary>
?????????? /// <param name="strMsg">消息內容</param>
?????????? /// <param name="REP">接收節點</param>
?????????? private void ServerSendData(string strMsg,IPEndPoint REP)
?????????? {
?????????????? byte[] byMsg = System.Text.Encoding.Default.GetBytes(strMsg.ToCharArray());
?????????????? m_udpServer.Send(byMsg, byMsg.Length, REP);
?????????? }


?????????? /// <summary>
?????????? /// 發送本地節點信息
?????????? /// </summary>
?????????? /// <param name="strLocalIP">本地IP</param>
?????????? /// <param name="iLocalPort">本地端口</param>
?????????? public void SendLocalPoint(string strLocalIP, int iLocalPort,IPEndPoint REP)
?????????? {
?????????????? string strLocalPoint = "/x01/x02" + strLocalIP + ":" + iLocalPort.ToString() + "/x02/x01";
?????????????? SendData(strLocalPoint, REP);
?????????? }

/// <summary>
????????? /// 同時向指定的終端(包括公共終端和私有終端)打洞
????????? /// </summary>
????????? /// <param name="pubEndPoint">公共終端</param>
????????? /// <param name="prEndPoint">私有終端</param>
????????? /// <returns>打洞成功返回true,否則返回false</returns>
????????? public void StartBurrowTo(IPEndPoint pubEndPoint, IPEndPoint prEndPoint)
????????? {
????????????? Thread burrowThread = new Thread(new ThreadStart(BurrowProc));
????????????? m_toEndPoint.m_privateEndPoint = prEndPoint;
????????????? m_toEndPoint.m_publicEndPoint = pubEndPoint;
????????????? burrowThread.Start();
????????? }

????????
????????? /// <summary>
????????? /// 打洞線程
????????? /// </summary>
????????? private void BurrowProc()
????????? {
????????????? IPEndPoint prEndPoint = m_toEndPoint.m_privateEndPoint;
????????????? IPEndPoint pubEndPoint = m_toEndPoint.m_publicEndPoint;
????????????? int j = 0;
????????????? for (int i = 0; i < MAX_CONNECT_TRY; i++)
????????????? {
????????????????? SendData("/x01/x07/x07/x01", prEndPoint);
????????????????? SendData("/x01/x07/x07/x01", pubEndPoint);

????????????????? //等待接收線程標記修改
????????????????? for (j = 0; j < MAX_CONNECT_TRY; j++)
????????????????? {
????????????????????? if (m_bRecvAck)
????????????????????? {
????????????????????????? m_bRecvAck = false;
????????????????????????? SendData("/x01/x07/x07/x01", prEndPoint);
????????????????????????? Thread.Sleep(50);
????????????????????????? SendData("/x01/x07/x07/x01", pubEndPoint);

????????????????????????? UDPSockEventArgs args = new UDPSockEventArgs("");
????????????????????????? args.RemoteEndPoint = pubEndPoint;
????????????????????????? if (OnNewConnectU != null)
????????????????????????? {
????????????????????????????? OnNewConnectU(this, args);
????????????????????????? }
????????????????????????? //Thread .Sleep (System .Threading.Timeout .Infinite );
????????????????????????? return;
????????????????????? }
????????????????????? else
????????????????????? {
????????????????????????? Thread.Sleep(100);
????????????????????? }
????????????????? }

????????????????? //如果沒有收到目標主機的回應,表明本次打
????????????????? //洞嘗試失敗,等待100毫秒后嘗試下一次打洞
????????????????? Thread.Sleep(100);
????????????? }

????????????? //MAX_CONNECT_TRY嘗試都失敗,表明打洞失敗,拋出異常
????????????? //throw new Exception("打洞失敗!");
????????????? System.Windows.Forms.MessageBox.Show("打洞失敗!");
????????? }
?????????

????????? /// <summary>
????????? /// 轉發打洞請求消息,在服務器端使用
????????? /// </summary>
????????? /// <param name="strSrcPrEndpoint">請求轉發的源私有終端</param>
????????? /// <param name="strSrcPubEndPoint">請求轉發的源公共終端</param>
????????? /// <param name="REP">轉發消息到達的目的終端</param>
????????? public void SendBurrowRequest(string strSrcPrEndpoint, string strSrcPubEndPoint,IPEndPoint REP)
????????? {
????????????? string strBurrowMsg = "/x04/x07" + strSrcPrEndpoint + " " + strSrcPubEndPoint + "/x07/x04";
????????????? ServerSendData(strBurrowMsg, REP);
????????? }


????????? /// <summary>
????????? /// 檢查字符串中的命令
????????? /// </summary>
????????? private void CheckCommand()
????????? {
????????????? int nPos;
????????????? string strCmd = m_sbResponse.ToString();

????????????? //如果接收遠端用戶名
????????????? if ((nPos = strCmd.IndexOf("/x01/x02")) > -1)
????????????? {
????????????????? ReceiveName(strCmd, nPos);
????????????????
????????????????? //反饋公共終給端遠端主機
????????????????? string strPubEPMsg = "/x03/x07" + m_remotePoint.ToString() + "/x07/x03";
????????????????? SendData(strPubEPMsg, m_remotePoint);

????????????????? return;
????????????? }

????????????? //如果接收我的公共終端
????????????? if ((nPos = strCmd.IndexOf("/x03/x07")) > -1)
????????????? {
????????????????? ReceiveMyPublicEndPoint(strCmd, nPos);
????????????????? return;
????????????? }

????????????? //如果是打洞請求消息
????????????? if ((nPos = strCmd.IndexOf("/x04/x07")) > -1)
????????????? {
????????????????? ReceiveAndSendAck(strCmd, nPos);
????????????????? return;
????????????? }

????????????? //如果是打洞回應消息
????????????? if ((nPos =strCmd .IndexOf ("/x01/x07"))>-1)
????????????? {
????????????????? m_bRecvAck = true;
????????????????? int nPos2 = strCmd.IndexOf("/x07/x01");
????????????????? if (nPos2 > -1)
????????????????? {
????????????????????? m_sbResponse.Remove(nPos, nPos2 - nPos + 2);
????????????????? }

????????????????? /*
????????????????? if (m_requestPublicEndPoint != null)
????????????????? {
????????????????????? if (!m_bHasConnected)
????????????????????? {
????????????????????????? m_bHasConnected = true;
????????????????????????? UDPSockEventArgs args = new UDPSockEventArgs("");
????????????????????????? args.RemoteEndPoint = m_requestPublicEndPoint;
????????????????????????? if (OnNewConnectU != null)
????????????????????????? {
????????????????????????????? OnNewConnectU(this, args);
????????????????????????? }
????????????????????????? m_requestPublicEndPoint = null;
????????????????????? }
????????????????? }*/

????????????????? return;
????????????? }

????????????? //一般聊天消息
????????????? m_sbResponse.Remove(0, strCmd.Length);
????????????? RaiseMessageEvent(strCmd);
????????? }


????????? /// <summary>
????????? /// 接收遠端用戶名
????????? /// </summary>
????????? /// <param name="strCmd">包含用戶名的控制信息</param>
????????? /// <param name="nPos"></param>
????????? private void ReceiveName(string strCmd, int nPos)
????????? {
????????????? int nPos2 = strCmd.IndexOf("/x02/x01");
????????????? if (nPos2 == -1)
????????????? {
????????????????? return;
????????????? }
????????????? m_sbResponse.Remove(nPos, nPos2 - nPos + 2);

????????????? string strUserName = strCmd.Substring(nPos + 2, nPos2 - nPos - 2);
????????????? UDPSockEventArgs e = new UDPSockEventArgs("");
????????????? e.RemoteUserName = strUserName;
????????????? e.RemoteEndPoint = m_remotePoint;

????????????? //觸發用戶登錄事件
????????????? if (OnUserLogInU != null)
????????????? {
????????????????? OnUserLogInU(this, e);
????????????? }
????????? }


????????? /// <summary>
????????? /// 接收打洞請求的消息并發送回應
????????? /// </summary>
????????? /// <param name="strCmd"></param>
????????? /// <param name="nPos"></param>
????????? private void ReceiveAndSendAck(string strCmd, int nPos)
????????? {
????????????? int nPos2 = strCmd.IndexOf("/x07/x04");
????????????? if (nPos2 == -1)
????????????? {
????????????????? return;
????????????? }
????????????? m_sbResponse.Remove(nPos, nPos2 - nPos + 2);

????????????? string strBurrowMsg = strCmd.Substring(nPos + 2, nPos2 - nPos - 2);

????????????? string[] strSrcPoint = strBurrowMsg.Split(' ');

????????????? //分析控制字符串包含的節點信息
????????????? string[] strPrEndPoint = strSrcPoint[0].Split(':');
????????????? string[] strPubEndPoint = strSrcPoint[1].Split(':');
????????????? m_requestPrivateEndPoint??? = new IPEndPoint(IPAddress.Parse(strPrEndPoint[0]), int.Parse(strPrEndPoint[1]));
????????????? m_requestPublicEndPoint??? = new IPEndPoint(IPAddress.Parse(strPubEndPoint[0]), int.Parse(strPubEndPoint[1]));

????????????? //向請求打洞終端的方向打洞
????????????? StartBurrowTo(m_requestPublicEndPoint, m_requestPrivateEndPoint);
????????? }


????????? /// <summary>
????????? /// 接收我的公共終端
????????? /// </summary>
????????? /// <param name="strCmd">包含公共終端的控制信息</param>
????????? /// <param name="nPos">控制字符串的起始位置</param>
????????? private void ReceiveMyPublicEndPoint(string strCmd, int nPos)
????????? {
????????????? int nPos2 = strCmd.IndexOf("/x07/x03");
????????????? if (nPos2 == -1)
????????????? {
????????????????? return;
????????????? }
????????????? m_sbResponse.Remove(nPos, nPos2 - nPos + 2);

????????????? m_strMyPublicEndPoint=strCmd.Substring(nPos + 2, nPos2 - nPos - 2);
????????? }


????????? /// <summary>
????????? /// 觸發一般UDP消息事件
????????? /// </summary>
????????? /// <param name="strMsg">消息內容</param>
????????? private void RaiseMessageEvent(string strMsg)
????????? {
????????????? UDPSockEventArgs args = new UDPSockEventArgs("");
????????????? args.SockMessage = strMsg;
????????????? args.RemoteEndPoint = m_remotePoint;
????????????? if (OnSockMessageU != null)
????????????? {
????????????????? OnSockMessageU(this, args);
????????????? }
????????? }


????????? /// <summary>
????????? /// 獲取當前進程作為客戶端的公共終端
????????? /// </summary>
????????? public string MyPublicEndPoint
????????? {
????????????? get
????????????? {
????????????????? return m_strMyPublicEndPoint;
????????????? }
????????? }


????????? /// <summary>
????????? /// 獲取當前進程作為客戶端的私有終端
????????? /// </summary>
????????? public string MyPrivateEndPoint
????????? {
????????????? get
????????????? {
????????????????? return m_strMyPrivateEndPoint;
????????????? }
????????? }
????? }

????
????? /// <summary>
????? /// 保存打洞消息要發向的節點信息
????? /// </summary>
????? class ToEndPoint
????? {
????????? /// <summary>
????????? /// 私有節點
????????? /// </summary>
????????? public IPEndPoint m_privateEndPoint;

????????? /// <summary>
????????? /// 公共節點
????????? /// </summary>
????????? public IPEndPoint m_publicEndPoint;
????? }

}

?????????? 關于如何使用上述程序包的一些說明:
?????????? 主要程序的初始化,參考代碼如下:
????????????? //創建UDP服務器和客戶端
????????????? try
????????????? {
????????????????? string strServerIP="127.0.0.1"
????????????????? udpSock = new UDPP2PSock();
????????????????? udpSock.OnUserLogInU += new UdpUserLogInDelegate(OnUserLogInU);
????????????????? udpSock.OnNewConnectU += new UdpNewConnectDelegate(OnNewConnectU);
????????????????? udpSock.CreateUDPSever();
????????????????? udpSock.CreateUDPClient(strServerIP, P2PConsts.UDP_SRV_PORT);
????????????? }
????????????? catch (Exception ex)
????????????? {

????????????? }

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/389069.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389069.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389069.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NLPPython筆記——WordNet

WordNet是一種面向語義的英語詞典&#xff0c;由Princeton大學的心理學家、語言學家和計算機工程師聯合設計。它不是光把單詞以字母順序排列&#xff0c;而且按照單詞的意義組成一個“單詞的網絡”。 NLTK庫中包含了英語WordNet&#xff0c;里面共有155287個詞以及117659個同義…

crc16的c語言函數 計算ccitt_C語言為何如此重要

●●●如今&#xff0c;有很多學生不懂為何要學習編程語言&#xff0c;為何要學習C語言&#xff1f;原因是大學生不能滿足于只會用辦公軟件&#xff0c;而應當有更高的學習要求&#xff0c;對于理工科的學生尤其如此。計算機的本質是“程序的機器”&#xff0c;程序和指令的思想…

毫米波雷達與激光雷達的初探

毫米波雷達與激光雷達的初探 雷達 &#xff08;Radio Detection and Range, Radar&#xff09;是一種利用電磁波來對目標進行探測和定位的電子設備。實現距離測量、運動參數測量、搜索和發現目標、目標定位、目標特性參數分析等功能。 分類 電磁波按照從低頻到高頻的順序&…

aws spark_使用Spark構建AWS數據湖時的一些問題以及如何處理這些問題

aws spark技術提示 (TECHNICAL TIPS) 介紹 (Introduction) At first, it seemed to be quite easy to write down and run a Spark application. If you are experienced with data frame manipulation using pandas, numpy and other packages in Python, and/or the SQL lang…

沖刺第三天 11.27 TUE

任務執行情況 已解決問題 數據庫結構已經確定 對聯生成model已訓練完成 詞匹配部分完成 微信前端rush版本完成 總體情況 團隊成員今日已完成任務剩余任務困難Dacheng, Weijieazure數據庫搭建(完成&#xff09;multiple communication scripts, call APIs需要進行整合調試Yichon…

鎖是網絡數據庫中的一個非常重要的概念

鎖是網絡數據庫中的一個非常重要的概念&#xff0c;它主要用于多用戶環境下保證數據庫完整性和一致性。各種大型數據庫所采用的鎖的基本理論是一致的&#xff0c;但在具體 實現上各有差別。目前&#xff0c;大多數數據庫管理系統都或多或少具有自我調節、自我管理的功能&#x…

DPDK+Pktgen 高速發包測試

參考博客 Pktgen概述 Pktgen,(Packet Gen-erator)是一個基于DPDK的軟件框架&#xff0c;發包速率可達線速。提供運行時管理&#xff0c;端口實時測量。可以控制 UDP, TCP, ARP, ICMP, GRE, MPLS and Queue-in-Queue等包。可以通過TCP進行遠程控制。Pktgen官網 安裝使用過程 版本…

python 商城api編寫_Python實現簡單的API接口

1. get方法import jsonfrom urlparse import parse_qsfrom wsgiref.simple_server import make_server# 定義函數&#xff0c;參數是函數的兩個參數&#xff0c;都是python本身定義的&#xff0c;默認就行了。def application(environ, start_response):# 定義文件請求的類型和…

opencv (一) 學習通過OpenCV圖形界面及基礎

opencv 學習通過OpenCV圖形界面基礎 用的函數有 cv.line(), cv.circle(),cv.rectangle(), cv.ellipse(),cv.putText() 常用參數 img : 想要繪制圖形的圖片color: 圖形的顏色&#xff0c; BGRthickness&#xff1a;厚度lineType: 線的類型&#xff0c; 8-connected、anti-al…

python精進之路 -- open函數

下面是python中builtins文件里對open函數的定義&#xff0c;我將英文按照我的理解翻譯成中文&#xff0c;方便以后查看。 def open(file, moder, bufferingNone, encodingNone, errorsNone, newlineNone, closefdTrue): # known special case of open """  …

數據科學家編程能力需要多好_我們不需要這么多的數據科學家

數據科學家編程能力需要多好I have held the title of data scientist in two industries. I’ve interviewed for more than 30 additional data science positions. I’ve been the CTO of a data-centric startup. I’ve done many hours of data science consulting.我曾擔…

基于xtrabackup GDIT方式不鎖庫作主從同步(主主同步同理,反向及可)

1.安裝數據同步工具 注&#xff1a;xtrabackup 在數據恢復的時候比mysqldump要快很多&#xff0c;特別是大數據庫的時候&#xff0c;但網絡傳輸的內容要多&#xff0c;壓縮需要占用時間。 yum install https://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.12…

excel表格行列顯示十字定位_WPS表格:Excel表格打印時,如何每頁都顯示標題行?...

電子表格數據很多的時候&#xff0c;要分很多頁打印&#xff0c;如何每頁都能顯示標題行呢&#xff1f;以下表為例&#xff0c;我們在WPS2019中演示如何每頁都顯示前兩行標題行&#xff1f;1.首先點亮頂部的頁面布局選項卡。然后點擊打印標題或表頭按鈕。2.在彈出的頁面設置對話…

opencv(二) 圖片處理

opencv 圖片處理 opencv 圖片像素操作 取像素點操作設置像素點取圖片塊分離&#xff0c;合并 b, g, r import numpy as np import cv2 as cvimg cv.imread(/Users/guoyinhuang/Desktop/G77.jpeg)# 獲取像素值 px img[348, 120] # 0 是y, 1 是x print(px)blue img[100, 1…

【NLP】語言模型和遷移學習

10.13 Update&#xff1a;最近新出了一個state-of-the-art預訓練模型&#xff0c;傳送門&#xff1a;李入魔&#xff1a;【NLP】Google BERT詳解?zhuanlan.zhihu.com1. 簡介長期以來&#xff0c;詞向量一直是NLP任務中的主要表征技術。隨著2017年底以及2018年初的一系列技術突…

TCPIP傳送協議

以下代碼實現在客戶端查詢成績&#xff08;數據庫在服務器端&#xff09;: 客戶端&#xff1a; static void Main(string[] args) { string str null; while (str ! Convert.ToString(0)) { Console.WriteLine("…

sql優化技巧_使用這些查詢優化技巧成為SQL向導

sql優化技巧成為SQL向導&#xff01; (Become an SQL Wizard!) It turns out storing data by rows and columns is convenient in a lot of situations, so relational databases have remained a cornerstone of data management in businesses across the globe. Structured…

Day 4:集合——迭代器與List接口

Collection-迭代方法 1、toArray() 返回Object類型數據&#xff0c;接收也需要Object對象&#xff01; Object[] toArray(); Collection c new ArrayList(); Object[] arr c.toArray(); 2、iterator() Collection的方法&#xff0c;返回實現Iterator接口的對象&#xff0c;…

oem是代工還是貼牌_代加工和貼牌加工的區別是什么

展開全部代加工就是替別人加工&#xff0c;貼別人的牌子。貼牌加工即商家自己不生產&#xff0c;而是委托其他生產企e68a8462616964757a686964616f31333365663431業生產&#xff0c;而品牌是自己的。拓展資料&#xff1a;OEM(Original Equipment Manufacture)的基本含義是定牌生…

KNN 算法--圖像分類算法

KNN 算法–圖像分類算法 找到最近的K個鄰居&#xff0c;在前k個最近樣本中選擇最近的占比最高的類別作為預測類別。 給定測試對象&#xff0c;計算它與訓練集中每個對象的距離。圈定距離最近的k個訓練對象&#xff0c;作為測試對象的鄰居。根據這k個緊鄰對象所屬的類別&#xf…