LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# UDP穿越NAT,UDP打洞,UDP Hole Punching源代码

admin
2021年2月2日 11:47 本文热度 3185
***阅读下面代码前请先了解UDP穿越NAT原理***

1.服务器主窗体源代码
public partial class frmServer : Form
{
   
private Server _server;
   
   
public frmServer()
   {
      InitializeComponent();
   }
   
   
private void button1_Click(object sender, EventArgs e)
   {
      _server = 
new Server();
      _server.OnWriteLog += 
new WriteLogHandle(server_OnWriteLog);
      _server.OnUserChanged += 
new UserChangedHandle(OnUserChanged);
      
try
      {
         _server.Start();
      }
      
catch (Exception ex)
      {
         MessageBox.Show(ex.Message);
      }
   }
   
   
//刷新用户列表
   
private void OnUserChanged(UserCollection users)
   {
      listBox2.DisplayMember = "FullName";
      listBox2.DataSource = 
null;
      listBox2.DataSource = users;
   }
   
   
//显示跟踪消息
   
public void server_OnWriteLog(string msg)
   {
      listBox1.Items.Add(msg);
      listBox1.SelectedIndex = listBox1.Items.Count - 1;
   }
   
   
private void button2_Click(object sender, EventArgs e)
   {
      Application.Exit();
   }
   
   
private void frmServer_FormClosing(object sender, FormClosingEventArgs e)
   {
      
if (_server != null)
      _server.Stop();
   }
   
   
private void button3_Click(object sender, EventArgs e)
   {
      
//发送消息给所有在线用户
      P2P_TalkMessage msg = 
new P2P_TalkMessage(textBox1.Text);
      
foreach (object o in listBox2.Items)
      {
         User user = o 
as User;
         _server.SendMessage(msg, user.NetPoint);
      }
   }
   
   
private void button6_Click(object sender, EventArgs e)
   {
      listBox1.Items.Clear();
   }
}

2.服务器业务类
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using vjsdn.net.library;
using System.Windows.Forms;

