异步Socket服务器及客户端

using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;

namespace SocketServer
{
    /// <summary>
    /// 网络通讯事件模型委托
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e">与客户端的连接类</param>
    public delegate void NetEvent(object sender, TcpTranslate e);

    /// <summary>
    /// 监听端口,接受多客户的TCP连接
    /// </summary>
    public class TcpServer
    {
        #region 事件定义
        /// <summary>
        /// 接收客户端连接事件
        /// </summary>
        public event NetEvent Connected;
        /// <summary>
        /// 与客户端连接断开事件
        /// </summary>
        public event NetEvent DisConnect;
        #endregion

        #region 字段
        private int maxsockets = 10000;                 //最大客户连接数
        private IPEndPoint iep;                         //监听终结点
        private TcpListener listener;                   //监听类
        private Dictionary<EndPoint, TcpTranslate> session;
        #endregion

        #region 属性
        /// <summary>
        /// 当前客户连接数
        /// </summary>
        public int ConnectCount
        {
            get { return session.Count; }
        }
        /// <summary>
        /// 与客户连接的所有Socket
        /// </summary>
        public Dictionary<EndPoint, TcpTranslate> Session
        {
            get { return session; }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">监听的端口号</param>
        /// <param name="maxsocket">最大客户连接量</param>
        public TcpServer(int maxsockets, string IP, int port)
        {
            this.maxsockets = maxsockets;
            iep = new IPEndPoint(IPAddress.Parse(IP), port);
        }
        public TcpServer(int port)
        {
            iep = new IPEndPoint(IPAddress.Parse("0.0.0.0"), port);
        }
        #endregion

        #region 公用方法
        /// <summary>
        /// 启动服务器程序,开始监听客户端请求
        /// </summary>
        public void Start()
        {
            session = new Dictionary<EndPoint, TcpTranslate>();
            listener = new TcpListener(iep);
            listener.Start(10);
            //监听客户端连接请求
            listener.BeginAcceptSocket(
                new AsyncCallback(clientConnect), listener);
        }
        private void clientConnect(IAsyncResult ar)
        {
            //接受客户的连接,得连接Socket
            Socket socket = listener.EndAcceptSocket(ar);
            TcpTranslate trans = new TcpTranslate(socket);
            //trans.DisConnect += new NetEvent(trans_DisConnect);
            //开始接受数据
            trans.StartReceive();

            //客户端连接成功事件
            if (Connected != null) Connected(this, trans);
            TcpTranslate.WriteLine(trans.RemoteEndPoint.ToString() + " is Connection...Num" + session.Count.ToString());
            if (session.ContainsKey(trans.RemoteEndPoint))
            {
                session[trans.RemoteEndPoint] = trans;
            }
            else
            {
                session.Add(trans.RemoteEndPoint, trans);
            }
            if (ConnectCount < maxsockets)
            {
                //继续监听客户端连接请求
                listener.BeginAcceptSocket(
                    new AsyncCallback(clientConnect), listener);
            }
            else
            {   //达到最大连接客户数,则关闭监听.
                listener.Stop();
            }
        }

        //客户端断开连接
        void trans_DisConnect(object sender, Socket e)
        {
            //如果已关闭侦听器,则打开,继续监听
            TcpTranslate trans = (TcpTranslate)sender;
            if (ConnectCount == maxsockets)
            {
                listener.Start(1);
                listener.BeginAcceptSocket(
                    new AsyncCallback(clientConnect), listener);
            }
            session.Remove(trans.RemoteEndPoint);
            //触发客户断开事件
            if (DisConnect != null) { DisConnect(this, trans); }
            TcpTranslate.WriteLine(trans.RemoteEndPoint.ToString() + " is DisConnect...Num" + session.Count.ToString());
        }
        #endregion
    }

