欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C# p2p UDP穿越NAT,UDP打洞源碼

admin
2018年2月10日 10:7 本文熱度 8187

思路如下(參照源代碼):

  1、 frmServer啟動(dòng)兩個(gè)網(wǎng)絡(luò)偵聽,主連接偵聽,協(xié)助打洞的偵聽。

  2、 frmClientA和frmClientB分別與frmServer的主連接保持聯(lián)系。

  3、 當(dāng)frmClientA需要和frmClientB建立直接的udp連接時(shí),首先連接frmServer的協(xié)助打洞端口,并發(fā)送協(xié)助連接申請(qǐng),同時(shí)在該端口號(hào)上啟動(dòng)偵聽。

     4、  frmServer的協(xié)助打洞連接收到frmClientA的申請(qǐng)后通過主連接通知frmClientB,并將frmClientA經(jīng)過NAT-A轉(zhuǎn)換后的公網(wǎng)IP地址和端口等信息告訴frmClientB。

  5、 frmClientB收到frmServer的連接通知后首先與frmServer的協(xié)助打洞端口連接,發(fā)送一些數(shù)據(jù)后立即斷開,目的是讓frmServer能知道frmClientB經(jīng)過NAT-B轉(zhuǎn)換后的公網(wǎng)IP和端口號(hào)。

  6、 frmClientB嘗試與frmClientA的經(jīng)過NAT-A轉(zhuǎn)換后的公網(wǎng)IP地址和端口進(jìn)行connect,不同的路由器會(huì)有不同的結(jié)果,多數(shù)路由器對(duì)未知不請(qǐng)自到的SYN請(qǐng)求包直接丟棄而導(dǎo)致connect失敗,但NAT-A會(huì)紀(jì)錄此次連接的源地址和端口號(hào),為接下來真正的連接做好了準(zhǔn)備,這就是所謂的打洞,即frmClientB向frmClientA打了一個(gè)洞,下次frmClientA就能直接連接到frmClientB剛才使用的端口號(hào)了。

  7、 客戶端frmClientB打洞的同時(shí)在相同的端口上啟動(dòng)偵聽。frmClientB在一切準(zhǔn)備就緒以后通過與frmServer的主連接回復(fù)消息“可以了,已經(jīng)準(zhǔn)備”,frmServer在收到以后將frmClientB經(jīng)過NAT-B轉(zhuǎn)換后的公網(wǎng)IP和端口號(hào)告訴給frmClientA。

  8、 frmClientA收到frmServer回復(fù)的frmClientB的公網(wǎng)IP和端口號(hào)等信息以后,開始連接到frmClientB公網(wǎng)IP和端口號(hào),由于在步驟6中frmClientB曾經(jīng)嘗試連接過frmClientA的公網(wǎng)IP地址和端口,NAT-A紀(jì)錄了此次連接的信息,所以當(dāng)frmClientA主動(dòng)連接frmClientB時(shí),NAT-B會(huì)認(rèn)為是合法的SYN數(shù)據(jù),并允許通過,從而直接的udp連接建立起來了。

  • frmClientB

客戶端核心代碼:

private void Run()
        {
            try
            {
                byte[] buffer;//接受數(shù)據(jù)用
                while (true)
                {
                    buffer = _client.Receive(ref _remotePoint);//_remotePoint變量返回當(dāng)前連接的用戶IP地址

                    object msgObj = ObjectSerializer.Deserialize(buffer);
                    Type msgType = msgObj.GetType();
                    DoWriteLog("接收到消息:" + msgType.ToString() + " From:" + _remotePoint.ToString());

                    if (msgType == typeof(S2C_UserListMessage))
                    {
                        // 更新用戶列表
                        S2C_UserListMessage usersMsg = (S2C_UserListMessage)msgObj;
                        _userList.Clear();

                        foreach (User user in usersMsg.UserList)
                            _userList.Add(user);

                        this.DisplayUsers(_userList);
                    }
                    else if (msgType == typeof(S2C_UserAction))
                    {
                        //用戶動(dòng)作,新用戶登錄/用戶登出
                        S2C_UserAction msgAction = (S2C_UserAction)msgObj;
                        if (msgAction.Action == UserAction.Login)
                        {
                            _userList.Add(msgAction.User);
                            this.DisplayUsers(_userList);
                        }
                        else if (msgAction.Action == UserAction.Logout)
                        {
                            User user = _userList.Find(msgAction.User.UserName);
                            if (user != null) _userList.Remove(user);
                            this.DisplayUsers(_userList);
                        }
                    }
                    else if (msgType == typeof(S2C_HolePunchingMessage))
                    {
                        //接受到服務(wù)器的打洞命令
                        S2C_HolePunchingMessage msgHolePunching = (S2C_HolePunchingMessage)msgObj;

                        //NAT-B的用戶給NAT-A的用戶發(fā)送消息,此時(shí)UDP包肯定會(huì)被NAT-A丟棄,
                        //因?yàn)镹AT-A上并沒有A->NAT-B的合法Session, 但是現(xiàn)在NAT-B上就建立了有B->NAT-A的合法session了!
                        P2P_HolePunchingTestMessage msgTest = new P2P_HolePunchingTestMessage(_LocalUserName);
                        this.SendMessage(msgTest, msgHolePunching.RemotePoint);
                    }
                    else if (msgType == typeof(P2P_HolePunchingTestMessage))
                    {
                        //UDP打洞測(cè)試消息
                        //_HoleAccepted = true;
                        P2P_HolePunchingTestMessage msgTest = (P2P_HolePunchingTestMessage)msgObj;
                        UpdateConnection(msgTest.UserName, _remotePoint);

                        //發(fā)送確認(rèn)消息
                        P2P_HolePunchingResponse response = new P2P_HolePunchingResponse(_LocalUserName);
                        this.SendMessage(response, _remotePoint);
                    }
                    else if (msgType == typeof(P2P_HolePunchingResponse))
                    {
                        //_HoleAccepted = true;//打洞成功
                        P2P_HolePunchingResponse msg = msgObj as P2P_HolePunchingResponse;
                        UpdateConnection(msg.UserName, _remotePoint);

                    }
                    else if (msgType == typeof(P2P_TalkMessage))
                    {
                        //用戶間對(duì)話消息
                        P2P_TalkMessage workMsg = (P2P_TalkMessage)msgObj;
                        DoWriteLog(workMsg.Message);
                    }
                    else
                    {
                        DoWriteLog("收到未知消息!");
                    }
                }
            }
            catch (Exception ex) { DoWriteLog(ex.Message); }
        }

  • frmClientA

