Websockets使用asioC++库作为服务器,使用javascript作为客户端
Websockets using asio c++ library for the server and javascript as client
我已经使用asio
库用C++编写了服务器代码。我知道服务器代码是有效的,因为我用一个同样用C++编写并使用asio
的客户端测试了它。
问题是,使用以下客户端的javascript代码,连接不会被接受。我立即在javascript客户端上看到消息框Connection closed...
,在服务器上看到这个奇怪的消息:
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-连接立即关闭。。。几乎与这里看到的代码相同
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;
}
您的javascript代码正在发送您指向的标头,并等待标头,如:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 5A4gqmvwM2kbopObEm+Kr6zBrNw=
Sec-WebSocket-Protocol: echo-protocol
但你们发送的是已经得到的相同的标题。这是不对的。所以你得到了"连接关闭…"。您应该为Sec WebSocket Accept制作具有正确值的标头。
例如,do_write方法可能看起来像
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("rn"));
auto sha1 = SimpleWeb::Crypto::SHA1(key + ws_magic_string);
handshake << "HTTP/1.1 101 Switching Protocolsrn";
handshake << "Upgrade: websocketrn";
handshake << "Connection: Upgradern";
handshake << "Sec-WebSocket-Accept: " << SimpleWeb::Crypto::Base64::encode(sha1) << "rn";
handshake << "Sec-WebSocket-Protocol: echo-protocolrn";
handshake << "rn";
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();
}
});
}
在这里,我使用了Crypto项目中的方法https://github.com/eidheim/Simple-WebSocket-Server,将ws_magic_string定义为
const std::string ws_magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
祝你好运。
相关文章:
- Javascript 找不到使用 emscripten 编译的导出 WASM 函数
- 如何使用EM_JS从带有参数的C++调用javascript方法
- 我可以使用谷歌 v8 在回调函数中获取 JavaScript 函数C++源文本吗?
- 用输出参数包装一个c++函数,以便在javascript/node中使用
- 如何在 v8 Javascript 中的多个函数中使用相同的上下文?
- 如何使用 cocos creator 在 Cocos2d-X/Cocos2d-JS 中调用 javascript 函数并
- 如何使用 emscripten 将使用 zlib 的项目转换为 javascript?
- 如何使用V8引擎从C 获取JavaScript字节码
- 使用 javascript 实现 Trade/Quote API(c++ 或 Java)
- QT WebKit桥:使用JavaScript调用C 功能
- 在 Internet Explorer 中使用 Javascript 调用C++
- Websockets使用asioC++库作为服务器,使用javascript作为客户端
- 使用JavaScript将Websocket连接到Qt财富服务器
- 在QWebview中使用javascript访问文件系统
- 是否有类似于CrossBridge的项目,但只是使用Javascript而不是Flash
- 我可以保存一个文件吗?该文件将由服务器端的php代码生成,只使用javascript/C/C++,而不打开浏览器
- 使用javascript ActiveX对象触发System.Windows.Forms dll
- 为什么在MongoDB或CouchDB中使用Javascript而不是其他语言,如Java, c++
- 如何在CEF3中使用JavaScript访问C++中的动态字符串值
- 使用JavaScript从UIWebView调用操作