    #region 传输对象类
    /// <summary>
    /// 传输对象类,接收缓冲区为默认值 8192 个字节。
    /// </summary>
    public class TcpTranslate
    {
        #region 网络事件
        /// <summary>
        /// 连接成功事件
        /// </summary>
        public event NetEvent Connect;
        /// <summary>
        /// 断开连接事件
        /// </summary>
        public event NetEvent DisConnect;
        /// <summary>
        /// 接收到数据事件
        /// </summary>
        public event NetEvent Receive;
        /// <summary>
        /// 接收到文本事件
        /// </summary>
        public event NetEvent ReceiveText;
        /// <summary>
        /// 接收完文件事件
        /// </summary>
        public event NetEvent ReceiveFile;
        /// <summary>
        /// 接收完对象事件
        /// </summary>
        public event NetEvent ReceiveObje;
        #endregion

        #region 字段
        private Socket socket;              // 客户连接类
        private Stream bufferObject;        // 缓存所有接收到的对象数据
        private Stream bufferFile;          // 缓存所有接收到的文件数据
        private int recObjeLen = -1;        // 接收到的对象的长度
        private int recFileLen = -1;        // 接收到的文件的长度
        string filePath = @"c:/temp/";      //文件的保存位置
        string fileName;
        //private List<string> bufferText;  // 缓存所有接收到的文本
        private IPEndPoint iep;

        private bool allowSendText = true;
        private bool allowSendObje = true;
        private bool allowSendFile = true;
        private bool isConnected;

        const int bufferLen = 8192;         //缓存大小
        const int headLen = 4;              //包头大小,用于保存要发送数据的总长度
        const int headLens = 5;             //第一包包头大小
        //包头第一个字节,表示此包所包含的内容
        readonly byte[] textHead = new byte[] { 0 };//文本
        readonly byte[] objeHead = new byte[] { 1 };//对象
        readonly byte[] fileHead = new byte[] { 2 };//文件
        int receiveBigs;                    //接收到的包数
        //int sendBigs;                       //发送的包数
        #endregion

        #region 属性
        public EndPoint RemoteEndPoint
        {
            get { return this.socket.RemoteEndPoint; }
        }
        public bool Connected
        {
            get { return this.socket.Connected; }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 服务器端调用此构造函数
        /// </summary>
        /// <param name="socket">Socket成功连接的Socket</param>
        public TcpTranslate(Socket socket)
        {
            this.socket = socket;
            this.socket.ReceiveBufferSize = bufferLen;
            this.isConnected = true;
        }
        /// <summary>
        /// 客户端调用此构造函数
        /// </summary>
        /// <param name="ip">要连接的服务器IP</param>
        /// <param name="port">要连接的端口</param>
        public TcpTranslate(string ip, int port)
        {
            iep = new IPEndPoint(IPAddress.Parse(ip), port);
            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.socket.ReceiveBufferSize = bufferLen;
            this.isConnected = false;
        }
        #endregion

        [System.Diagnostics.Conditional("DUBUG")]
        public static void WriteLine(string message)
        {
            Console.WriteLine(message);
        }
        /// <summary>
        /// 开始接收数据
        /// </summary>
        public void StartReceive()
        {
            if (isConnected)
            {
                byte[] bytes = new byte[bufferLen];
                this.socket.BeginReceive(bytes, 0, bufferLen, SocketFlags.None,
                    new AsyncCallback(ReceivceData), bytes);
            }
            else
            {
                this.socket.BeginConnect(iep, new AsyncCallback(connected), socket);
            }
        }
        private void connected(IAsyncResult iar)
        {
            isConnected = true;
            if (Connect != null) Connect(this, this);
            byte[] bytes = new byte[bufferLen];
            this.socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None,
                new AsyncCallback(ReceivceData), bytes);
        }

        /// <summary>
        /// 接收数据回调函数
        /// </summary>
        /// <param name="ar"></param>
        private void ReceivceData(IAsyncResult ar)
        {
            try
            {
                //接收到的数据长度.
                SocketError sErr;
                int receLen = this.socket.EndReceive(ar, out sErr);
                if (receLen > 0)
                {
                    byte[] receBytes = (byte[])ar.AsyncState;
                    switch (receBytes[0])
                    {
                        case 0:     //接收到文本
                            ReceivceText(receLen, receBytes);
                            break;
                        case 1:     //接收到对象
                            ReceivceObje(receLen, receBytes);
                            break;
                        case 2:     //接收到文件
                            ReceivceFile(receLen, receBytes);
                            break;
                        default:    //接收错误
                            WriteLine("错误的数据包: 包头为" + receBytes[0].ToString());
                            WriteLine(sErr.ToString());
                            break;

                    }
                    //继续接收数据
                    byte[] bytes = new byte[bufferLen];
                    this.socket.BeginReceive(bytes, 0, bytes.Length, SocketFlags.None,
                       new AsyncCallback(ReceivceData), bytes);
                    return;
                }
            }
            catch (SocketException socketErr)
            {
                WriteLine(socketErr.Message);
            }
            catch (ObjectDisposedException socketClose)
            {
                WriteLine(socketClose.Message);
            }
            catch (Exception err)
            {
                WriteLine(err.Message);
            }
            //断开连接事件
            if (DisConnect != null) DisConnect(socket, this);
            this.recObjeLen = -1;
            this.recFileLen = -1;
        }

        void ReceivceObje(int receLen, byte[] receBytes)
        {
            //读第一包.得到本次要接收的数据包的总长
            if (recObjeLen == -1 && receLen > headLen)
            {
                this.recObjeLen = Buffer.Bin2Int(new byte[] {
                            receBytes[1], receBytes[2], receBytes[3], receBytes[4] });
                WriteLine("总长度为:"  + recObjeLen.ToString());
                this.bufferObject = new MemoryStream();
                //不只一包(第一包不为最后一包)
                if (this.recObjeLen > bufferLen - headLens)
                {
                    this.bufferObject.Write(receBytes, headLens, receLen - headLens);
                }
                else
                {
                    this.bufferObject.Write(receBytes, headLens, recObjeLen);
                    reObjeEnd();
                }
            }

            //最后一包
            else if (this.bufferObject.Length + (bufferLen - 1) >= this.recObjeLen)
            {
                int lastLen = (int)(this.recObjeLen - this.bufferObject.Length);
                this.bufferObject.Write(receBytes, 1, lastLen);
                reObjeEnd();
            }
            else
            {
                this.bufferObject.Write(receBytes, 1, receLen - 1);
                //接收到数据事件
                if (Receive != null) { Receive(receBytes, this); }
                receiveBigs++;
                WriteLine(receiveBigs.ToString() + "  " + bufferObject.Length.ToString());
            }
        }
        void reObjeEnd()
        {
            object obj;
            lock (bufferObject)
            {
                this.recObjeLen = -1;
                BinaryFormatter formatter = new BinaryFormatter();
                bufferObject.Position = 0;
                obj = formatter.Deserialize(bufferObject);
            }
            //接收完数据事件
            if (ReceiveObje != null) { ReceiveObje(obj, this); }
            WriteLine("对象接收完成  " + obj.GetType().ToString() + "   " + obj.ToString());
        }
        void ReceivceFile(int receLen, byte[] receBytes)
        {
            //读第一包.得到本次要接收的数据包的总长
            if (recFileLen == -1 && receLen > headLen)
            {
                this.recFileLen = Buffer.Bin2Int(new byte[] {
                            receBytes[1], receBytes[2], receBytes[3], receBytes[4] });
                WriteLine("总长度为:" + recFileLen.ToString());
                this.bufferFile = new MemoryStream();
                this.bufferFile.Write(receBytes, headLens, receLen - headLens);
                do
                {
                    fileName = filePath + DateTime.Now.ToFileTime().ToString();
                }
                while (File.Exists(this.fileName));
                this.bufferFile = File.Create(fileName);

                //不只一包
                if (this.recFileLen > bufferLen - headLens)
                {
                    this.bufferFile.Write(receBytes, headLens, receLen - headLens);
                }
                else //第一包为最后一包
                {
                    this.bufferFile.Write(receBytes, headLens, recFileLen);
                    reFileEnd();
                }
            }
            //最后一包
            else if (this.bufferFile.Length + (bufferLen - 1) >= this.recFileLen)  //是否最后一包
            {
                int lastLen = (int)(this.recFileLen - this.bufferFile.Length);
                this.bufferFile.Write(receBytes, 1, lastLen);
                reFileEnd();
            }
            else
            {
                this.bufferFile.Write(receBytes, 1, receLen - 1);
                //接收到数据事件
                if (Receive != null) { Receive(receBytes, this); }
                receiveBigs++;
                WriteLine(receiveBigs.ToString() + "  " + bufferFile.Length.ToString());
            }
        }
        void reFileEnd()
        {
            lock (bufferFile)
            {
                this.recFileLen = -1;
                bufferFile.Close();
            }
            //接收完数据事件
            if (ReceiveFile != null) { ReceiveFile(this.fileName, this); }
            WriteLine("文件接收完成");
        }

