SocketServer.cs 6.3 KB
Newer Older
JasonWcx's avatar
JasonWcx 已提交
1
using System;
JasonWcx's avatar
JasonWcx 已提交
2
using System.Collections.Concurrent;
JasonWcx's avatar
JasonWcx 已提交
3 4 5 6
using System.Net.Sockets;

namespace Mozi.HttpEmbedded
{
JasonWcx's avatar
JasonWcx 已提交
7
    //TODO 加入定时器并利用POLL判断远端是否断开
JasonWcx's avatar
JasonWcx 已提交
8 9 10 11 12 13
    /// <summary>
    /// 异步单线程
    /// </summary>
    public class SocketServer
    {
        //private static SocketServer _mSocketServer;
14

JasonWcx's avatar
JasonWcx 已提交
15 16 17 18 19
        protected int _iport = 80;

        protected int _maxListenCount = 100;
        protected ConcurrentDictionary<string,Socket> _socketDocker;
        protected Socket _sc;
JasonWcx's avatar
JasonWcx 已提交
20

JasonWcx's avatar
JasonWcx 已提交
21 22 23 24 25 26 27 28
        /// <summary>
        /// 服务器启动事件
        /// </summary>
        public event ServerStart OnServerStart;
        /// <summary>
        /// 客户端连接事件
        /// </summary>
        public event ClientConnect OnClientConnect;
29 30 31
        /// <summary>
        /// 客户端断开连接时间
        /// </summary>
JasonWcx's avatar
JasonWcx 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
        public event ClientDisConnect AfterClientDisConnect;
        /// <summary>
        /// 数据接收开始事件
        /// </summary>
        public event ReceiveStart OnReceiveStart;
        /// <summary>
        /// 数据接收完成事件
        /// </summary>
        public event ReceiveEnd AfterReceiveEnd;
        /// <summary>
        /// 服务器停用事件
        /// </summary>
        public event AfterServerStop AfterServerStop;

        /// <summary>
        /// 端口
        /// </summary>
JasonWcx's avatar
JasonWcx 已提交
49
        public int Port
JasonWcx's avatar
JasonWcx 已提交
50
        {
JasonWcx's avatar
JasonWcx 已提交
51
            get { return _iport; }
JasonWcx's avatar
JasonWcx 已提交
52 53 54
        }
        public Socket SocketMain
        {
55
            get { return _sc; }
JasonWcx's avatar
JasonWcx 已提交
56 57 58 59
        }

        public SocketServer() 
        {
JasonWcx's avatar
JasonWcx 已提交
60
            _socketDocker = new ConcurrentDictionary<string, Socket>();
JasonWcx's avatar
JasonWcx 已提交
61 62 63 64 65 66 67 68 69
        }

