对.Net WebSocket 和Socket的原理的思考
今早上班路上接到了一个朋友的微信信息,问我对WebSocket 是否熟悉,一楞,印象之中没有用过这个类....来到公司后,得空问了一下度娘,原来这是一个随着HTML5推出的一种新协议,意义在于能实现浏览器与服务器全双工通信(full-duplex)。度娘对此的解释是:
internal class WinHttpWebSocket : WebSocket { .....
public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) { ..... _operation.SessionHandle = InitializeWinHttp(options); _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback( _operation.SessionHandle, uri.IdnHost, (ushort)uri.Port, 0); ThrowOnInvalidHandle(_operation.ConnectionHandle); bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss; _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback( _operation.ConnectionHandle, "GET", uri.PathAndQuery, null, Interop.WinHttp.WINHTTP_NO_REFERER, null, secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0); ThrowOnInvalidHandle(_operation.RequestHandle); _operation.IncrementHandlesOpenWithCallback(); ..... } ...... }
namespace System.Net.Sockets { public partial class Socket : IDisposable { ....... public void Connect(EndPoint remoteEP) { ...... EndPoint endPointSnapshot = remoteEP; Internals.SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true); if (!Blocking) { _nonBlockingConnectRightEndPoint = endPointSnapshot; _nonBlockingConnectInProgress = true; } DoConnect(endPointSnapshot, socketAddress); } private void DoConnect(EndPoint endPointSnapshot, Internals.SocketAddress socketAddress) { ....... SocketError errorCode = SocketPal.Connect(_handle, socketAddress.Buffer, socketAddress.Size); ...... } ...... } }
namespace System.Net.Sockets { internal static class SocketPal { ....... public static SocketError Connect(SafeCloseSocket handle, byte[] peerAddress, int peerAddressLen) { SocketError errorCode = Interop.Winsock.WSAConnect( handle.DangerousGetHandle(), peerAddress, peerAddressLen, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; } ....... } }
由上面代码可见,
(1)WebSocket最终调用了WinHTTP 的api,WinHTTP的全称是Microsoft Windows HTTP Services, 它提供给开发者一个HTTP客户端应用程序接口(API), 通过这种API借助HTTP协议给其他的HTTP服务器发送请求.关于WinHTTP 的详细API,请自行查询资料,网上一大把,这里不再累赘copy。由此可以验证了WebSocket是基于HTTP请求的,从调用的WinHTTPAPI方法名称可以得知,都是带有回调的方法,也正验证了WebSocket的双工通信的特点。
(2)Socket最终是调用了windows的Winsock接口,Winsock是Windows下的网络编程接口,它是由Unix下的BSD Socket发展而来,是一个与网络协议无关的编程接口。具体信息请自行查询网上资源。
因此,我个人觉得,WebSocket和Socket在技术上并没有太多关系,底层原理也是不同的,WebSocket 是为了满足基于 Web 的日益增长的实时通信需求而产生的,可以在一些实时通信时,代替采用 HTTP 协议不断发送请求的通用的方式,以达到带宽浪费和服务器 CPU 的消耗,更重要的是它是一种协议,而Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,并不是协议,WebSocket不能等同Socket,也不是Socket的演化,更不能代替Socket。