private async Task ConnectClientInternal() { if (_socket != null) { throw new Exception("connect() is already called"); } try { int port = (_uri.Port != -1) ? _uri.Port : (_uri.Scheme.Equals("wss") ? 443 : 80); string path = (_uri.AbsolutePath != null) ? _uri.AbsolutePath : "/"; if (_uri.Query != null) { path += "?" + _uri.Query; } string originScheme = _uri.Scheme.Equals("wss") ? "https" : "http"; Uri origin = new Uri(originScheme + "://" + _uri.Host); // To fix: get Origin from extraHeaders if set there. this._socket = new InternalSocket(); await this._socket.ConnectAsync(_uri.Host, port); if (_uri.Scheme.Equals("wss")) { await this._socket.UpgradeToSslAsync(_uri.Host); } string key = WebSocketHelper.CreateClientKey(); DataWriter writer = new DataWriter(_socket.OutputStream); writer.WriteString("GET " + path + " HTTP/1.1\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Host: " + _uri.Host + "\r\n"); writer.WriteString("Origin: " + origin.ToString() + "\r\n"); writer.WriteString("Sec-WebSocket-Key: " + key + "\r\n"); writer.WriteString("Sec-WebSocket-Version: 13\r\n"); if (_extraRequestHeaders != null) { foreach (Http.Header header in _extraRequestHeaders) { writer.WriteString(header.ToString() + "\r\n"); } } writer.WriteString("\r\n"); await writer.StoreAsync(); //异步发送数据 writer.DetachStream(); //分离 writer.Dispose(); //结束writer DataReader reader = new DataReader(_socket.InputStream); reader.ByteOrder = ByteOrder.LittleEndian; //// Read HTTP response status line. var startLine = await ReadLine(reader); if (startLine == null) { throw new Exception("Received no reply from server."); } Http.StatusLine statusLine = new Http.StatusLine(startLine); int statusCode = statusLine.StatusCode; if (statusCode != 101) { throw new Exception("wrong HTTP response code: " + statusCode); } // Read HTTP response headers. string line; while ((line = await ReadLine(reader)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); Debug.WriteLine(line); if (header.HeaderName.Equals("Sec-WebSocket-Accept", StringComparison.OrdinalIgnoreCase)) { string receivedAccept = header.HeaderValue; string shouldBeAccept = WebSocketHelper.CreateAccept(key); if (!receivedAccept.Equals(shouldBeAccept)) { throw new Exception("Wrong Sec-WebSocket-Accept: " + receivedAccept + " should be: " + shouldBeAccept); } } if (_serverResponseHeaders == null) { _serverResponseHeaders = new List <Http.Header>(); } _serverResponseHeaders.Add(header); } if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } //Upgrade: websocket //Connection: Upgrade //Sec-WebSocket-Accept: 1xY289lHcEMbLpEBgOYRBBL9N9c= //Sec-WebSocket-Protocol: chat //Content-Type: application/octet-stream //Seq-Id: 667035124 // Read & process frame while (true) { FrameParser.Frame frame = await FrameParser.ReadFrame(reader); if (frame != null) { await ProcessIncomingFrame(frame); } } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, ex.Message)); } } finally { Disconnect(); } }
private void ConnectServer() { Task.Factory.StartNew(async() => { try { DataReader stream = new DataReader(this._socket.InputStream); // Read HTTP request line. string startLine = await this.ReadLine(stream); if (startLine == null) { throw new Exception("Cannot read HTTP request start line"); } Http.RequestLine requestLine = new Http.RequestLine(startLine); this._uri = new Uri(requestLine.RequestURI); // can be checked in // onConnect() // Read HTTP response headers Dictionary <string, string> map = new Dictionary <string, string>(); string line; while ((line = await this.ReadLine(stream)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); map.Add(header.HeaderName.ToLower(), header.HeaderValue); } string value = map["sec-websocket-version"]; if (!"13".Equals(value)) { throw new IOException("wrong Sec-WebSocket-Version"); } string key = map["sec-websocket-key"]; if (key == null) { throw new IOException("missed Sec-WebSocket-Key"); } string accept = WebSocketHelper.CreateAccept(key); string upgrade = map["upgrade"]; if (upgrade == null || !upgrade.Equals("websocket", StringComparison.OrdinalIgnoreCase)) { throw new IOException("wrong Upgrade"); } string connection = map["connection"]; if (connection == null || !connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase)) { throw new IOException("wrong Connection"); } // Host and Origin can be checked later in onConnect() callback. this._host = map["host"]; if (this._host == null) { throw new IOException("Missed 'Host' header"); } this._origin = map["origin"]; if (this._origin == null) { throw new IOException("Missed 'Origin' header"); } // Some naive protocol selection. string protocols = map["sec-websocket-protocol"]; string selectedProtocol = null; if (protocols != null && protocols.Contains("chat")) { selectedProtocol = "chat"; } DataWriter writer = new DataWriter(this._socket.OutputStream); writer.WriteString("HTTP/1.1 101 Switching Protocols\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Sec-WebSocket-Accept: " + accept + "\r\n"); if (selectedProtocol != null) { writer.WriteString("Sec-WebSocket-Protocol: " + selectedProtocol + "\r\n"); } writer.WriteString("\r\n"); await writer.FlushAsync(); if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } // Read & process frame for (;;) { FrameParser.Frame frame = await FrameParser.ReadFrame(stream); await this.ProcessIncomingFrame(frame); } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "Exception")); } } finally { this.Disconnect(); } }); }