public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken)
{
_state = WebSocketState.Connecting;
await _connection.ConnectAsync(uri.Host, uri.Port);
_stream = _connection.GetStream();
var secKey = Convert.ToBase64String(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString().Substring(0, 16)));
var expectedAccept = HandshakeHelpers.CreateResponseKey(secKey);
var headerString =
$"GET {uri.PathAndQuery} HTTP/1.1\r\n" +
$"Host: {uri.Host}\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: websocket\r\n" +
"Sec-WebSocket-Version: 13\r\n" +
$"Sec-WebSocket-Protocol: {_subProtocol}\r\n" +
$"Sec-WebSocket-Key: {secKey}\r\n\r\n";
var bytes = Encoding.UTF8.GetBytes(headerString);
await _stream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
await _stream.FlushAsync(cancellationToken);
var buffer = new byte[1024];
var resultLenth = await _stream.ReadAsync(buffer, 0, 1024, cancellationToken);
var resultString = new StringReader(Encoding.UTF8.GetString(buffer, 0, resultLenth));
var respCode = 0;
var headers = new Dictionary<string, string>();
var line = resultString.ReadLine();
while (line != null)
{
if (line.StartsWith("HTTP/1.1 ") && line.Length > 11)
respCode = Convert.ToInt16(line.Substring(9, 3));
else
{
var items = line.Split(new[] { ':' }, 2);
if (items.Length == 2)
headers[items[0]] = items[1].TrimStart();
}
line = resultString.ReadLine();
}
if (respCode != (int) HttpStatusCode.SwitchingProtocols)
{
throw new WebSocketException($"The server returned status code '{respCode}' when status code '101' was expected");
}
if (!string.Equals(headers["Upgrade"], "WebSocket", StringComparison.OrdinalIgnoreCase)
|| !string.Equals(headers["Connection"], "Upgrade", StringComparison.OrdinalIgnoreCase)
|| !string.Equals(headers["Sec-WebSocket-Accept"], expectedAccept))
{
throw new WebSocketException("HTTP header error during handshake");
}
_state = WebSocketState.Open;
if (_keepAliveInterval != Timeout.InfiniteTimeSpan)
{
_keepAliveTimer = new Timer(SendKeepAlive, this, _keepAliveInterval, _keepAliveInterval);
}
}