服務(wù)端核心代碼:

private void Run()
        {
            byte[] msgBuffer = null;

            while (true)
            {
                msgBuffer = _server.Receive(ref _remotePoint); //接受消息
                try
                {
                    //將消息轉(zhuǎn)換為對(duì)象
                    object msgObject = ObjectSerializer.Deserialize(msgBuffer);
                    if (msgObject == null) continue;

                    Type msgType = msgObject.GetType();
                    DoWriteLog("接收到消息:" + msgType.ToString());
                    DoWriteLog("From:" + _remotePoint.ToString());

                    //新用戶登錄
                    if (msgType == typeof(C2S_LoginMessage))
                    {
                        C2S_LoginMessage lginMsg = (C2S_LoginMessage)msgObject;
                        DoWriteLog(string.Format("用戶’{0}’已登錄!", lginMsg.FromUserName));

                        // 添加用戶到列表
                        IPEndPoint userEndPoint = new IPEndPoint(_remotePoint.Address, _remotePoint.Port);
                        User user = new User(lginMsg.FromUserName, userEndPoint);
                        _userList.Add(user);

                        this.DoUserChanged(_userList);

                        //通知所有人,有新用戶登錄
                        S2C_UserAction msgNewUser = new S2C_UserAction(user, UserAction.Login);
                        foreach (User u in _userList)
                        {
                            if (u.UserName == user.UserName) //如果是自己,發(fā)送所有在線用戶列表
                                this.SendMessage(new S2C_UserListMessage(_userList), u.NetPoint);
                            else
                                this.SendMessage(msgNewUser, u.NetPoint);
                        }
                    }
                    else if (msgType == typeof(C2S_LogoutMessage))
                    {
                        C2S_LogoutMessage lgoutMsg = (C2S_LogoutMessage)msgObject;
                        DoWriteLog(string.Format("用戶’{0}’已登出!", lgoutMsg.FromUserName));

                        // 從列表中刪除用戶
                        User logoutUser = _userList.Find(lgoutMsg.FromUserName);
                        if (logoutUser != null) _userList.Remove(logoutUser);

                        this.DoUserChanged(_userList);

                        //通知所有人,有用戶登出
                        S2C_UserAction msgNewUser = new S2C_UserAction(logoutUser, UserAction.Logout);
                        foreach (User u in _userList)
                            this.SendMessage(msgNewUser, u.NetPoint);
                    }
                    else if (msgType == typeof(C2S_HolePunchingRequestMessage))
                    {
                        //接收到A給B打洞的消息,打洞請(qǐng)求,由客戶端發(fā)送給服務(wù)器端
                        C2S_HolePunchingRequestMessage msgHoleReq = (C2S_HolePunchingRequestMessage)msgObject;

                        User userA = _userList.Find(msgHoleReq.FromUserName);
                        User userB = _userList.Find(msgHoleReq.ToUserName);

                        // 發(fā)送打洞(Punching Hole)消息
                        DoWriteLog(string.Format("用戶:[{0} IP:{1}]想與[{2} IP:{3}]建立對(duì)話通道.",
                        userA.UserName, userA.NetPoint.ToString(),
                        userB.UserName, userB.NetPoint.ToString()));

                        //由Server發(fā)送消息給B,將A的IP的IP地址信息告訴B,然后由B發(fā)送一個(gè)測(cè)試消息給A.
                        S2C_HolePunchingMessage msgHolePunching = new S2C_HolePunchingMessage(_remotePoint);
                        this.SendMessage(msgHolePunching, userB.NetPoint); //Server->B
                    }
                    else if (msgType == typeof(C2S_GetUsersMessage))
                    {
                        // 發(fā)送當(dāng)前用戶信息
                        S2C_UserListMessage srvResMsg = new S2C_UserListMessage(_userList);
                        this.SendMessage(srvResMsg, _remotePoint);
                    }
                }
                catch (Exception ex) { DoWriteLog(ex.Message); }
            }
        }

  • frmServer 


該文章在 2018/2/10 10:08:37 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲(chǔ)管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved