• Asynchronous C# server[转]


    It hasn't been thoroughly tested, but seems to work OK.

    This should scale pretty nicely as well. Originally I was going to code it in C++, but after doing some research the scalability factor that I thought was going to gain using C++ seemed to be low considering the amount of work it was going to take.

    Server.cs

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net.Sockets;
    using System.Net;
    
    namespace Server
    {
        
        public class Server
        {
            private int port;
            private Socket serversocket;
    
            public delegate void ConnectionEvent(Connection conn);
            public List<Connection> connections;
            public event ConnectionEvent AcceptCallback;
            public event ConnectionEvent RecieveCallback;
            public event ConnectionEvent DisconnectCallback;
    
            public Server(int p)
            {
                port = p;
                connections = new List<Connection>(500);
            }
    
            public bool Start()
            {
                IPEndPoint ipendpoint;
    
                try
                {
    
                    //do not assign an IP, as it is a server (IPAdress.Any)
                    ipendpoint = new IPEndPoint(IPAddress.Any, this.port);
    
                }
                catch (ArgumentOutOfRangeException e)
                {
                    //port was probably out of range
                    throw new ArgumentOutOfRangeException("Please check port number.", e);
    
                }
    
                try
                {
    
                    //create the main server worker socket
                    serversocket = new Socket(ipendpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    
                }
                catch (SocketException e)
                {
    
                    //here because we couldn't create server socket
                    throw new ApplicationException("Couldn't create server socket.", e);
    
                }
    
                try
                {
                    //bind the socket to the specified port
                    serversocket.Bind(ipendpoint);
    
                    //begin listening for incoming connections
                    serversocket.Listen(100);
    
                }
                catch (SocketException e)
                {
                    
                    //probably here due to the port being in use
                    throw new ApplicationException("Couldn't bind/listen on port:  " + this.port.ToString(), e);
    
                }
    
                try
                {
    
                    //begin accepting incoming connections
                    serversocket.BeginAccept(new AsyncCallback(acceptCallback), this.serversocket);
    
                }
                catch (Exception e)
                {
                    
                    throw new ApplicationException("Error assigning the accept callback.", e);
    
                }
    
                return true;
            }
    
            private void acceptCallback(IAsyncResult ar)
            {
                Connection conn = new Connection();
    
                try
                {
                    
                    //finish the connection
    
                    //get the resulting state object
                    Socket sck = (Socket)ar.AsyncState;
                    
                    //create new connection object to be added to our concurrent connection list
                    conn = new Connection(sck.EndAccept(ar));
    
                    //lock our list for thread safety
                    lock(connections)
                    {
    
                        //add to our list
                        connections.Add(conn);
    
                    }
    
                    //begin accepting data on that socket, using our Connection object as the object state
                    conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), conn);
    
                    //start accepting connections again
                    serversocket.BeginAccept(new AsyncCallback(acceptCallback), this.serversocket);
           
                    //if the eventhandler for incoming connections has been assgined, call it
                    if(AcceptCallback != null)
                    {
    
                        AcceptCallback(conn);
    
                    }
    
                }
                catch(SocketException e)
                {
                    Disconnect(conn);
                    throw new ApplicationException(e.Message, e);
                }
            }
    
            private void Disconnect(Connection conn)
            {
                //remove connection from list
                lock (connections)
                {
                    connections.Remove(conn);
                }
    
                //make sure it's completely closed
                conn.socket.Close();
    
                //if the eventhandler for disconnection has been assgined, call it
                if (DisconnectCallback != null)
                {
    
                    DisconnectCallback(conn);
    
                }
            }
    
            private void receiveCallback(IAsyncResult ar)
            {
    
                //retrieve the connection that has data ready
                Connection conn = (Connection)ar.AsyncState;
    
                try
                {
    
                    //retrieve the data(bytes) while also returning how many bytes were read
                    int bytes = conn.socket.EndReceive(ar);
    
                    
                    //if bytes is more than zero, then data was successfully read
                    if(bytes > 0)
                    {
    
                        //if the data receive callback has been assigned, call it
                        if(RecieveCallback != null)
                        {
    
                            RecieveCallback(conn);
    
                        }
    
                        //being receiving data again
                        conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), conn);
    
                    }
                    else
                    {
    
                        //if zero bytes were read, connection was closed
                        Disconnect(conn);
    
                    }
                }
                catch(SocketException e)
                {
    
                    Disconnect(conn);
                    throw new ApplicationException("Error with EndReceive or BeginReceive", e);
                }
            }
        }
    }  
    View Code

    Connection.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net.Sockets;
    
    namespace Server
    {
       
        public class Connection
        {
            public byte[] buffer;
            public Socket socket;
    
            public Connection()
            {
    
            }
            public Connection(Socket sock)
            {
                buffer = new byte[1024];
                socket = sock;
            }
    
            public void Send(string data)
            {
                try
                {
    
                    if (this.socket.Connected)
                    {
                        //convert string into an aray of bytes
                        byte[] buffer = ASCIIEncoding.ASCII.GetBytes(data);
    
                        //send our byte[] buffer
                        socket.Send(buffer, SocketFlags.None);
                    }
    
    
                }
                catch (SocketException e)
                {
                    throw new ApplicationException("Error with Send", e);
                }
            }
    
        }
    } 
    View Code

    Usage:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    
    namespace Server
    {
        class Program
        {
            static void Main(string[] args)
            { 
                //port 80(webserver)
                Server server = new Server( 80 );
    
                server.RecieveCallback += server_RecieveCallback;
                server.AcceptCallback += server_AcceptCallback;
                server.DisconnectCallback += server_DisconnectCallback;
                server.Start();
    
                ThreadStart threadstart = new ThreadStart(ThreadJob);
                Thread thread = new Thread(threadstart);
    
                thread.Start();
    
            }
    
            static void server_DisconnectCallback(Connection conn)
            {
                Console.WriteLine("Connection disconnected
    ");
            }
    
            static void server_AcceptCallback(Connection conn)
            {
                Console.WriteLine("Incoming connection
    ");
            }
    
            static void ThreadJob()
            {
                while (true)
                    Thread.Sleep(1);
            }
    
            static void server_RecieveCallback(Connection conn)
            {
    
                Console.WriteLine(ASCIIEncoding.ASCII.GetString(conn.buffer));
    
            }
        }
    }
    View Code

    Go to your web browser and type 127.0.0.1 into the address bar.

    If any one sees any issues and things to improve on, let me know. (Sure there is).
    If any one has any questions let me know.

    不满足现状,用于挑战高峰!
  • 相关阅读:
    NPOI操作Excel
    父窗口调用iframe子窗口方法
    js 全选全不选
    常用的几种 SQLServer 分页查询方式实现
    通用简单的 分页 SQL
    C#导出
    delphi xe firemonkey 调用VLC播放器播放视频
    Android版本和API Level对应关系
    Android开发之视频录制1
    Android上实现视频录制
  • 原文地址:https://www.cnblogs.com/meyon/p/4009255.html
Copyright © 2020-2023  润新知