POCO 1.5.1 Websocket客户端无法连接到c#websocket服务器

Ric*_*tte 5 c# c++ poco eventmachine websocket

问题:

websocket客户端(POCO 1.5.1,c ++)不会连接到websocket c#服务器(带有Fleck库的命令行应用程序).一个超时达到与抛出的异常:

Cannot upgrade to WebSocket connection: OK
Exception Code: 1

Poco WebException Documentation
WS_ERR_NO_HANDSHAKE = 1 : 
No Connection: Upgrade or Upgrade: websocket header in handshake request.
Run Code Online (Sandbox Code Playgroud)

事实1:这个websocket客户端将连接到Ruby Event Machine websocket服务器.

事实2:javascript客户端将连接到websocket c#服务器.

事实3:同样的javascript客户端也将连接到websocket ruby​​服务器.

事实4:websocket客户端不会连接到Alchemy Websocket服务器 neigther.https://github.com/Olivine-Labs/Alchemy-Websockets

使用Wireshark更新POCO正在使用 GET/HTTP/1.0\r \n

Javascript版本: GET/HTTP/1.1\r \n


所有源代码

c ++中的客户端代码

#include "Game.h"

#include <irrlicht.h>
#include "driverChoice.h"
#include <iostream>
#include <assert.h>

#include "Poco/Net/WebSocket.h"
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/Exception.h"

using Poco::Net::HTTPClientSession;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;
using Poco::Net::WebSocket;
using Poco::Net::WebSocketException;
using Poco::Exception;

// VS2010
// POCO 1.5.1
// Irrlicht 3D engine
// Windows 7 Enterprise edition

Game::Game(void)
{
}

Game::~Game(void)
{
}

//...

void Game::TestWebSocketClient()
{
  char buffer[1024];
  int flags;
  int n;
  std::string payload;

  try
  {
      HTTPClientSession cs("localhost", 8080);
      HTTPRequest request(HTTPRequest::HTTP_GET, "/ws");
      HTTPResponse response;
      std::string cmd;

      WebSocket * ws = new WebSocket(cs, request, response); // Causes the timeout

      payload = "SGClient: Hello World!";
      ws->sendFrame(payload.data(), payload.size(), WebSocket::FRAME_TEXT);
      n = ws->receiveFrame(buffer, sizeof(buffer), flags);

      while( cmd != "exit")
      {
        cmd = "";
        std::cin >> cmd;
        ws->sendFrame(cmd.data(), cmd.size(), WebSocket::FRAME_TEXT);
        n = ws->receiveFrame(buffer, sizeof(buffer), flags);
        if( n > 0 )
        {
            std::cout << buffer << std::endl;
        }
      }

      ws->shutdown();
  }
  catch (Exception ex)
  {
      return;
  }
Run Code Online (Sandbox Code Playgroud)

c#中的服务器代码

// vs2010
// fleck library
// Windows 7 enterprise edition


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Fleck;
using System.Timers;

namespace TestWebsocket
{
    class Program
    {
        static void Main()
        {
            FleckLog.Level = LogLevel.Debug;
            var allSockets = new List<IWebSocketConnection>();
            var server = new WebSocketServer("ws://localhost:8080");
            server.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    Console.WriteLine("Open!");
                    allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine("Close!");
                    allSockets.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                    Console.WriteLine(message);
                    allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
                };
            });

            var input = Console.ReadLine();
            while (input != "exit")
            {
                foreach (var socket in allSockets.ToList())
                {
                    socket.Send(input);
                }
                input = Console.ReadLine();
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

备用HTML/Javascript客户端代码,在Chrome版本31.0.1650.57 m中运行

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>websocket client</title>
    <script type="text/javascript">
        var start = function () {
            var inc = document.getElementById('incomming');
            var wsImpl = window.WebSocket || window.MozWebSocket;
            var form = document.getElementById('sendForm');
            var input = document.getElementById('sendText');

            inc.innerHTML += "connecting to server ..<br/>";

            // create a new websocket and connect
            window.ws = new wsImpl('ws://localhost:8080/');

            // when data is comming from the server, this metod is called
            ws.onmessage = function (evt) {
                inc.innerHTML += evt.data + '<br/>';
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                inc.innerHTML += '.. connection open<br/>';
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                inc.innerHTML += '.. connection closed<br/>';
            }

            form.addEventListener('submit', function(e){
                e.preventDefault();
                var val = input.value;
                ws.send(val);
                input.value = "";
            });

        }
        window.onload = start;
    </script>
</head>
<body>
    <form id="sendForm">
        <input id="sendText" placeholder="Text to send" />
    </form>
    <pre id="incomming"></pre>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

使用在命令行界面上运行的eventmachine的备用ruby服务器代码

// Ruby 1.9
// gem install em-websocket required.
require 'em-websocket'

EventMachine::WebSocket.start(:host => "localhost", :port => 8080) do |ws|
  ws.onopen    { ws.send "RS: Hello Client!"}
  ws.onmessage { 
            |msg| ws.send "RS: Pong: #{msg}" 
            puts msg 
           }
  ws.onclose   { puts "WebSocket closed" }
end
Run Code Online (Sandbox Code Playgroud)

Ric*_*tte 6

问题是 POCO 默认的 HTTP 请求版本是 1.0。

RFC 规范的第 4.1 节指出最小值为 1.1:

http://tools.ietf.org/html/rfc6455#section-4.1

  1. 请求的方法必须是 GET,并且 HTTP 版本必须至少为 1.1。例如,如果 WebSocket URI 是“ws://example.com/chat”,则发送的第一行应该是“GET /chat HTTP/1.1”。

通过将 HTTPRequest 结构替换为以下内容解决了问题:

HTTPRequest request(HTTPRequest::HTTP_GET, "/ws", "HTTP/1.1" );
Run Code Online (Sandbox Code Playgroud)

干杯!