基于UDP协议的Socket服务器
来源:互联网 发布:新倩女幽魂网游mac 编辑:程序博客网 时间:2024/06/08 20:48
上篇文章介绍了自己开发的基于TCP协议的服务器,也具有一定的扩展性;既然做了TCP的,那自然就得把UDP的也研究下,因此本篇文章将探讨下基于UDP协议的服务器。
废话少说,下面开始介绍思路,由于UDP是无连接的,所以相对于TCP协议的服务器就简单很多,不需要去监听客户端,也不需要对会话进行维护,只需要对数据进行相应的处理就可以;因此整体思路就很明显了,用异步方式来接收客户端的数据,将数据放入队列中,用一个线程组来处理队列中的数据,每次从队列中取一个数据包进行处理,对于线程组中线程数可根据实际情况设定,首先给出成员定义:
private Socket server = null; private bool serverStart = false;//服务器是否启动 private int serverPort = 3130;//服务器端口 private int clientPort = 3131;//远程客户端端口 private IPAddress localIp;//服务器绑定的IP地址 private string brodcastIp;//广播IP地址 private byte[] tempReceiveData = null;//临时数据接收器 private EndPoint tempRemotePoint = null;//远程客户端 private Queue<BufferData> receivedBuffer;//数据缓冲区 private Thread[] threadDataHandler;//数据处理线程 private int threadDataHandlerNum = 1;//数据处理线程数 private IDataHandler iRceivedDataHandler = null;//数据处理接口 private Mutex m_ServerMutex; // 只能有一个服务器
启动服务器后,绑定端口,启动数据处理线程组,开始异步接收数据:
/// <summary> /// 启动服务器 /// </summary> public void Start() { if (this.serverStart) { return;//服务器已经启动 } this.server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); this.tempReceiveData = new byte[this.server.ReceiveBufferSize]; IPAddress[] ip = Dns.GetHostAddresses(Dns.GetHostName()); IPEndPoint addr = new IPEndPoint(ip[0], this.serverPort); this.localIp = ip[0]; //算出广播IP地址 string str = this.localIp.ToString(); int len = str.LastIndexOf('.'); str = str.Substring(0, len + 1); this.brodcastIp = str + "255"; //绑定IP,端口 this.server.Bind(addr); this.serverStart = true; this.threadDataHandler = new Thread[this.threadDataHandlerNum]; for (int i = 0; i < this.threadDataHandlerNum; i++) { this.threadDataHandler[i] = new Thread(new ThreadStart(this.HandlerReceivedData)); this.threadDataHandler[i].Start(); } this.AsyncBeginReceive();//开始接收数据 }
异步接收数据及其回调函数:
/// <summary> /// 异步接收数据 /// </summary> private void AsyncBeginReceive() { try { if (this.serverStart) { this.server.BeginReceiveFrom(this.tempReceiveData, 0, this.server.ReceiveBufferSize, SocketFlags.None,
ref this.tempRemotePoint, this.AsyncReceiveCallback, this); } } catch { } } /// <summary> /// 异步接收数据的回调函数 /// </summary> /// <param name="iar"></param> private void AsyncReceiveCallback(IAsyncResult iar) { try { iar.AsyncWaitHandle.Close(); if (this.serverStart) { AsyncBeginReceive(); int byteReadLen = this.server.EndReceiveFrom(iar, ref this.tempRemotePoint); byte[] temp = new byte[byteReadLen]; Array.Copy(this.tempReceiveData, temp, byteReadLen); BufferData buffer = new BufferData(this.tempRemotePoint, temp); this.receivedBuffer.Enqueue(buffer); } } catch { } }
异步发送数据及其回调函数:
/// <summary> /// 开始异步发送数据 /// </summary> /// <param name="buffer"></param> private void AsyncBeginSend(IPAddress ip, string data) { try { byte[] byteData = Encoding.ASCII.GetBytes(data); EndPoint iep = (EndPoint)new IPEndPoint(ip, this.clientPort); this.server.BeginSendTo(byteData, 0, byteData.Length, SocketFlags.None, iep,
new AsyncCallback(this.AsyncSendCallback), this); } catch { } } /// <summary> /// 开始异步发送数据 /// </summary> /// <param name="ip"></param> /// <param name="data"></param> private void AsyncBeginSend(string ip, int port, string data) { try { byte[] byteData = Encoding.ASCII.GetBytes(data); EndPoint iep = (EndPoint)new IPEndPoint(IPAddress.Parse(ip), port); this.server.BeginSendTo(byteData, 0, byteData.Length, SocketFlags.None, iep,
new AsyncCallback(this.AsyncSendCallback), this); } catch { } } /// <summary> /// 异步发送数据的回调 /// </summary> /// <param name="iar"></param> private void AsyncSendCallback(IAsyncResult iar) { try { this.server.EndSendTo(iar); iar.AsyncWaitHandle.Close(); } catch { } }
缓冲区数据处理函数:
/// <summary> /// 处理缓冲区中的数据 /// </summary> /// <summary> /// 处理缓冲区中的数据 /// </summary> private void HandlerReceivedData() { while (this.serverStart) { lock (this.receivedBuffer) { if (this.receivedBuffer.Count == 0) continue; BufferData buffer = this.receivedBuffer.Dequeue(); if (this.iRceivedDataHandler != null) this.iRceivedDataHandler.ReceivedDataHandler(buffer); } } }
数据处理线程组中的每个线程都会调用该函数,所以加个锁是必要的,对于数据的解析,给出了相应的数据接口,只要实现该接口即可实现其数据的处理,如向数据库存储,对数据的判断,向客户端回复等,都可以在该接口中去实现,因此具有一定的灵活性。
数据接口很简单:
public interface IDataHandler { /// <summary> /// 数据处理接口 /// </summary> /// <param name="buffer"></param> void ReceivedDataHandler(BufferData buffer); }
对于该接口,朋友们可以自己根据需要进行扩展。
指定客户端发送,广播,多播的实现:
/// <summary> /// 向指定客户端发送数据 /// </summary> /// <param name="ip">客户端IP</param> /// <param name="data">数据</param> public void SendToClient(IPAddress ip, string data) { if (this.serverStart) { this.server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); this.AsyncBeginSend(ip, data); } } /// <summary> /// 向指定客户端发送数据 /// </summary> /// <param name="ip"></param> /// <param name="data"></param> public void SendToClient(string ip, string data) { this.SendToClient(IPAddress.Parse(ip), data); } /// <summary> /// 向指定IP,指定端口的客户机发送数据 /// </summary> /// <param name="ip">Ip地址</param> /// <param name="port">端口号</param> /// <param name="data">数据</param> public void SendToClient(string ip, int port, string data) { if (this.serverStart) { this.server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); this.AsyncBeginSend(ip, port, data); } } /// <summary> /// 广播 /// </summary> /// <param name="data"></param> public void Broadcast(string data) { this.SendToClient(this.brodcastIp, data); } /// <summary> /// 在指定端口上广播数据 /// </summary> /// <param name="data">数据</param> /// <param name="port">端口号</param> public void Broadcast(string data,int port) { this.SendToClient(this.brodcastIp, port, data); } /// <summary> /// 多路广播 /// </summary> /// <param name="ipAddress"></param> public void Multicast(string data) { if (this.serverStart) { this.server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); this.AsyncBeginSend(IPAddress.Broadcast, data); } } /// <summary> /// 指定端口进行多路广播 /// </summary> /// <param name="data"></param> /// <param name="port"></param> public void Multicast(string data, int port) { if (this.serverStart) { this.server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); this.AsyncBeginSend(IPAddress.Broadcast.ToString(), port, data); } }
希望以上代码会对有需要的朋友有些帮助,也希望和大家一起共同进步,呵呵,加油! 源代码稍候会在我的下载资源http://download.csdn.net/detail/wdx888中给出。
- 基于UDP协议的Socket服务器
- 基于UDP协议的socket
- Socket网络程序设计(2) ———— 基于UDP协议的客户-服务器socket实例
- 创建基于UDP协议的socket通讯
- 基于TCP/UDP协议的Socket流程
- 基于UDP/IP 协议的Socket程序
- 基于UDP协议的socket编程
- 基于UDP协议的socket通信
- 基于UDP协议的Socket通信
- 基于Socket的UDP和TCP协议
- 基于UDP协议的Socket网络编程
- 基于UDP协议的Socket编程
- 基于LwIP socket的UDP服务器
- 网络编程(5)—— 基于Linux系统的UDP协议socket服务器和客户端
- 网络编程(6)—— 基于Windws系统的UDP协议socket服务器和客户端
- 基于UDP协议的服务器/客户端程序
- 基于UDP协议的服务器/客户端程序
- 基于UDP协议的服务器/客户端
- http://hi.baidu.com/cyberzeus/home
- 使用两个队列实现一个栈,使用两个栈实现一个队列!
- C# 启用Lync用户
- 对http提出Get请求,获取网页内容
- Ubuntu 11.04更改分辨率
- 基于UDP协议的Socket服务器
- 配置NHibernate有三种常见的配置方法
- Android 基础-生词
- soap请求体
- 序言
- 正则表达式
- QC/T 568—1999 汽车机械式变速器 台架试验方法
- JS正则注意事项
- Shell 脚本专家指南 学习笔记2 数据重定向