首页 > 代码库 > TCP/IP异步通讯服务端实现方法
TCP/IP异步通讯服务端实现方法
近期做了个TCP/IP异步通讯服务端实现方法,也是在网上胡乱搜索,然找了个自认为比较好的,然后封装一下,供后面自个使用,也供大家参考,如有不好的地方,欢迎指正,谢谢!
下面说一下这个方法里面的几个知识点:
1、托管
这个东西真心好用,虽然不知道具体怎么弄的,托管可以实现一个对象中的方法交由其他对象实现,而且可以同时触发多个方法,组件的触发函数就是由托管实现的,具体实现如下:
先声明一个托管的方法类型
public delegate void RecieveMsg(string IP_addr, int port, byte[] bytes, int length);
然后使用该托管类型声明一个方法
public event RecieveMsg OnRecieve;
最后直接在其他方法中调用该方法就可以了,如下
if (bytesRead > 0)//接收到数据 { OnRecieve(client.IP_addr, client.Port, client.rec_buffer, bytesRead);//数据处理,由外部调用提供函数 }
外部实现该方法时(注意里面有个小知识点,将string类型转换为char[] 类型方法:Encoding.UTF8.GetBytes())
socket_server.OnRecieve += new AsyncSocketServer.RecieveMsg(RecieveHandle); private void RecieveHandle(string IP_addr, int port, byte[] bytes, int length) { string strFileName = @"d:/data.txt"; if (!File.Exists(strFileName)) { File.CreateText(strFileName); } string temp; FileStream fs = new FileStream(strFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); temp = "\r\n" + IP_addr + " " + port.ToString() + ":"; fs.Position = fs.Length; fs.Write(Encoding.UTF8.GetBytes(temp), 0, temp.Length); fs.Position = fs.Length; fs.Write(bytes, 0, length); fs.Close(); socket_server.Send(IP_addr, port, bytes, length); }
2、刷新连接状态
使用异步通信不能实时获得各路client连接的状态,这里有个方法可以实现,当返回为真,则说明连接中断,该部分放在一个定时函数中定时执行:
if (((socket.Poll(1000, SelectMode.SelectRead) && (socket.Available == 0)) || !socket.Connected)) //连接中断 { }
3、设置系统定时函数,注意在windows服务中一般是不允许出现窗体的,所以在函数中对form类的一些控件建议不要使用,虽然编译不会出错,但控件对应的方法却不会执行。
先声明一个定时器:
System.Timers.Timer updata_time;初始化定时器:
updata_time = new System.Timers.Timer(1000);//定时1s updata_time.Enabled = true;//使能定时器 updata_time.AutoReset = true;//设置为循环执行 updata_time.Elapsed += new System.Timers.ElapsedEventHandler(this.updata_time_Tick);最后实现定时调用的函数 updata_time_Tick。
4、重载,本次使用了一个单独的类来封装客户端,为了便于集成管理,需要对一些方法重载,如Equals,特别是对ArrayList类,所有涉及到查找的方法都涉及到Equals方法,其重载实现如下:
public override bool Equals(Object obj) { IP_Port IP_port = obj as IP_Port;//传入参数为 IP_Port if (IP_port != null) { if ((IP_port.IP_addr == this.IP_addr) && (IP_port.port == this.Port)) { return true; } else { return false; } } Client client = obj as Client;//传入参数为Client if (client != null) { if ((client.IP_addr == this.IP_addr) && (client.Port == this.Port)) { return true; } else { return false; } } return false; }注意里面 IP_Port IP_port = obj as IP_Port 可以判断传入的参数是什么类型,这样可以根据不同的传入参数做不同的方法,增加灵活性。
其他的方法是用如下:
clients.Remove(clients[i]); int index = clients.IndexOf(ip_port);
这个类的使用方法很简单:
AsyncSocketServer socket_server; socket_server.OnRecieve += new AsyncSocketServer.RecieveMsg(RecieveHandle); socket_server.OnSend += new AsyncSocketServer.SendMsg(SendBackHandle); socket_server.OnException += new AsyncSocketServer.ExceptionMsg(ExceptionHandle); socket_server.StartListen();还有在结束时调用StopListen()
具体源文件如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Runtime; using System.Net; using System.Net.Sockets; using System.Threading; using System.Collections; namespace AsyncSocketServerApp { class AsyncSocketServer { #region 公共成员 public int port;//需要监听的本机端口号 public delegate void RecieveMsg(string IP_addr, int port, byte[] bytes, int length);//接受数据后,需要外部函数来处理 public event RecieveMsg OnRecieve; public delegate void SendMsg(string IP_addr, int port, int length);//发送数据完成后,需要外部函数来处理 public event SendMsg OnSend; public delegate void ExceptionMsg(string IP_addr, int port, Exception e);//发生异常函数 public event ExceptionMsg OnException; #endregion #region 私有成员 private Socket socket; private ArrayList clients; static private bool bListening = false; Thread thread; System.Timers.Timer updata_time; #endregion #region 公共方法 public AsyncSocketServer() { port = 1234;//默认端口号 SystemInit(); } public AsyncSocketServer(int _port) { port = _port;//默认端口号 SystemInit(); } ~AsyncSocketServer()//析构函数 { try { socket.Shutdown(SocketShutdown.Both); socket.Close(); } catch { } } public void StartListen()//开始监听 { if (bListening == false) { thread = new Thread(new ThreadStart(this.SocketInit)); bListening = true; thread.Start(); } } public void StopListen()//停止监听 { if (bListening == true) { try { socket.Shutdown(SocketShutdown.Both); } catch { } socket.Close(); thread.Abort(); bListening = false; } } public int Send(string IP_addr, int port, byte[] bytes, int length)//发送数据到客户端 { if (clients.Count == 0) return -1; IP_Port ip_port = new IP_Port(IP_addr, port); int index = clients.IndexOf(ip_port); if (index < 0) return -1; Client client = (Client)clients[index]; client.socket.BeginSend(bytes, 0, length, 0, new AsyncCallback(SendCallback), client); return length; } public ArrayList GetClientList()//获取客户端列表 { ArrayList client_list = new ArrayList(); IP_Port ip_port; Monitor.Enter(clients);//获取对象锁防止在访问clients时updata_time_Tick线程修改 add by LC 2014.08.18 11:14 try { if (clients.Count == 0) return null; foreach (Object obj in clients) { Client client = (Client)obj; ip_port = new IP_Port(client.IP_addr, client.Port); client_list.Add(ip_port); } } finally { Monitor.Exit(clients); }//释放该对象,必须执行 add by LC 2014.08.18 11:15 return client_list; } #endregion private void SystemInit()//form类的定时器改成System.Timers.Timer类 modfiy by LC 2014.08.14 16:51 { clients = new ArrayList(); updata_time = new System.Timers.Timer(1000);//定时1s updata_time.Enabled = true;//使能定时器 updata_time.AutoReset = true;//设置为循环执行 updata_time.Elapsed += new System.Timers.ElapsedEventHandler(this.updata_time_Tick); } private void SocketInit() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ip_end_point = new IPEndPoint(IPAddress.Any, port); socket.Bind(ip_end_point); socket.Listen(int.MaxValue);//开始监听,可连接数量设为最大 socket.BeginAccept(new AsyncCallback(AcceptCallback), socket); } private void AcceptCallback(IAsyncResult ar) { try { Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); EndPoint ip = handler.RemoteEndPoint; Client client = new Client(); client.socket = handler; //IP_Port ip_port = new IP_Port((handler.RemoteEndPoint as IPEndPoint).Address.ToString() , (handler.RemoteEndPoint as IPEndPoint).Port); if (!clients.Contains(client))//判断原来有没有连接,若没有,则添加到客户端列表 { clients.Add(client); } handler.BeginReceive(client.rec_buffer, 0, Client.BufferSize, 0, new AsyncCallback(ReadCallback), client); listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);//继续侦听其他连接 } catch { } } private void ReadCallback(IAsyncResult ar) { Client client = (Client)ar.AsyncState; try { Socket handler = client.socket; int bytesRead = handler.EndReceive(ar); if (bytesRead > 0)//接收到数据 { OnRecieve(client.IP_addr, client.Port, client.rec_buffer, bytesRead);//数据处理,由外部调用提供函数 } handler.BeginReceive(client.rec_buffer, 0, Client.BufferSize, 0, new AsyncCallback(ReadCallback), client); } catch(Exception re) { OnException(client.IP_addr, client.Port, re); } } private void SendCallback(IAsyncResult ar)//发送成功后的回调函数 { Client client = (Client)ar.AsyncState; try { int bytes_sent = client.socket.EndSend(ar); OnSend(client.IP_addr, client.Port, bytes_sent);//发送成功后返回 } catch (Exception re) { OnException(client.IP_addr, client.Port, re); } } private void updata_time_Tick(object sender, EventArgs e)//1s执行一次 { if (clients.Count == 0) return; Monitor.Enter(clients);// add by LC 2014.08.18 11:17 try { for (int i = 0; i < clients.Count; i++) { Socket socket = ((Client)clients[i]).socket;//指向错误 modfiy by LC 2014.08.14 16:58 if (((socket.Poll(1000, SelectMode.SelectRead) && (socket.Available == 0)) || !socket.Connected)) //连接中断 { //socket.Shutdown(SocketShutdown.Both); //socket.Close(); //MessageBox.Show((socket.RemoteEndPoint as IPEndPoint).Address.ToString() + ":" + (socket.RemoteEndPoint as IPEndPoint).Port.ToString() + "连接中断"); clients.Remove(clients[i]); } } } catch (Exception re) { OnException("updata list ", 0, re); } Monitor.Exit(clients);// add by LC 2014.08.18 11:17 } } public class IP_Port { public string IP_addr; public int port; public IP_Port(string e_IP, int e_port) { IP_addr = e_IP; port = e_port; } } public class Client { private int _port;//端口号 private string _IP_addr;//IP号 public Socket socket; public static int BufferSize = 1024; // Receive buffer. public byte[] rec_buffer = new byte[BufferSize]; // Received data string. ~Client() { socket.Shutdown(SocketShutdown.Both); socket.Close(); } public int Port//读取端口号 { get { _port = (socket.RemoteEndPoint as IPEndPoint).Port; return _port; } } public string IP_addr { get { _IP_addr = (socket.RemoteEndPoint as IPEndPoint).Address.ToString(); return _IP_addr; } } public override bool Equals(Object obj) { IP_Port IP_port = obj as IP_Port;//传入参数为 IP_Port if (IP_port != null) { if ((IP_port.IP_addr == this.IP_addr) && (IP_port.port == this.Port)) { return true; } else { return false; } } Client client = obj as Client;//传入参数为Client if (client != null) { if ((client.IP_addr == this.IP_addr) && (client.Port == this.Port)) { return true; } else { return false; } } return false; } public override int GetHashCode() { return Port; } public void RelaseTcpClient()//释放TcpClient资源 { try { socket.Shutdown(SocketShutdown.Both); socket.Close(); socket.Close(); } catch { } } } }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。