namespace vjsdn.net.library
{
   
/// <summary>
   
/// 服务器端业务类
   
/// </summary>
   
public class Server
   {
      
private UdpClient _server; //服务器端消息监听器
      
private UserCollection _userList; //在线用户列表
      
private Thread _serverThread;
      
private IPEndPoint _remotePoint; //远程用户请求的IP地址及端口
      
      
private WriteLogHandle _WriteLogHandle = null;
      
private UserChangedHandle _UserChangedHandle = null;
      
      
/// <summary>
      
/// 显示跟踪消息
      
/// </summary>
      
public WriteLogHandle OnWriteLog
      {
         
get { return _WriteLogHandle; }
         
set { _WriteLogHandle = value; }
      }
      
      
/// <summary>
      
/// 当用户登入/登出时触发此事件
      
/// </summary>
      
public UserChangedHandle OnUserChanged
      {
         
get { return _UserChangedHandle; }
         
set { _UserChangedHandle = value; }
      }
      
      
/// <summary>
      
/// 构造器
      
/// </summary>
      
public Server()
      {
         _userList = 
new UserCollection();
         _remotePoint = 
new IPEndPoint(IPAddress.Any, 0);
         _serverThread = 
new Thread(new ThreadStart(Run));
      }
      
      
/// <summary>
      
///显示跟踪记录
      
/// </summary>
      
/// <param name="log"></param>
      
private void DoWriteLog(string log)
      {
         
if (_WriteLogHandle != null)
         (_WriteLogHandle.Target 
as System.Windows.Forms.Control).Invoke(_WriteLogHandle, log);
      }
      
      
/// <summary>
      
/// 刷新用户列表
      
/// </summary>
      
/// <param name="list">用户列表</param>
      
private void DoUserChanged(UserCollection list)
      {
         
if (_UserChangedHandle != null)
         (_UserChangedHandle.Target 
as Control).Invoke(_UserChangedHandle, list);
      }
      
      
/// <summary>
      
/// 开始启动线程
      
/// </summary>
      
public void Start()
      {
         
try
         {
            _server = 
new UdpClient(Globals.SERVER_PORT);
            _serverThread.Start();
            DoWriteLog("
服务器已经启动,监听端口:" + Globals.SERVER_PORT.ToString() + ",等待客户连接...");
         }
         
catch (Exception ex)
         {
            DoWriteLog("
启动服务器发生错误: " + ex.Message);
            
throw ex;
         }
      }
      
      
/// <summary>
      
/// 停止线程
      
/// </summary>
      
public void Stop()
      {
         DoWriteLog("
停止服务器...");
         
try
         {
            _serverThread.Abort();
            _server.Close();
            DoWriteLog("
服务器已停止.");
         }
         
catch (Exception ex)
         {
            DoWriteLog("
停止服务器发生错误: " + ex.Message);
            
throw ex;
         }
      }
      
      
//线程主方法
      
private void Run()
      {
         
byte[] msgBuffer = null;
         
         
while (true)
         {
            msgBuffer = _server.Receive(
ref _remotePoint); //接受消息
            
try
            {
               
//将消息转换为对象
               
object msgObject = ObjectSerializer.Deserialize(msgBuffer);
               
if (msgObject == nullcontinue;
               
               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) //如果是自己,发送所有在线用户列表
                     
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))
               {
                  
//接收到AB打洞的消息,打洞请求,由客户端发送给服务器端
                  C2S_HolePunchingRequestMessage msgHoleReq = (C2S_HolePunchingRequestMessage)msgObject;
                  
                  User userA = _userList.Find(msgHoleReq.FromUserName);
                  User userB = _userList.Find(msgHoleReq.ToUserName);
                  
                  
// 发送打洞(Punching Hole)消息
                  DoWriteLog(
string.Format("用户:[{0} IP:{1}]想与[{2} IP:{3}]建立对话通道.",
                  userA.UserName, userA.NetPoint.ToString(),
                  userB.UserName, userB.NetPoint.ToString()));
                  
                  
//Server发送消息给B,AIPIP地址信息告诉B,然后由B发送一个测试消息给A.
                  S2C_HolePunchingMessage msgHolePunching = 
new S2C_HolePunchingMessage(_remotePoint);
                  
this.SendMessage(msgHolePunching, userB.NetPoint); //Server->B
               }
               
else if (msgType == typeof(C2S_GetUsersMessage))
               {
                  
// 发送当前用户信息
                  S2C_UserListMessage srvResMsg = 
new S2C_UserListMessage(_userList);
                  
this.SendMessage(srvResMsg, _remotePoint);
               }
            }
            
catch (Exception ex) { DoWriteLog(ex.Message); }
         }
      }
      
/// <summary>
      
/// 发送消息
      
/// </summary>
      
public void SendMessage(MessageBase msg, IPEndPoint remoteIP)
      {
         DoWriteLog("
正在发送消息:" + msg.ToString());
         
if (msg == nullreturn;
         
byte[] buffer = ObjectSerializer.Serialize(msg);
         _server.Send(buffer, buffer.Length, remoteIP);
         DoWriteLog("
消息已发送.");
      }
   }
}

3.客户端主窗体源代码
public partial class frmClient : Form
{
   
private Client _client;
   
   
public frmClient()
   {
      InitializeComponent();
   }
   
   
private void frmClient_Load(object sender, EventArgs e)
   {
      _client = 
new Client();
      _client.OnWriteMessage = 
this.WriteLog;
      _client.OnUserChanged = 
this.OnUserChanged;
   }
   
   
private void button1_Click(object sender, EventArgs e)
   {
      _client.Login(textBox2.Text, "");
      _client.Start();
   }
   
   
private void WriteLog(string msg)
   {
      listBox2.Items.Add(msg);
      listBox2.SelectedIndex = listBox2.Items.Count - 1;
   }
   
   
private void button4_Click(object sender, EventArgs e)
   {
      
this.Close();
   }
   
   
private void button3_Click(object sender, EventArgs e)
   {
      
if (_client != null)
      {
         User user = listBox1.SelectedItem 
as User;
         _client.HolePunching(user);
      }
   }
   
   
private void button2_Click(object sender, EventArgs e)
   {
      
if (_client != null) _client.DownloadUserList();
   }
   
   
private void frmClient_FormClosing(object sender, FormClosingEventArgs e)
   {
      
if (_client != null) _client.Logout();
   }
   
   
private void OnUserChanged(UserCollection users)
   {
      listBox1.DisplayMember = "FullName";
      listBox1.DataSource = 
null;
      listBox1.DataSource = users;
   }
   
   
private void button5_Click(object sender, EventArgs e)
   {
      P2P_TalkMessage msg = 
new P2P_TalkMessage(textBox1.Text);
      User user = listBox1.SelectedItem 
as User;
      _client.SendMessage(msg, user);
   }
   
   
private void button6_Click(object sender, EventArgs e)
   {
      listBox2.Items.Clear();
   }
}

4.客户端业务逻辑代码
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using vjsdn.net.library;
using System.Windows.Forms;
using System.IO;

namespace vjsdn.net.library
{
   
/// <summary>
   
/// 客户端业务类
   
/// </summary>
   
public class Client : IDisposable
   {
      
//private const int MAX_RETRY_SEND_MSG = 1; //打洞时连接次数,正常情况下一次就能成功
      
      
private UdpClient _client;//客户端监听器
      
private IPEndPoint _hostPoint; //主机IP
      
private IPEndPoint _remotePoint; //接收任何远程机器的数据
      
private UserCollection _userList;//在线用户列表
      
private Thread _listenThread; //监听线程
      
private string _LocalUserName; //本地用户名
      
//private bool _HoleAccepted = false; //A->B,接收到B用户的确认消息
      
      
private WriteLogHandle _OnWriteMessage;
      
public WriteLogHandle OnWriteMessage
      {
         
get { return _OnWriteMessage; }
         
set { _OnWriteMessage = value; }
      }
      
      
private UserChangedHandle _UserChangedHandle = null;
      
public UserChangedHandle OnUserChanged
      {
         
get { return _UserChangedHandle; }
         
set { _UserChangedHandle = value; }
      }
      
      
/// <summary>
      
///显示跟踪记录
      
/// </summary>
      
/// <param name="log"></param>
      
private void DoWriteLog(string log)
      {
         
if (_OnWriteMessage != null)
         (_OnWriteMessage.Target 
as Control).Invoke(_OnWriteMessage, log);
      }
      
      
/// <summary>
      
/// 构造器
      
/// </summary>
      
/// <param name="serverIP"></param>
      
public Client()
      {
         
string serverIP = this.GetServerIP();
         _remotePoint = 
new IPEndPoint(IPAddress.Any, 0); //任何与本地连接的用户IP地址。
         _hostPoint = 
new IPEndPoint(IPAddress.Parse(serverIP), Globals.SERVER_PORT); //服务器地址
         _client = 
new UdpClient();//不指定端口,系统自动分配
         _userList = 
new UserCollection();
         _listenThread = 
new Thread(new ThreadStart(Run));
      }
      
      
/// <summary>
      
/// 获取服务器IPINI文件内设置
      
/// </summary>
      
/// <returns></returns>
      
private string GetServerIP()
      {
         
string file = Application.StartupPath + "//ip.ini";
         
string ip = File.ReadAllText(file);
         
return ip.Trim();
      }
      
      
/// <summary>
      
/// 启动客户端
      
/// </summary>
      
public void Start()
      {
         
if (this._listenThread.ThreadState == ThreadState.Unstarted)
         {
            
this._listenThread.Start();
         }
      }
      
      
/// <summary>
      
/// 客户登录
      
/// </summary>
      
public void Login(string userName, string password)
      {
         _LocalUserName = userName;
         
         
// 发送登录消息到服务器
         C2S_LoginMessage loginMsg = 
new C2S_LoginMessage(userName, password);
         
this.SendMessage(loginMsg, _hostPoint);
      }
      
      
/// <summary>
      
/// 登出
      
/// </summary>
      
public void Logout()
      {
         C2S_LogoutMessage lgoutMsg = 
new C2S_LogoutMessage(_LocalUserName);
         
this.SendMessage(lgoutMsg, _hostPoint);
         
         
this.Dispose();
         System.Environment.Exit(0);
      }
      
      
/// <summary>
      
/// 发送请求获取用户列表
      
/// </summary>
      
public void DownloadUserList()
      {
         C2S_GetUsersMessage getUserMsg = 
new C2S_GetUsersMessage(_LocalUserName);
         
this.SendMessage(getUserMsg, _hostPoint);
      }
      
      
/// <summary>
      
/// 显示在线用户
      
/// </summary>
      
/// <param name="users"></param>
      
private void DisplayUsers(UserCollection users)
      {
         
if (_UserChangedHandle != null)
         (_UserChangedHandle.Target 
as Control).Invoke(_UserChangedHandle, users);
      }
      
      
//运行线程
      
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.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))
               {
                  
//用户动作,新用户登录/用户登出
                  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))
               {
                  
//接受到服务器的打洞命令
                  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);
                  
this.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);
                  
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))
               {
                  
//用户间对话消息
                  P2P_TalkMessage workMsg = (P2P_TalkMessage)msgObj;
                  DoWriteLog(workMsg.Message);
               }
               
else
               {
                  DoWriteLog("
收到未知消息!");
               }
            }
         }
         
catch (Exception ex) { DoWriteLog(ex.Message); }
      }
      
      
