Sign in to follow this  
Zuyko

WebSocket + C# - Handshake, client does not response on handshake

Recommended Posts

Hi guys.
I am trying to make connection between HTML5 WebSockets client, and Server written in C# .Net 4.0.
Client does connects server and server does get messages from it through stream, but then i've got issue with responding with handshake, probably or I do wrong way of sending response, or there is some other issue with connection or other things. I couldn't find more low-level of verifying where the issue appears.

So simple client on HTML5 + JavaScript:
[code]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
var socket = null;

console.log("creating socket");

try { // mozilla
socket = new MozWebSocket('ws://192.168.1.50:8181/webtest');
} catch(err) { // chrome
socket = new WebSocket('ws://192.168.1.50:8181/webtest');
}

if (socket != null) {
console.log("socket created");

socket.onopen = function() {
console.log("onopen");
};
socket.onmessage = function (evt) {
console.log("onmessage: " + evt.data);
};
socket.onclose = function() {
console.log("onclose");
};
socket.onerror = function(evt) {
console.log("onerror: " + evt);
};

console.log("callback functions bound");
}
</script>
</head>
</html>[/code]

With just normal open, it does output in console:
[code]creating socket
socket created
callback functions bound[/code]

After some time, looks like by timeout, while connection haven't been established, happens:
[code]onclose[/code]

So client does triggers on events and so on, lets try with server then.
Code is very simple, just to make things straight forward. Do not say anything that approach is really bad and so on, I do know that, this is made for little simple example:
[code]this.socketWeb = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);

IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 8181);

this.socketWeb.Bind(endPoint);

this.socketWeb.Listen(10);

string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

while (true) {
try {
Log.Add(" -1- ");

Socket clientWeb = this.socketWeb.Accept();

Log.Add(" -2- ");

NetworkStream stream = new NetworkStream(clientWeb);
StreamWriter streamWriter = new StreamWriter(stream);
StreamReader streamReader = new StreamReader(stream);

Log.Add(" -3- ");

string readed = "";
string key = "";
while (!string.IsNullOrEmpty(readed = streamReader.ReadLine())) {
Log.Add("< " + readed);
if (readed.Length > 20 && readed.Substring(0, 19) == "Sec-WebSocket-Key: ") {
key = readed.Substring(19);
}
}

SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(key+guid));
string acceptKey = Convert.ToBase64String(hash);

Log.Add(" -4- ");

List<string> handshakeLines = new List<string>();

handshakeLines.Add("HTTP/1.1 101 Switching Protocols");
handshakeLines.Add("Upgrade: websocket");
handshakeLines.Add("Connection: Upgrade");
handshakeLines.Add("Sec-WebSocket-Accept: "+acceptKey);

foreach (string line in handshakeLines) {
Log.Add("> " + line);
streamWriter.WriteLine(line);
}

Log.Add(" -5- ");
} catch (Exception ex) {
Log.Add(ex.ToString());
}
}[/code]
So here, by the flow we are waiting for connections, then creating Stream accessors and getting header information from WebSocket connection. Extracting the key and based on [url="http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#page-7"]documentation[/url] about how to generate answer key, I generated the answer key. Checked with given example data, and it does generate right response key, so there should not be an issue at all.
Then server sends lines with response.

What happens in the end, client connects, server gets the header, reads it, generates answer and sends answer back. No then there is no reaction on client at all. onopen event does not triggers, onerror as well does not triggers. Connection still going on, so it does not interrupts. If I close server, then client will get onclose event. So it does establish connection, but does not proceeds with handshake.

Here is logs from test, from server:
[code]-1-
-2-
-3-
< GET /webtest HTTP/1.1
< Host: 192.168.x.x:xxxx
< User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1
< Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
< Accept-Language: en-gb,en;q=0.5
< Accept-Encoding: gzip, deflate
< Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
< Connection: keep-alive, Upgrade
< Sec-WebSocket-Version: 8
< Sec-WebSocket-Origin: http://192.168.x.x
< Sec-WebSocket-Extensions: deflate-stream
< Sec-WebSocket-Key: tZ8vdQLijXN/V4S4IEMYrg==
< Pragma: no-cache
< Cache-Control: no-cache
< Upgrade: websocket
-4-
> HTTP/1.1 101 Switching Protocols
> Upgrade: websocket
> Connection: Upgrade
> Sec-WebSocket-Accept: 7YRAvVPSRoaTvhv5b3/GqKJroaY=
-5-[/code]
[i]I hide IP and Port.[/i]

Logs between points 3 and 4, is what we receive on server from client.
And logs between 4 and 5 is what server sends to client after.

I used Firefox 7.0.1, as well checked Chrome 14.0.835.186 m.

So I am trying to understand where is an issue, what I wrong here?

Cheers.

Share this post


Link to post
Share on other sites
Found an solution: just using Socket.Send, and big string with "\r\n" as next line will work well.

Again proved for my self, that is better to use simple byte[] conversions and do things my self, the using some StreamReaders and other stuff, that may work weird, because I may not have full understanding of them.
Not saying, that is not good to write everything by yourself, but its definitely better for learning.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this