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
class Program { static void Main(string[] args) { TCPListener tcp = new TCPListener(); Console.ReadLine(); } }
我们运行看一下效果
接下来我们使用telnet测试一下
开启telnet
然后打开cmd
输入 telnet 127.0.0.1 9527
我们看到收到了一个连接