private void UpdateConnection(string user, IPEndPoint ep)
      {
         User remoteUser = _userList.Find(user);
         
if (remoteUser != null)
         {
            remoteUser.NetPoint = ep;
//保存此次连接的IP及端口
            remoteUser.IsConnected = 
true;
            DoWriteLog(
string.Format("您已经与{0}建立通信通道,IP:{1}!",
            remoteUser.UserName, remoteUser.NetPoint.ToString()));
            
this.DisplayUsers(_userList);
         }
      }
      
      
#region IDisposable 成员
      
      
public void Dispose()
      {
         
try
         {
            
this._listenThread.Abort();
            
this._client.Close();
         }
         
catch
         {
            
         }
      }
      
      
#endregion
      
      
public void SendMessage(MessageBase msg, User user)
      {
         
this.SendMessage(msg, user.NetPoint);
      }
      
      
public void SendMessage(MessageBase msg, IPEndPoint remoteIP)
      {
         
if (msg == nullreturn;
         DoWriteLog("
正在发送消息给->" + remoteIP.ToString() + ",内容:" + msg.ToString());
         
byte[] buffer = ObjectSerializer.Serialize(msg);
         _client.Send(buffer, buffer.Length, remoteIP);
         DoWriteLog("
消息已发送.");
      }
      
      
/// <summary>
      
/// UDP打洞过程
      
/// 假设A想连接B.首先A发送打洞消息给Server,Server告诉B有人想与你建立通话通道,ServerAIP信息转发给B
      
/// B收到命令后向A发一个UDP,此时BNAT会建立一个与A通讯的Session. 然后A再次向B发送UDPB就能收到了
      
/// </summary>
      
public void HolePunching(User user)
      {
         
//A:自己; B:参数user
         
//A发送打洞消息给服务器,请求与B打洞
         C2S_HolePunchingRequestMessage msg = 
new C2S_HolePunchingRequestMessage(_LocalUserName, user.UserName);
         
this.SendMessage(msg, _hostPoint);
         
         Thread.Sleep(2000);
//等待对方发送UDP包并建立Session
         
         
//再向对方发送确认消息,如果对方收到会发送一个P2P_HolePunchingResponse确认消息,此时打洞成功
         P2P_HolePunchingTestMessage confirmMessage = 
new P2P_HolePunchingTestMessage(_LocalUserName);
         
this.SendMessage(confirmMessage, user);
      }
   }
   
}

5.公共代码
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net;
using System.Collections;

namespace vjsdn.net.library
{
   /// 
   /// 显示跟踪消息的事件委托
   /// 

   public delegate void WriteLogHandle(string msg);
   
   /// 
   /// 刷新在线用户的事件委托
   /// 

   public delegate void UserChangedHandle(UserCollection users);
   
   public class Globals
   {
      /// 
      /// 服务器侦听端口
      /// 

      public const int SERVER_PORT = 21134;
      
      /// 
      /// 本地侦听端口
      /// 

      public const int LOCAL_PORT = 19786;
   }
   
   /// 
   /// User 的摘要说明。
   /// 

   [Serializable]
   public class User
   {
      protected string _userName;
      protected IPEndPoint _netPoint;
      protected bool _conntected;
      
      public User(string UserName, IPEndPoint NetPoint)
      {
         this._userName = UserName;
         this._netPoint = NetPoint;
      }
      
      public string UserName
      {
         get { return _userName; }
      }
      
      public IPEndPoint NetPoint
      {
         get { return _netPoint; }
         set { _netPoint = value; }
      }
      
      public bool IsConnected //打洞标记
      {
         get { return _conntected; }
         set { _conntected = value; }
      }
      
      public string FullName { get { return this.ToString(); } }
      
      public override string ToString()
      {
         return _userName + "- [" + _netPoint.Address.ToString() + ":" + _netPoint.Port.ToString() + "] " + (_conntected ? "Y" : "N");
      }
   }
   
   /// 
   /// 在线用户列表
   /// 

   [Serializable]
   public class UserCollection : CollectionBase
   {
      public void Add(User user)
      {
         InnerList.Add(user);
      }
      
      public void Remove(User user)
      {
         InnerList.Remove(user);
      }
      
      public User this[int index]
      {
         get { return (User)InnerList[index]; }
      }
      
      public User Find(string userName)
      {
         foreach (User user in this)
         {
            if (string.Compare(userName, user.UserName, true) == 0)
            {
               return user;
            }
         }
         return null;
      }
   }
   
   /// 
   /// 序列化反序列化对象
   /// 

   public class ObjectSerializer
   {
      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;
      }
   }
}

6.消息类(转发命令)
6.1 消息基类.所有命令的基类
/// 
/// 消息基类,抽象类
/// 

[Serializable]
public abstract class MessageBase
{
   //消息基类
}

6.2 Client to Server命令
#region 客户端发送到服务器的消息
/// 
/// 客户端发送到服务器的消息基类
/// 

[Serializable]
public abstract class C2S_MessageBase : MessageBase
{
   private string _fromUserName;
   
   protected C2S_MessageBase(string fromUserName)
   {
      _fromUserName = fromUserName;
   }
   
   public string FromUserName
   {
      get { return _fromUserName; }
   }
}

/// 
/// 用户登录消息
/// 

[Serializable]
public class C2S_LoginMessage : C2S_MessageBase
{
   private string _password;
   
   public C2S_LoginMessage(string userName, string password)
   : base(userName)
   {
      this._password = password;
   }
   
   public string Password
   {
      get { return _password; }
   }
}

/// 
/// 用户登出消息
/// 

[Serializable]
public class C2S_LogoutMessage : C2S_MessageBase
{
   
   public C2S_LogoutMessage(string userName)
   : base(userName)
   { }
}

/// 
/// 请求用户列表消息
/// 

[Serializable]
public class C2S_GetUsersMessage : C2S_MessageBase
{
   public C2S_GetUsersMessage(string userName)
   : base(userName)
   { }
}