        //TODO 测试此处是否有BUG
        /// <summary>
        /// 启动服务器
        /// </summary>
        /// <param name="port"></param>
        public void StartServer(int port)
        {
JasonWcx's avatar
JasonWcx 已提交
70
            _iport = port;
71
            if (_sc == null)
JasonWcx's avatar
JasonWcx 已提交
72
            {
73
                _sc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
JasonWcx's avatar
JasonWcx 已提交
74 75 76
            }
            else
            {
77
                _sc.Close();
JasonWcx's avatar
JasonWcx 已提交
78
            }
JasonWcx's avatar
JasonWcx 已提交
79
            System.Net.IPEndPoint endpoint = new System.Net.IPEndPoint(System.Net.IPAddress.Any, _iport);
JasonWcx's avatar
JasonWcx 已提交
80 81
            //允许端口复用
            _sc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
82
            _sc.Bind(endpoint);
JasonWcx's avatar
JasonWcx 已提交
83
            _sc.Listen(_maxListenCount);            
JasonWcx's avatar
JasonWcx 已提交
84 85 86 87 88
            //回调服务器启动事件
            if (OnServerStart != null) 
            {
                OnServerStart(this, new ServerArgs() { StartTime=DateTime.Now,StopTime=DateTime.MinValue });
            }
89
            _sc.BeginAccept(new AsyncCallback(CallbackAccept), _sc);
JasonWcx's avatar
JasonWcx 已提交
90 91 92 93 94 95 96 97 98
        }
        /// <summary>
        /// 关闭服务器
        /// </summary>
        public void StopServer() 
        {
            _socketDocker.Clear();
            try
            {
99
                _sc.Shutdown(SocketShutdown.Both);
JasonWcx's avatar
JasonWcx 已提交
100 101
                if (AfterServerStop != null) 
                {
102
                    AfterServerStop(_sc, null);
JasonWcx's avatar
JasonWcx 已提交
103 104 105 106 107 108 109 110 111 112 113
                }
            }
            catch 
            { 
            
            }
        }
        /// <summary>
        /// 开始连接回调
        /// </summary>
        /// <param name="iar"></param>
JasonWcx's avatar
JasonWcx 已提交
114
        protected void CallbackAccept(IAsyncResult iar)
JasonWcx's avatar
JasonWcx 已提交
115 116 117
        {
            Socket server = (Socket)iar.AsyncState;
            Socket client = server.EndAccept(iar);
JasonWcx's avatar
JasonWcx 已提交
118
            //接受新连接传入
JasonWcx's avatar
JasonWcx 已提交
119
            server.BeginAccept(CallbackAccept, server);
JasonWcx's avatar
JasonWcx 已提交
120

JasonWcx's avatar
JasonWcx 已提交
121 122
            if (OnClientConnect != null) 
            {
JasonWcx's avatar
JasonWcx 已提交
123
                OnClientConnect.BeginInvoke(this, new ClientConnectArgs() { 
JasonWcx's avatar
JasonWcx 已提交
124
                    Client=client
JasonWcx's avatar
JasonWcx 已提交
125
                },null,null);
JasonWcx's avatar
JasonWcx 已提交
126 127 128 129 130 131 132 133
            }
            StateObject so = new StateObject() 
            { 
                WorkSocket = client,
                Id = Guid.NewGuid().ToString(),
                IP = ((System.Net.IPEndPoint)client.RemoteEndPoint).Address.ToString(),
                RemotePort = ((System.Net.IPEndPoint)client.RemoteEndPoint).Port,
            };
JasonWcx's avatar
JasonWcx 已提交
134
            _socketDocker.TryAdd(so.Id, client);
JasonWcx's avatar
JasonWcx 已提交
135 136
            try
            {
JasonWcx's avatar
JasonWcx 已提交
137
                client.BeginReceive(so.Buffer, 0, so.Buffer.Length, SocketFlags.None, CallbackReceive, so);
JasonWcx's avatar
JasonWcx 已提交
138 139
                if (OnReceiveStart != null)
                {
JasonWcx's avatar
JasonWcx 已提交
140
                    OnReceiveStart.BeginInvoke(this, new DataTransferArgs(), null, null);
JasonWcx's avatar
JasonWcx 已提交
141 142 143 144 145 146 147 148 149 150 151
                }
            }
            catch(Exception ex)
            {
                var ex2 = ex;
            }
        }
        /// <summary>
        /// 接收数据回调
        /// </summary>
        /// <param name="iar"></param>
JasonWcx's avatar
JasonWcx 已提交
152
        protected void CallbackReceive(IAsyncResult iar)
JasonWcx's avatar
JasonWcx 已提交
153 154 155
        {
            StateObject so = (StateObject)iar.AsyncState;
            Socket client = so.WorkSocket;
156 157 158
            if (client.Connected)
            {
                int iByteRead = client.EndReceive(iar);
JasonWcx's avatar
JasonWcx 已提交
159
                   
160 161 162 163
                if (iByteRead >0)
                {
                    //置空数据连接
                    so.ResetBuffer(iByteRead);
164
                    if (client.Available > 0){
165
                        //Thread.Sleep(10);
JasonWcx's avatar
JasonWcx 已提交
166
                        client.BeginReceive(so.Buffer, 0, so.Buffer.Length, SocketFlags.None, CallbackReceive, so);
167
                    }else{
JasonWcx's avatar
JasonWcx 已提交
168
                        InvokeAfterReceiveEnd(so, client);
JasonWcx's avatar
JasonWcx 已提交
169 170
                    }
                }
JasonWcx's avatar
JasonWcx 已提交
171
                else
172
                {
JasonWcx's avatar
JasonWcx 已提交
173
                    InvokeAfterReceiveEnd(so, client);
JasonWcx's avatar
JasonWcx 已提交
174
                }
175 176 177
            }
            else 
            {
JasonWcx's avatar
JasonWcx 已提交
178 179 180 181 182 183 184 185
                InvokeAfterReceiveEnd(so, client);
            }
        }
        private void InvokeAfterReceiveEnd(StateObject so,Socket client)
        { 
            RemoveClientSocket(so);
            if (AfterReceiveEnd != null)
            {
JasonWcx's avatar
JasonWcx 已提交
186
                AfterReceiveEnd.BeginInvoke(this,
JasonWcx's avatar
JasonWcx 已提交
187 188 189 190 191 192
                    new DataTransferArgs()
                    {
                        Data = so.Data.ToArray(),
                        IP = so.IP,
                        Port = so.RemotePort,
                        Socket = so.WorkSocket
JasonWcx's avatar
JasonWcx 已提交
193
                 },null,null);
194
            }
JasonWcx's avatar
JasonWcx 已提交
195
        }
JasonWcx's avatar
JasonWcx 已提交
196 197 198 199 200 201
        //TODO 此处开启Socket状态监听,对断开的链接进行关闭销毁
        private void RemoveClientSocket(StateObject so)
        {
            Socket client;
            _socketDocker.TryRemove(so.Id, out client);
        }
JasonWcx's avatar
JasonWcx 已提交
202 203
    }
}