首页 > 代码库 > 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
            {

            }
        }
    }
}