C# Socket系列一 簡單的創建socket的監聽


socket的應用場景,在快速,穩定,保持長連接的數據傳輸代碼。Http也是socket封裝出來的,基於一次請求一次回復,然后斷開的socket連接封裝。

比如我們常見的游戲服務器,目前的很火的物聯網服務器,都需要開啟socket服務器去監聽實時傳輸的數據。

那么我們如何實現socket的監聽呢。說到這里,我們需要知道,socket的監聽分為tcp和udp兩種形式,但是tcp其實是udp封裝而來的,可看做可靠的udp傳輸,基於udp的定向傳輸,收到消息回復發送方收到消息。等驗證,來實現tcp的數據傳輸,所以一般我們tcp的傳輸相對udp稍微慢一點。

我們先將一下socket 的tcp狀態創建一個TCPListener類

/// <summary>
    /// 建立TCP通信監聽服務
    /// </summary>
    internal class TCPListener
    {
        private IPEndPoint _IP;
        private Socket _Listeners;
        private volatile bool IsInit = false;
        private List<TSocketBase> sockets = new List<TSocketBase>();

        /// <summary>
        /// 初始化服務器
        /// </summary>
        public TCPListener(string ip = "0.0.0.0", int port = 9527)
        {
            IsInit = true;
            IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(ip), port);
            this._IP = localEP;
            try
            {
                Console.WriteLine(string.Format("Listen Tcp -> {0}:{1} ", ip, port));
                this._Listeners = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this._Listeners.Bind(this._IP);
                this._Listeners.Listen(5000);
                SocketAsyncEventArgs sea = new SocketAsyncEventArgs();
                sea.Completed += new EventHandler<SocketAsyncEventArgs>(this.AcceptAsync_Async);
                this.AcceptAsync(sea);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                this.Dispose();
            }
        }

        private void AcceptAsync(SocketAsyncEventArgs sae)
        {
            if (IsInit)
            {
                if (!this._Listeners.AcceptAsync(sae))
                {
                    AcceptAsync_Async(this, sae);
                }
            }
            else
            {
                if (sae != null)
                {
                    sae.Dispose();
                }
            }
        }

        private void AcceptAsync_Async(object sender, SocketAsyncEventArgs sae)
        {
            if (sae.SocketError == SocketError.Success)
            {
                var socket = new TSocketClient(sae.AcceptSocket);
                sockets.Add(socket);
                Console.WriteLine("Remote Socket LocalEndPoint:" + sae.AcceptSocket.LocalEndPoint + " RemoteEndPoint:" +
                                  sae.AcceptSocket.RemoteEndPoint.ToString());
            }
            sae.AcceptSocket = null;
            if (IsInit)
            {
                this._Listeners.AcceptAsync(sae);
            }
            else
            {
                sae.Dispose();
            }
        }

        /// <summary>
        /// 釋放資源
        /// </summary>
        public void Dispose()
        {
            if (IsInit)
            {
                IsInit = false;
                this.Dispose(true);
                GC.SuppressFinalize(this);
            }
        }

        /// <summary>
        /// 釋放所占用的資源
        /// </summary>
        /// <param name="flag1"></param>
        protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1)
        {
            if (flag1)
            {
                if (_Listeners != null)
                {
                    try
                    {
                        Console.WriteLine(string.Format("Stop Listener Tcp -> {0}:{1} ", this.IP.Address.ToString(),
                            this.IP.Port));
                        _Listeners.Close();
                        _Listeners.Dispose();
                    }
                    catch
                    {
                    }
                }
            }
        }

        /// <summary>
        /// 獲取綁定終結點
        /// </summary>
        public IPEndPoint IP
        {
            get { return this._IP; }
        }
    }

  

主要兩點我們socket的初始化代碼 new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);初始化的類型是基於tcp。

還有就是我們綁定ip地址,過去很多人socket的bind地址習慣寫成127.0.0.1(測試環境)或者讀取網卡信息,讀取ip地址,這樣麻煩,代碼要寫很多,切不符合多網卡多線路實際環境。我們用0.0.0.0是表示開啟ipv4的所有線路監聽,包括你的多路網卡,以及127.0.0.1

復制代碼
1     class Program
2     {
3         static void Main(string[] args)
4         {
5             TCPListener tcp = new TCPListener();
6             Console.ReadLine();
7         }
8     }
復制代碼

我們運行看一下效果

 

接下來我們使用telnet測試一下

開啟telnet

 

然后打開cmd 

輸入 telnet 127.0.0.1 9527

 

我們看到收到了一個連接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM