SocketServer.cs 6.2 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 7 8
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;

namespace Mozi.HttpEmbedded
{
JasonWcx's avatar
JasonWcx 已提交
9 10
    //TODO 加入定时器并利用POLL判断远端是否断开

JasonWcx's avatar
JasonWcx 已提交
11 12 13 14 15 16
    /// <summary>
    /// 异步单线程
    /// </summary>
    public class SocketServer
    {
        //private static SocketServer _mSocketServer;
JasonWcx's avatar
JasonWcx 已提交
17
        
JasonWcx's avatar
JasonWcx 已提交
18
        private int _iPort = 9000;
JasonWcx's avatar
JasonWcx 已提交
19 20 21
        private int _maxListenCount = 10;

        private ConcurrentDictionary<string,Socket> _socketDocker;
22
        private Socket _sc;
JasonWcx's avatar
JasonWcx 已提交
23

JasonWcx's avatar
JasonWcx 已提交
24 25 26 27 28 29 30 31
        /// <summary>
        /// 服务器启动事件
        /// </summary>
        public event ServerStart OnServerStart;
        /// <summary>
        /// 客户端连接事件
        /// </summary>
        public event ClientConnect OnClientConnect;
32 33 34
        /// <summary>
        /// 客户端断开连接时间
        /// </summary>
JasonWcx's avatar
JasonWcx 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
        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 已提交
52
        public int Port
JasonWcx's avatar
JasonWcx 已提交
53 54 55 56 57 58
        {
            get { return _iPort; }
        }

        public Socket SocketMain
        {
59
            get { return _sc; }
JasonWcx's avatar
JasonWcx 已提交
60 61 62 63
        }

        public SocketServer() 
        {
JasonWcx's avatar
JasonWcx 已提交
64
            _socketDocker = new ConcurrentDictionary<string, Socket>();
JasonWcx's avatar
JasonWcx 已提交
65 66 67 68 69 70 71 72 73 74
        }

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

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

        }
JasonWcx's avatar
JasonWcx 已提交
205 206
    }
}