Websockets使用asio c ++库作为服务器,javascript作为客户端 [英] Websockets using asio c++ library for the server and javascript as client

查看:221
本文介绍了Websockets使用asio c ++库作为服务器,javascript作为客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 asio 库在C ++中编写了服务器代码。我知道服务器代码工作,因为我测试它与客户端也写在C + +和使用 asio

I have written server code in C++ using the asio library. I know that the server code works, because I tested it with a client also written in C++ and using asio.

问题是,对于客户端使用以下javascript代码,连接不会被接受。我立即看到在javascript客户端上的消息框 Connection closed ... ,在服务器上我看到这个奇怪的消息:

The problem is that with the following javascript code for client, the connection doesn't get accepted. I immediately see the message box Connection closed... on the javascript client, and on the server I see this strange message:

Data RECEIVED: <------ I print this line myself
GET / HTTP/1.1
Host: localhost:15562
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://localhost:63344
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Sec-WebSocket-Key: IidMJmdoGe4kYu0+1VlrvQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

index.html - 连接只是立即关闭...几乎相同的代码此处

index.html - Connection just closes immediately... Almost same code as seen here

function WebSocketTest() {
    if ("WebSocket" in window) {
        var ws = new WebSocket("ws://localhost:15562");

        ws.onopen = function () {
            alert("Connection opened...");
        };

        ws.onmessage = function (evt) {
            alert("Message received...");
        };

        ws.onclose = function () {
            alert("Connection closed...");
        };

        ws.send("Hi, from the client");
        ws.send("Hi, from the client");
    }
}

server.cpp 这工作正常。与此处

#define ASIO_STANDALONE
#include <iostream>
#include <asio.hpp>

using asio::ip::tcp;

const std::size_t    max_length = 2048;
const unsigned short PORT       = 15562;


class Session
    : public std::enable_shared_from_this<Session>
{
public:
    Session(tcp::socket server_socket)
        : _session_socket(std::move(server_socket))
    {
    }

    void start()
    {
        do_read();
    }

private:
    void do_read()
    {
        auto self(shared_from_this()); // shared_ptr instance to this

        // Start an asynchronous read.
        // This function is used to asynchronously read data from the stream socket.
        _session_socket.async_read_some(asio::buffer(_data, max_length),
                                        [this, self](std::error_code error, std::size_t length)
                                        {
                                            if (!error)
                                            {
                                                std::cout << "Data RECEIVED: " << std::endl;
                                                std::cout << _data << std::endl;
                                                do_write(length);
                                            }
                                        });
    }

    void do_write(std::size_t length)
    {
        auto self(shared_from_this()); // shared_ptr instance to this

        // Start an asynchronous write.
        // This function is used to asynchronously write data to the stream socket.
        strncpy(_data, "Hi, from the server", max_length);
        asio::async_write(_session_socket, asio::buffer(_data, length),
                          [this, self](std::error_code error, std::size_t /*length*/)
                          {
                              if (!error)
                              {
                                  do_read();
                              }
                          });
    }

    tcp::socket _session_socket;
    char        _data[max_length];
};


class server
{
public:
    server(asio::io_service &io_service, const tcp::endpoint &endpoint)
        : _server_socket(io_service),
          _server_acceptor(io_service, endpoint)
    {
    }

    void do_accept()
    {
        // Start an asynchronous accept.
        // This function is used to asynchronously accept a new connection into a socket.
        _server_acceptor.async_accept(_server_socket,
                                      [this](std::error_code error)
                                      {
                                          // Accept succeeded
                                          if (!error)
                                          {
                                              // Create a session
                                              auto session = std::make_shared<Session>(
                                                  std::move(_server_socket));
                                              session->start();
                                          }

                                          // Continue to accept more connections
                                          do_accept();
                                      });
    }

private:
    tcp::acceptor _server_acceptor;
    tcp::socket   _server_socket;
};


int main()
{
    try
    {
        asio::io_service io_service;                   // io_service provides functionality for sockets, connectors, etc
        tcp::endpoint    endpoint(tcp::v4(), PORT);    // create an endpoint using a IP='any' and the specified PORT
        server           server(io_service, endpoint); // create server on PORT
        server.do_accept();
        std::cout << "Server started on port: " << PORT << std::endl;
        io_service.run();
    }
    catch (std::exception &e)
    {
        std::cerr << "Exception: " << e.what() << "\n"; // Print error
    }

    return 0;
}

client.cpp 几乎与此处

#define ASIO_STANDALONE  
#include <iostream>
#include <asio.hpp>

using asio::ip::tcp;


int main(int argc, char *argv[])
{
    asio::io_service io_service;
    tcp::socket      socket(io_service);
    tcp::resolver    resolver(io_service);
    // Connect
    asio::connect(socket, resolver.resolve({"localhost", "15562"}));

    for (int i = 0; i < 10; ++i)
    {
        std::cout << "Enter message to sent to server:" << std::endl;
        char client_message[2048];
        std::cin.getline(client_message, 2048);
        // Send message to server
        asio::write(socket, asio::buffer(client_message, 2048));

        char server_message[2048];
        // Read message from server
        asio::read(socket, asio::buffer(server_message, 2048));
        std::cout << "Reply is: " << std::endl;
        std::cout << server_message << std::endl;
    }

    return 0;
}


推荐答案

你指向和等待头像:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 5A4gqmvwM2kbopObEm+Kr6zBrNw=
Sec-WebSocket-Protocol: echo-protocol

但是你发回了已经获得的同一个头。这是不正确的。所以你得到连接关闭...。
您应该为Sec-WebSocket-Accept创建正确的头。

But you send back same header that has gotten. It is not correct. So you are getting "Connection closed...". You should make header with correct value for Sec-WebSocket-Accept.

例如,do_write方法可能看起来

For example, do_write method may look

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());

    std::stringstream handshake;

    std::string tmp(data_);
    tmp.erase(0, tmp.find("Sec-WebSocket-Key: ") + strlen("Sec-WebSocket-Key: "));
    auto key = tmp.substr(0, tmp.find("\r\n"));

    auto sha1 = SimpleWeb::Crypto::SHA1(key + ws_magic_string);

    handshake << "HTTP/1.1 101 Switching Protocols\r\n";
    handshake << "Upgrade: websocket\r\n";
    handshake << "Connection: Upgrade\r\n";
    handshake << "Sec-WebSocket-Accept: " << SimpleWeb::Crypto::Base64::encode(sha1) << "\r\n";
    handshake << "Sec-WebSocket-Protocol: echo-protocol\r\n";
    handshake << "\r\n";

    boost::asio::async_write(socket_, boost::asio::buffer(handshake.str().c_str(), handshake.str().size()),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

这里我使用了项目 https://github.com/eidheim/Simple-WebSocket-Server ,将ws_magic_string定义为

Here i used Crypto's methods from project https://github.com/eidheim/Simple-WebSocket-Server, there defined ws_magic_string as

  const std::string ws_magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

祝你好运。

这篇关于Websockets使用asio c ++库作为服务器,javascript作为客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