C# Socket系列一 簡單的創建socket的監聽
socket的應用場景,在快速,穩定,保持長連接的數據傳輸代碼。Http也是socket封裝出來的,基於一次請求一次回復,然後斷開的socket連接封裝。
比如我們常見的游戲服務器,目前的很火的物聯網服務器,都需要開啟socket服務器去監聽實時傳輸的數據。
那麼我們如何實現socket的監聽呢。說到這裡,我們需要知道,socket的監聽分為tcp和udp兩種形式,但是tcp其實是udp封裝而來的,可看做可靠的udp傳輸,基於udp的定向傳輸,收到消息回復發送方收到消息。等驗證,來實現tcp的數據傳輸,所以一般我們tcp的傳輸相對udp稍微慢一點。
我們先將一下socket 的tcp狀態創建一個TCPListener類
1 /// <summary>
2 /// 建立TCP通信監聽服務
3 /// </summary>
4 internal class TCPListener
5 {
6 private IPEndPoint _IP;
7 private Socket _Listeners;
8 private volatile bool IsInit = false;
9 List<TSocketBase> sockets = new List<TSocketBase>();
10
11 /// <summary>
12 /// 初始化服務器
13 /// </summary>
14 public TCPListener(string ip = "0.0.0.0", int port = 9527)
15 {
16 IsInit = true;
17 IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(ip), port);
18 this._IP = localEP;
19 try
20 {
21 Console.WriteLine(string.Format("Listen Tcp -> {0}:{1} ", ip, port));
22 this._Listeners = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
23 this._Listeners.Bind(this._IP);
24 this._Listeners.Listen(5000);
25 SocketAsyncEventArgs sea = new SocketAsyncEventArgs();
26 sea.Completed += new EventHandler<SocketAsyncEventArgs>(this.AcceptAsync_Async);
27 this.AcceptAsync(sea);
28 }
29 catch (Exception ex)
30 {
31 Console.WriteLine(ex);
32 this.Dispose();
33 }
34 }
35
36 private void AcceptAsync(SocketAsyncEventArgs sae)
37 {
38 if (IsInit)
39 {
40 if (!this._Listeners.AcceptAsync(sae))
41 {
42 AcceptAsync_Async(this, sae);
43 }
44 }
45 else
46 {
47 if (sae != null)
48 {
49 sae.Dispose();
50 }
51 }
52 }
53
54 private void AcceptAsync_Async(object sender, SocketAsyncEventArgs sae)
55 {
56 if (sae.SocketError == SocketError.Success)
57 {
58 var socket = new TSocketClient(sae.AcceptSocket);
59 sockets.Add(socket);
60 Console.WriteLine("Remote Socket LocalEndPoint:" + sae.AcceptSocket.LocalEndPoint + " RemoteEndPoint:" + sae.AcceptSocket.RemoteEndPoint.ToString());
61 }
62 sae.AcceptSocket = null;
63 if (IsInit)
64 {
65 this._Listeners.AcceptAsync(sae);
66 }
67 else { sae.Dispose(); }
68 }
69
70 /// <summary>
71 /// 釋放資源
72 /// </summary>
73 public void Dispose()
74 {
75 if (IsInit)
76 {
77 IsInit = false;
78 this.Dispose(true);
79 GC.SuppressFinalize(this);
80 }
81 }
82 /// <summary>
83 /// 釋放所占用的資源
84 /// </summary>
85 /// <param name="flag1"></param>
86 protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1)
87 {
88 if (flag1)
89 {
90 if (_Listeners != null)
91 {
92 try
93 {
94 Console.WriteLine(string.Format("Stop Listener Tcp -> {0}:{1} ", this.IP.Address.ToString(), this.IP.Port));
95 _Listeners.Close();
96 _Listeners.Dispose();
97 }
98 catch { }
99 }
100 }
101 }
102
103 /// <summary>
104 /// 獲取綁定終結點
105 /// </summary>
106 public IPEndPoint IP { get { return this._IP; } }
107 }
主要兩點我們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 }