Reputation: 61775
I'm testing using the latest version of Chrome (websocket version 13).
Here's my simple client page located at http://127.0.0.1/folder/default.aspx
:
<script type="text/javascript">
var socket = new WebSocket('ws://localhost:8181/websession');
socket.onopen = function () {
alert('handshake successfully established. May send data now...');
};
socket.onclose = function () {
alert('connection closed');
};
socket.onmessage = function(msg) {
alert(msg);
};
</script>
And here's my listener (c#)
var listener = new TcpListener(IPAddress.Loopback, 8181);
listener.Start();
while (true)
{
Console.WriteLine("Listening...");
using (var client = listener.AcceptTcpClient())
using (var stream = client.GetStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:8181/websession");
writer.WriteLine("");
}
Console.WriteLine("Finished");
}
When I run the server, and then load the client page it only says "connection closed"
.
Could someone please tell me how to get this handshake performing correctly? As far as I can tell from documentation and previous questions, the response I'm sending back to the client looks correct.
Upvotes: 4
Views: 2447
Reputation: 144
StreamReader and StreamWriter on dispose are closing underlying stream (NetworkStream).So client page only says "connection closed"
Upvotes: 1
Reputation: 116178
Based on your code ,this should work (at least with chrome)
var listener = new TcpListener(IPAddress.Loopback, 8181);
listener.Start();
while (true)
{
Console.WriteLine("Listening...");
using (var client = listener.AcceptTcpClient())
using (var stream = client.GetStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
string line = null, key = "", responseKey = "";
string MAGIC_STRING = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
while (line != "")
{
line = reader.ReadLine();
if (line.StartsWith("Sec-WebSocket-Key:"))
{
key = line.Split(':')[1].Trim();
}
}
if (key != "")
{
key += MAGIC_STRING;
using (var sha1 = SHA1.Create())
{
responseKey = Convert.ToBase64String(sha1.ComputeHash(Encoding.ASCII.GetBytes(key)));
}
}
// send handshake to the client
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:8181/websession");
if (!String.IsNullOrEmpty(responseKey))
writer.WriteLine("Sec-WebSocket-Accept: " + responseKey);
writer.WriteLine("");
writer.Flush();
SendString(stream, "This code works!!!!");
SendString(stream, "This code also works!!!! ".PadRight(300, '.') + "\r\nEND");
}
Console.WriteLine("Finished");
}
void SendString(Stream s, string str)
{
var buf = Encoding.UTF8.GetBytes(str);
int frameSize = 64;
var parts = buf.Select((b, i) => new { b, i })
.GroupBy(x => x.i / (frameSize - 1))
.Select(x => x.Select(y => y.b).ToArray())
.ToList();
for (int i = 0; i < parts.Count; i++ )
{
byte cmd = 0;
if (i == 0) cmd |= 1;
if (i == parts.Count - 1) cmd |= 0x80;
s.WriteByte(cmd);
s.WriteByte((byte)parts[i].Length);
s.Write(parts[i], 0, parts[i].Length);
}
s.Flush();
}
PS: Use
socket.onmessage = function(msg) {
alert(msg.data);
};
to see the content of message sent by the server.
Upvotes: 3
Reputation: 1063884
You haven't computed the security hash. The client sends you a number, and there is another number hard-coded in the spec. You need to combine them as per the instructions in the spec, and return it as a header.
This demonstrates that your server is actually a web-socket server.
See RFC6455
Note that you might also want to consider whether to implement Hixie 76 in addition to the RFC.
Upvotes: 2