.NET Socket開發(1) 之同步Socket實現

來源:互聯網
上載者:User
.NET Socket開發之同步Socket實現兩例今天,我們來講一下在.NET 網路應用程式開發中同步Socket的應用,很多人認為在網路應用的服務端Socket不應該使用同步Socket。是的,在大多數情況下是這樣的,但是也有一些情境下我們使用同步Socket可能會得到更的結果。如在下面的兩種情境下我們便可以考慮使用同步的Socket。一、用戶端數量比較少:數量比較少是指會同時串連到伺服器的用戶端數量一般在50人以下。這種情況下我們可以考慮使用同步Socket+Thread來實現我們的服務端。這樣會讓我們編寫邏輯更清晰的代碼而效能不會下降太多。二、用戶端數量較多但都是短串連:短串連是指用戶端的串連在處理完一次收發之後就產即斷開的情境,比如說HTTP協議就是一種短串連。HTTP在用戶端發出請求時建立一個Socket串連,並通過Socket發出一個URL請求,服務端在處理完這個請求並回傳相應的頁面後便會斷開這個串連。那麼在這種情境下我們也可以使用同步Socket來實現我們的需求。

那麼應該如果實現我上面提到的兩種需求呢。對於這兩種需求,我將採用不同的方案來實現它們。首先我們來看看第一種需求,這裡我採用Socket+Thread來實現,基本的流程如下:首先建立一個Socket,並且給它綁定一個EndPoint後開始監聽。接下來我們建立一個線程,在這個線程中我們用一個無限迴圈來接收來自用戶端的串連請求。在接收到一個請求後,為這個用戶端建立一個新的線程,並且在這個線程中也使用一個無限迴圈接收來自這個用戶端的資料。下面讓我們來看看代碼:

 

代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketServer
{
    /// <summary>
    /// Socket 同步通訊 Socket+Thread
    /// </summary>
    public class SocketA
    {
        Socket server;
        public SocketA()
        {
            //建立一個Socket用來偵聽用戶端的串連
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Any,9999));
            server.Listen(100);
            Console.WriteLine("伺服器啟動......");

            //然後建立一個線程來處理用戶端的串連請求
            Thread th = new Thread(new ThreadStart(WriteConnction));
            th.Start();
            Console.ReadLine();
        }

        public void WriteConnction()
        {
            Thread.CurrentThread.IsBackground = true;
            while(true)
            {
                Socket s = server.Accept();
                IPEndPoint ippoint =(IPEndPoint)s.RemoteEndPoint;
                Console.WriteLine("收到串連,來自:" + ippoint.Address.ToString());
                //然後建立一個線程來接受資訊
                Thread th = new Thread(new ParameterizedThreadStart(WriteMsg));
                th.Start(s);
            }
        }

        public void WriteMsg(object obj)
        {
            Thread.CurrentThread.IsBackground = true;
            if(obj !=null)
            {
                Socket socket = (Socket)obj;
                byte[] byt=new byte[1024];
                while(true)
                {
                    int getlength = socket.Receive(byt);
                    if(getlength>0)
                    {
                        IPEndPoint ippoint = (IPEndPoint)socket.RemoteEndPoint;
                        string address=ippoint.Address.ToString();
                        string msg = System.Text.Encoding.UTF8.GetString(byt, 0, getlength);
                        Console.WriteLine("收到來自" + address+"的訊息:"+msg);

                        socket.Send(byt, getlength, SocketFlags.None);
                    }
                }
            }                  
        }

    }
}

 

現在讓我們來看看第二個需求:這個方案我們將採用另外一個方法來實現,為什麼不採用上一個方法來實現呢?讓我們來分析一下。我們知道,在上一個實現中,每接入一個用戶端就要建立一個線程,如果有大量的用戶端接入的話,就會建立過多的線程。但是如果線程過多的話,Windows就需要更多的CPU時間來切換線程的上下文(這也是上一個實現不能接入很多用戶端的原因)。我們知道,在這個方案中每一個串連都是短串連。而且順序都是固定的。都是:接入->接收->發送這樣的順序,那麼我們就可以在一個方法中完成整個處理。這樣,我們就可以利用線程池來實現我們所需要的。好了,讓我們用代碼來說話吧:

 

代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketServer
{
    /// <summary>
    /// Socket 同步通訊 Socket+Thread
    /// 用戶端數量比較少 
    /// </summary>
    public class SocketB
    {
        Socket server;
        public SocketB()
        {
            //建立一個Socket用來偵聽用戶端的串連
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(new IPEndPoint(IPAddress.Any, 8888));
            server.Listen(100);
            Console.WriteLine("伺服器啟動......");

            //建立一個線程池
            Thread[] ths=new Thread[30];
            for (int i = 0; i < ths.Length;i++ )
            {
                ths[i] = new Thread(new ThreadStart(WaiteConnetion));
            }
            Console.ReadLine();
        }

        public void WaiteConnetion()
        {
            byte[] byt=new byte[1024];
            Socket s = server.Accept();
            IPEndPoint ipoint=(IPEndPoint)s.RemoteEndPoint;
            string ip=ipoint.Address.ToString();
            Console.WriteLine("收到串連,來自:" + ip);
            int getlength = s.Receive(byt);
            if(getlength>0)
            {
                string msg = System.Text.Encoding.UTF8.GetString(byt);
                Console.WriteLine("收到資訊"+ip+"來自"+msg);
                s.Send(byt,getlength,SocketFlags.None);
            }
            s.Shutdown(SocketShutdown.Both);
            s.Close();
        }

    }
}
為什麼我們要這樣做呢? 首先我們建立了一個Socket用於偵聽用戶端的串連請求,接下我們建立了一個擁有30個線程的線程池。並在每個線程中實現了Accept、Receive、Send和Close(),以完成串連、接收、發送、關閉的操作。現在我們假設有一個客戶串連到伺服器了,這時會有一個線程Accept到這個請求,並開始接收用戶端發送過來的資料,接收到資料之後處理完髮送給用戶端,然後關閉這個串連,再次進入等待串連狀態。而其它29個線程由於沒有Accept到這個請求,仍然處理等待接入狀態。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.