C#里的SOCKET应用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Net.Sockets;

using System.Threading;
using System.Text.RegularExpressions;

using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime;
namespace TcpScket
{

    /// <summary>
    /// Unicode字符集:CodePage=1200
    /// </summary>
    [StructLayout(LayoutKind.Explicit,CharSet=CharSet.Unicode)]
    public class  MessageData
    {
        /// <summary>
        /// 数据报文分隔符:定长为16个不可显的ASCII字节(这是一个回定值)
        /// </summary>
        [FieldOffset(0)]
        private  byte[] MessageHeader ;
        /// <summary>
        /// 16bytes 的MD5值------非十六制格式(仅为消息体的校验)
        /// </summary>
        [FieldOffset(16)]
        private  byte[] Md5Value  ;
        /// <summary>
        /// 数据报类型
        /// </summary>
        [FieldOffset(32)]
        public   int MessageType;
        /// <summary>
        /// 主消息ID-------如果为0,就表示消息是一个独立的消息(其取值一定是一个大于>0)
        /// </summary>
        [FieldOffset(36)]
        public   int MajorMessageId;
        /// <summary>
        /// 附消息ID-------MajorMessageId==0 就是一个独立的息;MajorMessageId!=0 是MajorMesageId消息的第( MinorMessageId) 部分
        /// </summary>
        [FieldOffset(40)]
        public int MinorMessageId;
        /// <summary>
        /// 消息体的实际长度:取值为定值
        /// </summary>
        [FieldOffset(44)]
        private  int BodyLength;
        /// <summary>
        /// 保留值(暂时不可用)16字节
        /// </summary>
        [FieldOffset(48)]
        private  byte[] Reversed ;
        /// <summary>
        /// 消息体的实际数据长度(最大长度为取值为0,4,8,16,32,64,128,256,512,1024)
        /// </summary>
        [FieldOffset(64)]
        private byte[]  BodyData;


        /// <summary>
        /// 数据报中的数据
        /// </summary>
        public byte[]  PacketData
        {
            get
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    ms.Write(MessageHeader, 0, 16);
                    ms.Write(Md5Value, 0, 16);
                    ms.Write(BitConverter.GetBytes(MessageType), 0, 4);
                    ms.Write(BitConverter.GetBytes(MajorMessageId), 0, 4);
                    ms.Write(BitConverter.GetBytes(MinorMessageId), 0, 4);
                    ms.Write(BitConverter.GetBytes(BodyLength), 0, 4);
                    ms.Write(Reversed, 0, 16);
                    if (BodyLength > 0)
                    {
                        ms.Write(BodyData, 0, BodyLength);
                    }
                    return ms.ToArray();
                }
            }
        }
 
        public byte[] EntityBuffer
        {
            get { return BodyData; }
        }
        public int  EntityBufferSize
        {
            get { return BodyLength; }
        }

        public MessageData(int msgType, int majorMessageId, int minorMsgId, byte[] msg)
        {

            MessageType = msgType;
            MajorMessageId = majorMessageId;
            MinorMessageId = minorMsgId;

            MessageHeader = MessageHelper.helperInstance.MessageHeader;
            if (msg == null || msg.Length == 0)
            {
                Md5Value = MessageHelper.helperInstance.ComputeMd5Value(new byte[] { 0 });
            }
            else
            {
                Md5Value = MessageHelper.helperInstance.ComputeMd5Value(msg);
            }
            BodyLength = msg.Length;
            BodyData = msg;
            Reversed = new byte[16];

        }

        public MessageData(byte[] data)
        {
            MessageHeader = new byte[16];
            Buffer.BlockCopy(data, 0, MessageHeader, 0, 16);
            Md5Value = new byte[16];
            Buffer.BlockCopy(data, 16, Md5Value, 0, 16);
            MessageType = BitConverter.ToInt32(data, 32);
            MajorMessageId = BitConverter.ToInt32(data, 36);
            MinorMessageId = BitConverter.ToInt32(data, 40);
            BodyLength = BitConverter.ToInt32(data, 44);
            Reversed = new byte[16];
            Buffer.BlockCopy(data, 48, Reversed, 0, 16);
            if(BodyLength >0)
            {
                BodyData =new byte[BodyLength ];
                Buffer.BlockCopy(data, 64, BodyData, 0, BodyLength);
            }
        }
        
    }


    public delegate void MessageDataArrivedEventHandler(object sender, MessageData data);


    public sealed class MessageHelper
    {

        public const int CodePage = 1200;
        public const string MessageHeaderStr = "MDHZDTCP";
        private byte[] messageHeaderByte;
        private Encoding  cding;
        private System.Security.Cryptography.MD5 md5;
        private MessageHelper()
        {
            cding =Encoding.GetEncoding(1200) ;
            messageHeaderByte =cding.GetBytes(MessageHeaderStr);
            md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
        }
        public static readonly MessageHelper helperInstance = new MessageHelper();
        public Encoding Encoding
        {
            get
            {
                return cding;
            }

        }
        public Byte[] MessageHeader
        {
            get
            {
                return messageHeaderByte;
            }
        }
        public Byte[] ComputeMd5Value(byte[] input)
        {
            return  md5.ComputeHash(input);
        }
        public int IndexOfMessageHeader(byte[] buffer, int startIndex, int lastIndex)
        {


          
            if (buffer == null || buffer.Length < 16)
                return -1;
            if (startIndex < 0 || lastIndex >= buffer.Length || startIndex >=lastIndex )
                return -1;
            int mi=0;
            int b = startIndex;
            int len=buffer.Length ;
            bool find = false;
            int ipx= -1 ;

            while (b <= lastIndex   )
            {
                if (messageHeaderByte[mi] == buffer[b])
                {
                   if(ipx ==-1)
                       ipx =b ;
                    mi++;
                }
                else
                {
                    mi = 0;
                    ipx = -1;
                }
                if (mi ==16 )
                {
                    find = true;
                    break;
                }
                b++;
            }
            if (!find)
                return -1;
            return ipx ;
        }

        public bool IsStartWithMessageHeaderStr(byte[] data)
        {
            if (data == null || data.Length < 16)
                return false;
            for (int i = 0; i < 16; i++)
            {
                if (messageHeaderByte[i] != data[i])
                    return false;
            }
            return true;
        }
        public bool IsComplectedPacketData(byte[] data)
        {
            if (data == null || data.Length < 64)
#if DEBUG
            {
                Console.WriteLine(" data ==null ||  data.Length < 64");
                return false;
            }
#else
                return false;
#endif

            if (!IsStartWithMessageHeaderStr(data))
            {
#if DEBUG
                Console.WriteLine(" 包头的起始值不正确!");
#endif
                return false;
            }
            int bodyLen = BitConverter.ToInt32(data, 44);
            if(data.Length !=(64+ bodyLen ))
            {

                return false;
            }
            byte[] md5Hash = null;
            if (bodyLen == 0)
            {
                 md5Hash = MessageHelper.helperInstance.ComputeMd5Value(new byte[] { 0 });
               
            }
            else
            {
                byte[] msg = new byte[data.Length - 64];
                Buffer.BlockCopy(data, 64, msg, 0, bodyLen);
                 md5Hash = MessageHelper.helperInstance.ComputeMd5Value(msg);
            }

            for (int i = 16; i < 32; i++)
            {
                if (md5Hash[i - 16] != data[i])
                {

                    return false;
                }
            }


            return false;



        }
        
    }


 
    public class TcpScket : IDisposable
    {

        protected Socket svrSkt;
        private  ManualResetEvent hAcceptHandle = new ManualResetEvent(true);

        public List<WorketSokcet> clients = new List<WorketSokcet>();

        public TcpScket(string ipAddress, int port)
        {
            IPAddress ip = IPAddress.Parse(ipAddress);
            svrSkt = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            svrSkt.Bind(
                new IPEndPoint(
                    ip, port));

        }

        public void Run(int maxBlocking)
        {
            svrSkt.Listen(maxBlocking);
            while (true)
            {
                hAcceptHandle.WaitOne();
                svrSkt.BeginAccept(accepteCallback, svrSkt);
                hAcceptHandle.Reset();
            }
        }

        public void RegisteredWorker(WorketSokcet ws)
        {
            ws.Closed += new EventHandler(ws_Closed);
            clients.Add(ws);
        }

        void ws_Closed(object sender, EventArgs e)
        {
            clients.Remove((WorketSokcet)sender);
        }
         

        private void accepteCallback(IAsyncResult ar)
        {
            try
            {
                Socket sck = ar.AsyncState as Socket;
                Socket workerHandle = sck.EndAccept(ar);
                WorketSokcet worker = new WorketSokcet(workerHandle, this);
                worker.ReceviedMessage +=new MessageDataArrivedEventHandler(worker_ReceviedMessage);
                worker.Run();
            }
            finally
            {
                //无论如何都要放锁
                hAcceptHandle.Set();
            }

        }

        void worker_ReceviedMessage(object sender, MessageData e)
        {
            Console.WriteLine(e.MajorMessageId);
            Console.WriteLine(e.MinorMessageId);
            Console.WriteLine(e.MessageType);
            Console.WriteLine(e.EntityBufferSize);
            Console.WriteLine("=======");
             
        }






        #region IDisposable 成员

        bool disposed;
        private  void Dispose(bool disp)
        {
            if (!disposed && disp)
            {
                if (svrSkt != null)
                {
                    svrSkt.Shutdown(SocketShutdown.Both);
                    svrSkt.Close();
                }

                if (hAcceptHandle != null)
                {
                    hAcceptHandle.Close();
                    hAcceptHandle = null;
                }

                disposed = true;
            }
        }


        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion


        #region  数据处理事件
        public class SocketDataArrivedEventArgs : EventArgs
        {
            public byte[] ReceviedMessageData
            {
                get;
                private    set;
            }
            public SocketDataArrivedEventArgs(byte[]  bufferData)
                : base()
            {
                this.ReceviedMessageData = bufferData;
            }
            /// <summary>
            /// 提取消息体后余下的部分数据
            /// </summary>
            public Byte[] LeftData
            {
                get;
                set;
            }
        }


        public class SocketReadDataErrorEventArgs : EventArgs
        {
            public SocketReadDataErrorEventArgs(SocketError se)
                : base()
            {
                Error = se;
            }
            public SocketError Error
            {
                get;
                private set;
            }
            /// <summary>
            /// 是否取消( true: 取消继续读取数据,false :继续读取下一段数据(默认))
            /// </summary>
            public bool Cancel
            {
                get;
                set;
            }
        }

        #endregion

        public class WorketSokcet : IDisposable
        {
            const int LEN = 1024;
            static ManualResetEvent readLocker = new ManualResetEvent(true);
            static ManualResetEvent writeLocker = new ManualResetEvent(true);

            protected Socket mSckt;
            protected byte[] mDataBuffer;
            public TcpScket Parent
            {
                get;
                private set;
            }

            public event EventHandler Closed;

            public event EventHandler<SocketReadDataErrorEventArgs> ReadError;

            public event MessageDataArrivedEventHandler   ReceviedMessage;
             
            protected BufferedStream bufferStream;
            protected MemoryStream memoryStream;
            protected bool disposed = false;




            public  WorketSokcet(Socket socket,TcpScket  tcp)
            {
                mSckt = socket;
                mDataBuffer = new byte[1024];
                memoryStream = new MemoryStream();
                bufferStream = new BufferedStream(memoryStream);
                Parent = tcp;
            }
            private void readDataCallback(IAsyncResult ar)
            {
                ReadCallbackStateObject rs = ar.AsyncState as ReadCallbackStateObject;
                SocketError se = default(SocketError);
              
                    int size = mSckt.EndReceive(ar, out se);
                    if (se != SocketError.Success  && this.ReadError !=null  )
                    {
                        SocketReadDataErrorEventArgs serr = new SocketReadDataErrorEventArgs(se);
                        this.ReadError(this, serr);
                        if (serr.Cancel)
                            return;
                        //继续接收
                        mSckt.BeginReceive(
                            rs.BufferData, 0, ReadCallbackStateObject.BufferLen,
                            SocketFlags.None,
                            out se, readDataCallback, rs
                        );
                        return;
                    }
                    if (size <= 0)
                    {
                        bufferStream.Flush();
                        byte[] buffered = memoryStream.ToArray();
                        memoryStream.Seek(0L, SeekOrigin.Begin);
                        memoryStream.SetLength(0L);
                        int lastIndex = buffered.Length - 1;

                        int idx = MessageHelper.helperInstance.IndexOfMessageHeader(buffered, 0, lastIndex);
                        int preEnd = -1;
                        while (idx != -1)
                        {
                            //提取消息数据
                            int nxt = MessageHelper.helperInstance.IndexOfMessageHeader(buffered, idx + 16, lastIndex);

                            if (nxt != -1)
                            {
                                int tmpLen = nxt - idx;
                                byte[] tmp = new byte[tmpLen];
                                Buffer.BlockCopy(buffered, idx, tmp, 0, tmpLen);
                                idx = nxt;
                                preEnd = nxt ;
                                if (MessageHelper.helperInstance.IsComplectedPacketData(tmp))

                                {
                                    if (ReceviedMessage != null)
                                    {
                                        ReceviedMessage(this, new MessageData(tmp));
                                    }
#if DEBUG
                                    Console.WriteLine(MessageHelper.helperInstance.Encoding.GetString(

                                        tmp, 64, tmp.Length - 64));
#endif
                                }
                                else
                                {
#if DEBUG
                                    Console.WriteLine("ErrorMessage!");
#endif
                                }

                            }
                            else
                            {
                                byte[] data = new byte[buffered.Length - preEnd];
                                Buffer.BlockCopy(buffered, preEnd, data, 0, data.Length);
                                if (MessageHelper.helperInstance.IsStartWithMessageHeaderStr(data))
                                {
                                    if (MessageHelper.helperInstance.IsComplectedPacketData(data))
                                    {
                                        if (ReceviedMessage != null)
                                        {
                                            ReceviedMessage(this, new MessageData(data));
                                        }

#if DEBUG
                                        Console.WriteLine(MessageHelper.helperInstance.Encoding.GetString(
                                            data, 64, data.Length - 64
                                         ));
#endif
                                    }
                                    else
                                    {
                                        //不是完整的数据包
                                        memoryStream.Write(data, 0, data.Length);
                                    }
                                }
                                else
                                {
#if DEBUG
                                    Console.WriteLine("出现非法数据");
#endif
                                }
                                idx = -1;
                            }
                        }
 
                    }
                    else
                    {
                        bufferStream.Write(rs.BufferData, 0, size);
                        //继续接收
                        mSckt.BeginReceive(
                            rs.BufferData, 0, ReadCallbackStateObject.BufferLen,
                            SocketFlags.None,
                            out se, readDataCallback, rs
                        );
                    }
                   
                     
                 

            }
 

            public void Run()
            {
                Parent.RegisteredWorker(this);
                mSckt.UseOnlyOverlappedIO = true;
                SocketError se = default(SocketError);
             
                ReadCallbackStateObject rst = new ReadCallbackStateObject();

                mSckt.BeginReceive(
                    rst.BufferData ,0,ReadCallbackStateObject.BufferLen ,SocketFlags.None,
                    out  se, readDataCallback,rst
                );
            


            }
           
            #region IDisposable 成员

            private void Dispose(bool disposing)
            {
                if (disposed == false && disposing)
                {
                    if (bufferStream != null)
                    {
                        bufferStream.Close();
                        bufferStream = null;
                    }
                    if (memoryStream != null)
                    {
                        memoryStream.Close();
                        memoryStream = null;
                    }
                    if (mDataBuffer != null)
                    {
                        mDataBuffer = null;
                    }
                    if (mSckt != null)
                    {
                        mSckt.Shutdown(SocketShutdown.Both);
                        mSckt.Close();
                    }
                    if (this.Closed != null)
                    {
                        this.Closed(this, EventArgs.Empty);
                    }
                    disposed = true;
                }
            }

            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }

            #endregion


            #region  ReadCallback
            class ReadCallbackStateObject
            {

                public ReadCallbackStateObject()
                {
                    BufferData = new byte[1024];
                }
                public Byte[] BufferData
                {
                    get;
                    private set;
                }
                public const int BufferLen = 1024;
            }
            #endregion
        }
    }

   


    class Program
    {
        static void Main(string[] args)
        {
            TcpScket tcs = new TcpScket("127.0.0.1", 7777);
            tcs.Run(10);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值