        void ReceivceText(int receLen, byte[] receBytes)
        {
            string reStr = Encoding.Default.GetString(receBytes, 1, receLen - 1).TrimEnd('/u0000');
            //接收完数据事件
            if (ReceiveText != null) { ReceiveText(reStr, this); }
            WriteLine(reStr);
        }

        #region 发送数据
        /// <summary>
        /// 发送文本
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public bool SendText(string text)
        {
            if (allowSendText)
            {
                this.allowSendText = false;                                         //禁止发送文本
                Stream stream = new MemoryStream(Encoding.Default.GetBytes(text));  //得到文本的内存流
                StateBig stateBig = new StateBig(textHead, stream);                 //用于格式化流的对象
                byte[] bytes = new byte[bufferLen];                                 //初始化发送包
                if (stateBig.GetData(ref bytes) > 0)                                //向包中填数据
                {
                    this.socket.BeginSend(bytes, 0, bufferLen, SocketFlags.None,     //开始异步发送
                         new AsyncCallback(sendCallback), stateBig);
                }
                else
                {
                    this.socket.Send(new byte[] { });
                    this.allowSendText = true;
                }
                return true;
            }
            return false;
        }
        /// <summary>
        /// 发送对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool SendObject(Object obj)
        {
            if (allowSendObje)
            {
                this.allowSendObje = false;                                             //禁止发送对象
                Stream stream = Buffer.GetStream(obj);                                  //得到对象的内存流
                stream.Position = 0;
                StateBig stateBig = new StateBig(objeHead, stream);                     //用于格式化流的对象
                byte[] bytesFrist = new byte[bufferLen - headLen];                      //初始化发送包
                if (stateBig.GetData(ref bytesFrist) > 0)                               //向包中填数据
                {
                    byte[] bytes = new byte[bufferLen];
                    byte[] head = Buffer.Int2Bin((int)stream.Length);                   //构造包头.包头含有发送的数据的大小
                    Array.Copy(bytesFrist, 0, bytes, 0, objeHead.Length);               //复制文件头标识
                    Array.Copy(head, 0, bytes, objeHead.Length, headLen);               //复制要传送的文件的大小标识
                    int headLens = objeHead.Length + head.Length;
                    Array.Copy(bytesFrist, 1, bytes, headLens, bufferLen - headLens);  //复制数据
                    this.socket.BeginSend(bytes, 0, bufferLen, SocketFlags.None,        //开始异步发送
                         new AsyncCallback(sendCallback), stateBig);
                }
                else
                {
                    this.socket.Send(new byte[] { });
                    this.allowSendObje = true;
                }
                return true;
            }
            return false;
        }
        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns></returns>
        public bool SendFile(string filePath)
        {
            if (allowSendFile && File.Exists(filePath))
            {
                this.allowSendFile = false;                                             //禁止发送文件
                Stream stream = File.OpenRead(filePath);                                //得到文件流
                stream.Position = 0;
                StateBig stateBig = new StateBig(fileHead, stream);                     //用于格式化流的对象
                byte[] bytesFrist = new byte[bufferLen - headLen];                      //初始化发送包
                if (stateBig.GetData(ref bytesFrist) > 0)                               //向包中填数据
                {
                    byte[] bytes = new byte[bufferLen];
                    byte[] head = Buffer.Int2Bin((int)stream.Length);                   //构造包头.包头含有发送的数据的大小
                    Array.Copy(bytesFrist, 0, bytes, 0, objeHead.Length);               //复制文件头标识
                    Array.Copy(head, 0, bytes, objeHead.Length, headLen);               //复制要传送的文件的大小标识
                    int headLens = objeHead.Length + head.Length;
                    Array.Copy(bytesFrist, 1, bytes, headLens, bufferLen - headLens);   //复制数据
                    this.socket.BeginSend(bytes, 0, bufferLen, SocketFlags.None,        //开始异步发送
                         new AsyncCallback(sendCallback), stateBig);
                }
                else
                {
                    this.socket.Send(new byte[] { });
                    this.allowSendFile = true;
                }
                return true;
            }
            return false;
        }


        /// <summary>
        /// 异步发送回调函数
        /// </summary>
        /// <param name="ar">包含要发送的数据流及数据包的包头</param>
        private void sendCallback(IAsyncResult ar)
        {
            StateBig stateBig = (StateBig)ar.AsyncState;                            //得到包含要发送的数据流的对象
            int sent = this.socket.EndSend(ar);
            byte[] bytes = new byte[bufferLen];
            if (stateBig.GetData(ref bytes) > 0)
            {
                this.socket.BeginSend(bytes, 0, bufferLen, SocketFlags.None,
                    new AsyncCallback(sendCallback), stateBig);
            }
            else
            {
                byte headNum = stateBig.BigHead[0];
                switch (headNum)
                {
                    case 0:
                        this.allowSendText = true; break;
                    case 1:
                        this.allowSendObje = true; break;
                    case 2:
                        this.allowSendFile = true; break;
                    default:
                        break;
                }
                stateBig.Close();
            }
        }
        #endregion

        /// <summary>
        /// 从流中读出数据转化为格式化的包.
        /// </summary>
        public class StateBig
        {
            private byte[] bigHead;
            private Stream stream;
            public byte[] BigHead
            {
                get { return bigHead; }
            }
            public Stream Stream
            {
                get { return stream; }
            }
            public StateBig(byte[] bigHead, Stream stream)
            {
                this.bigHead = bigHead;
                this.stream = stream;
                this.stream.Position = 0;
            }
            ~StateBig()
            {
                this.bigHead = null;
                this.stream.Close();
            }
            public int GetData(ref byte[] bytes)
            {
                Array.Copy(bigHead, 0, bytes, 0, bigHead.Length);
                int readNum = stream.Read(bytes, bigHead.Length, bytes.Length - bigHead.Length);
                return readNum;
            }
            public void Close()
            {
                this.bigHead = null;
                this.stream.Close();
            }
        }

    }
    #endregion

    #region INT to BIN
    public class Buffer
    {
        /// <summary>
        /// 将Int转换为Byte[4]
        /// </summary>
        public static byte[] Int2Bin(int intNum)
        {
            byte[] byteNew = new byte[4];
            for (byte i = 0; i < 4; i++)
            {
                byteNew[i] = (byte)(intNum % 256);
                intNum = intNum >> 8;
            }
            return byteNew;
        }
        /// <summary>
        /// 将Byte[4]数组转换为int;
        /// </summary>
        public static int Bin2Int(byte[] bytes)
        {
            int intNum = 0;
            for (byte i = 0; i < 4; i++)
            {
                intNum += bytes[i] << (i * 8);
            }
            return intNum;
        }
        /// <summary>
        /// 将uint转换为Byte[4]
        /// </summary>
        public static byte[] UInt2Bin(uint uintNum)
        {
            byte[] byteNew = new byte[4];
            for (byte i = 0; i < 4; i++)
            {
                byteNew[i] = (byte)(uintNum % 256);
                uintNum = uintNum >> 8;
            }
            return byteNew;
        }
        /// <summary>
        /// 将Byte[4]数组转换为uint;
        /// </summary>
        public static uint Bin2UInt(byte[] bytes)
        {
            uint uintNum = 0;
            for (byte i = 0; i < 4; i++)
            {
                uintNum += (uint)bytes[i] << (i * 8);
            }
            return uintNum;
        }
        public static Stream GetStream(object objData)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream objStrean = new MemoryStream();
            formatter.Serialize(objStrean, objData);
            return objStrean;
        }       
    #endregion
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值