/// <summary> /// UDP打洞过程 /// 假设A想连接B.首先A发送打洞消息给Server,让Server告诉B有人想与你建立通话通道,Server将A的IP信息转发给B /// B收到命令后向A发一个UDP包,此时B的NAT会建立一个与A通讯的Session. 然后A再次向B发送UDP包B就能收到了 /// </summary> public void HolePunching(User user) { //A:自己; B:参数user //A发送打洞消息给服务器,请求与B打洞 C2S_HolePunchingRequestMessage msg = new C2S_HolePunchingRequestMessage(_LocalUserName, user.UserName); SendMessage(msg, _hostPoint); Thread.Sleep(2000);//等待对方发送UDP包并建立Session //再向对方发送确认消息,如果对方收到会发送一个P2P_HolePunchingResponse确认消息,此时打洞成功 P2P_HolePunchingTestMessage confirmMessage = new P2P_HolePunchingTestMessage(_LocalUserName); SendMessage(confirmMessage, user); }
//运行线程 private void Run() { try { byte[] buffer;//接受数据用 while (true) { buffer = _client.Receive(ref _remotePoint);//_remotePoint变量返回当前连接的用户IP地址 object msgObj = ObjectSerializer.Deserialize(buffer); Type msgType = msgObj.GetType(); DoWriteLog("接收到消息:" + msgType + " From:" + _remotePoint); if (msgType == typeof(S2C_UserListMessage)) { // 更新用户列表 S2C_UserListMessage usersMsg = (S2C_UserListMessage)msgObj; _userList.Clear(); foreach (User user in usersMsg.UserList) _userList.Add(user); DisplayUsers(_userList); } else if (msgType == typeof(S2C_UserAction)) { //用户动作,新用户登录/用户登出 S2C_UserAction msgAction = (S2C_UserAction)msgObj; if (msgAction.Action == UserAction.Login) { _userList.Add(msgAction.User); DisplayUsers(_userList); } else if (msgAction.Action == UserAction.Logout) { User user = _userList.Find(msgAction.User.UserName); if (user != null) _userList.Remove(user); DisplayUsers(_userList); } } else if (msgType == typeof(S2C_HolePunchingMessage)) { //接受到服务器的打洞命令 S2C_HolePunchingMessage msgHolePunching = (S2C_HolePunchingMessage)msgObj; //NAT-B的用户给NAT-A的用户发送消息,此时UDP包肯定会被NAT-A丢弃, //因为NAT-A上并没有A->NAT-B的合法Session, 但是现在NAT-B上就建立了有B->NAT-A的合法session了! P2P_HolePunchingTestMessage msgTest = new P2P_HolePunchingTestMessage(_LocalUserName); SendMessage(msgTest, msgHolePunching.RemotePoint); } else if (msgType == typeof(P2P_HolePunchingTestMessage)) { //UDP打洞测试消息 //_HoleAccepted = true; P2P_HolePunchingTestMessage msgTest = (P2P_HolePunchingTestMessage)msgObj; UpdateConnection(msgTest.UserName, _remotePoint); //发送确认消息 P2P_HolePunchingResponse response = new P2P_HolePunchingResponse(_LocalUserName); SendMessage(response, _remotePoint); } else if (msgType == typeof(P2P_HolePunchingResponse)) { //_HoleAccepted = true;//打洞成功 P2P_HolePunchingResponse msg = msgObj as P2P_HolePunchingResponse; Debug.Assert(msg != null, "msg != null"); UpdateConnection(msg.UserName, _remotePoint); } else if (msgType == typeof(P2P_TalkMessage)) { //用户间对话消息 P2P_TalkMessage workMsg = (P2P_TalkMessage)msgObj; DoWriteLog(workMsg.Message); } else { DoWriteLog("收到未知消息!"); } } } catch (Exception ex) { DoWriteLog(ex.Message); } }