定义:
遵循RFC6544协议的通信协议。Webcoket协议和http协议属于并行关系,但是websocket是以http协议为基础开发出来的(微软用IhttpHandler接口中同时处理这两种协议),同时他们都是以TCP协议为基础。可以进行双向通信、持久化通信。Http是单向通信协议、无状态通信。
websocket协议(握手部分):
GET /chat HTTP/1.1
Host: http://server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
比http握手多了几个部分:
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
这几个部分告诉服务器,该请求是Webcoket,不是http了。
接收的数据
GET /chat HTTP/1.1
Host: http://example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
发送的数据
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
服务端:
- 使用第三方的Fleck库,建议采用吧,比较方便。
- 使用第三方的websocketsharp库,不方便服务端主动推送数据到客户端。
- 自己按照RFC6544协议,打包协议头+socket API库,收发数据。
- 使用IIS8.0以上可以处理websocket请求:
namespace SimpleWebSocketApplication
{ public class WebSocketHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { //Checks if the query is WebSocket request. if (context.IsWebSocketRequest) { //If yes, we attach the asynchronous handler. context.AcceptWebSocketRequest(WebSocketRequestHandler); } } public bool IsReusable { get { return false; } } //Asynchronous request handler. public async Task WebSocketRequestHandler(AspNetWebSocketContext webSocketContext) { //Gets the current WebSocket object. WebSocket webSocket = webSocketContext.WebSocket; /*We define a certain constant which will represent size of received data. It is established by us and we can set any value. We know that in this case the size of the sent data is very small. */ const int maxMessageSize = 1024; //Buffer for received bits. var receivedDataBuffer = new ArraySegment<Byte>(new Byte[maxMessageSize]); var cancellationToken = new CancellationToken(); //Checks WebSocket state. while (webSocket.State == WebSocketState.Open) { //Reads data. WebSocketReceiveResult webSocketReceiveResult = await webSocket.ReceiveAsync(receivedDataBuffer, cancellationToken); //If input frame is cancelation frame, send close command. if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close) { await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, cancellationToken); } else { byte[] payloadData = receivedDataBuffer.Array.Where(b => b != 0).ToArray(); //Because we know that is a string, we convert it. string receiveString = System.Text.Encoding.UTF8.GetString(payloadData, 0, payloadData.Length); //Converts string to byte array. var newString = String.Format("Hello, " + receiveString + " ! Time {0}", DateTime.Now.ToString()); Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(newString); //Sends data back. await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, cancellationToken); } } } }
}
- 使用TcpListener类库,不能使用httpListener类库,,创建监听,并将发送的数据按RFC6544协议打包。
(创建监听)
class Server {
public static void Main() {
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80);
server.Start();
Console.WriteLine("Server has started on 127.0.0.1:80.{0}Waiting for a connection...", Environment.NewLine);
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
}
}
(接收数据)
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
NetworkStream stream = client.GetStream();
while(client.Available < 3)
{
// wait for enough bytes to be available
}
//enter to an infinite cycle to be able to handle every change in stream
while (true) {
while (!stream.DataAvailable);
Byte[] bytes = new Byte[client.Available];
stream.Read(bytes, 0, bytes.Length);
}
(打包发送的数据)
if (new System.Text.RegularExpressions.Regex("^GET").IsMatch(data))
{
const string eol = "\r\n"; // HTTP/1.1 defines the sequence CR LF as the end-of-line marker
Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + eol
+ "Connection: Upgrade" + eol
+ "Upgrade: websocket" + eol
+ "Sec-WebSocket-Accept: " + Convert.ToBase64String(
System.Security.Cryptography.SHA1.Create().ComputeHash(
Encoding.UTF8.GetBytes(
new System.Text.RegularExpressions.Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)
)
) + eol
+ eol);
stream.Write(response, 0, response.Length);
}
客户端:
- html5的JS库
- Fleck库
- websocketsharp库
- 微软自己的wensocketclient库
- 自己按照RFC6544协议,打包协议头+socket API库,收发数据