/// 
/// 请求Purch Hole消息
/// 

[Serializable]
public class C2S_HolePunchingRequestMessage : C2S_MessageBase
{
   protected string toUserName;
   
   public C2S_HolePunchingRequestMessage(string fromUserName, string toUserName)
   : base(fromUserName)
   {
      this.toUserName = toUserName;
   }
   
   public string ToUserName
   {
      get { return this.toUserName; }
   }
}

#endregion

6.3 Server to Client命令
#region 服务器发送到客户端消息
/// 
/// 服务器发送到客户端消息基类
/// 

[Serializable]
public abstract class S2C_MessageBase : MessageBase
{
}

/// 
/// 请求用户列表应答消息
/// 

[Serializable]
public class S2C_UserListMessage : S2C_MessageBase
{
   private UserCollection userList;
   
   public S2C_UserListMessage(UserCollection users)
   {
      this.userList = users;
   }
   
   public UserCollection UserList
   {
      get { return userList; }
   }
}

/// 
/// 转发请求Purch Hole消息
/// 

[Serializable]
public class S2C_HolePunchingMessage : S2C_MessageBase
{
   protected System.Net.IPEndPoint _remotePoint;
   
   public S2C_HolePunchingMessage(System.Net.IPEndPoint point)
   {
      this._remotePoint = point;
   }
   
   public System.Net.IPEndPoint RemotePoint
   {
      get { return _remotePoint; }
   }
}

/// 
/// 服务器通知所有在线用户,
/// 

[Serializable]
public class S2C_UserAction : S2C_MessageBase
{
   protected User _User;
   protected UserAction _Action;
   
   public S2C_UserAction(User user, UserAction action)
   {
      _User = user;
      _Action = action;
   }
   
   public User User
   {
      get { return _User; }
   }
   
   public UserAction Action
   {
      get { return _Action; }
   }
}

#endregion

6.4 Client to Client(Peer to Peer P2P)命令
#region 点对点消息
/// 
/// 点对点消息基类
/// 

[Serializable]
public abstract class P2P_MessageBase : MessageBase
{
   //
}

/// 
/// 聊天消息
/// 

[Serializable]
public class P2P_TalkMessage : P2P_MessageBase
{
   private string message;
   
   public P2P_TalkMessage(string msg)
   {
      message = msg;
   }
   
   public string Message
   {
      get { return message; }
   }
}

/// 
/// UDP打洞测试消息
/// 

[Serializable]
public class P2P_HolePunchingTestMessage : P2P_MessageBase
{
   private string _UserName;
   
   public P2P_HolePunchingTestMessage(string userName)
   {
      _UserName = userName;
   }
   
   public string UserName
   {
      get { return _UserName; }
   }
}

/// 
/// 收到消息的回复确认
/// 如A与B想建立通话通道,些命令由B发出确认打洞成功
/// 

[Serializable]
public class P2P_HolePunchingResponse : P2P_MessageBase
{
   private string _UserName;
   
   public P2P_HolePunchingResponse(string userName)
   {
      _UserName = userName;
   }
   
   public string UserName
   {
      get { return _UserName; }
   }
}
#endregion

6.5 定义用户的动作
/// 
/// 用户动作
/// 

public enum UserAction
{
   Login,
   Logout

.... more action
}

该文章在 2021/2/2 11:54:37 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved