Websocket服务器:在网络套接字上的onopen函数从未被调用

62

我正在尝试实现一个C# WebSocket服务器,但是它给了我一些麻烦。 我运行一个Web服务器(ASP.NET),用来托管包含JavaScript的页面,而WebSocket服务器则作为一个C#控制台应用程序实现。

我能够检测到来自客户端(运行JavaScript的Chrome浏览器)的连接尝试,并且还能从客户端检索到握手信息。但是客户端似乎无法接受我发送回来的握手(Web Socket上的onopen函数从未被调用)。

我一直在阅读The Web Socket protocol,但我无法看出我做错了什么。 这里是一部分服务器代码:

Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8181);
listener.Bind(ep);
listener.Listen(100);
Console.WriteLine("Wainting for connection...");
Socket socketForClient = listener.Accept();
if (socketForClient.Connected)
{
    Console.WriteLine("Client connected");
    NetworkStream networkStream = new NetworkStream(socketForClient);
    System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
    System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);

    //read handshake from client:
    Console.WriteLine("HANDSHAKING...");
    char[] shake = new char[255];
    streamReader.Read(shake, 0, 255);

    string handshake =
       "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" +
       "Upgrade: WebSocket\r\n" +
       "Connection: Upgrade\r\n" +
       "WebSocket-Origin: http://localhost:8080\r\n" +
       "WebSocket-Location: ws://localhost:8181\r\n" +
       "\r\n";

    streamWriter.Write(handshake);
    streamWriter.Flush();

我在本地主机上的8080端口运行Web服务器和8181端口运行Web Socket服务器。

我尝试使用不同的编码(ASCII,字节和十六进制)发送握手请求,但似乎没有任何区别。连接从未完全建立。

JavaScript 代码如下:

var ws;
var host = 'ws://localhost:8181';
debug("Connecting to " + host + " ...");
try {
 ws = new WebSocket(host);
} catch (err) {
 debug(err, 'error');
}
ws.onopen = function () {
 debug("connected...", 'success');
};
ws.onclose = function () {
 debug("Socket closed!", 'error');
};
ws.onmessage = function (evt) {
 debug('response: ' + evt, 'response');
};

我猜测错误在于C#服务器,因为Chrome已经按照应该的方式发送了信息,但就像我说的,onopen函数从未被调用。

简而言之,我的问题是: 你们中有人完成过这个吗?如果是,你是怎么做到的? 当然:你能否看出代码中的明显错误(希望这不是太多要求)。


1
你可能想使用NuGet上提供的Fleck:http://nuget.org/packages/Fleck/ - Matt Cruikshank
3个回答

50

很可能是一个编码问题。这是我写的一个可工作的C#服务器:

class Program
{
    static void Main(string[] args)
    {
        var listener = new TcpListener(IPAddress.Loopback, 8181);
        listener.Start();
        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://localhost:8080");
            writer.WriteLine("WebSocket-Location: ws://localhost:8181/websession");
            writer.WriteLine("");
        }
        listener.Stop();
    }
}

对应的客户端托管在 localhost:8080 上:

<!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 = new WebSocket('ws://localhost:8181/websession');
      socket.onopen = function() {
        alert('handshake successfully established. May send data now...');
      };
      socket.onclose = function() {
        alert('connection closed');
      };
    </script>
  </head>
  <body>
  </body>
</html>

这个例子仅建立握手。你需要调整服务器以继续在握手建立后接受数据。


1
原来问题出在握手的WebSocket-Location部分。显然它不能只是'ws://localhost:8181'。 将其更改为'ws://localhost:8181/something'并将javascript中的主机更改为相同的内容-它就可以工作了。谢谢! - Jon List
感谢您的文章。我正在使用Chrome +一个静态HTML文件尝试这个,不得不更改源以防止浏览器立即断开连接:writer.WriteLine(“WebSocket-Origin:file://”); - Josh Rickard
@Darin,你的代码运行得很好。当我删除了那个“using”并像平常一样声明了那个“writer”时,它就不起作用了。问题在于写入器没有将数据写回客户端。你能解释一下吗? - prabhakaran
@Darin,我找到了我的问题的答案。答案是“writer.Flush()”。 - prabhakaran

24
请使用UTF8编码发送文本消息。
有一个由C#实现的开源WebSocket服务器,您可以直接使用它。 http://superwebsocket.codeplex.com/ 这是我的开源项目!

2
现在,SuperWebSocket 还包含了 WebSocket 客户端实现! - Kerry Jiang

3
.NET Framework 4.5引入了对WebSockets的支持,可以在Windows Communication Foundation中使用。WebSockets是一种高效的、基于标准的技术,可以通过标准HTTP端口80和443实现双向通信。使用标准HTTP端口可允许WebSockets通过代理在web上进行通信。添加了两个新的标准绑定来支持WebSocket传输。NetHttpBinding和NetHttpsBinding。可以通过访问WebSocketSettings属性,在HttpTransportBinding元素上配置WebSockets特定的设置。
我认为它仍然使用SOAP(注:SOAP是一种协议,用于交换XML消息)。
链接:http://msdn.microsoft.com/en-us/library/hh674271(v=vs.110).aspx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接