Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
e8583000b8 | |||
d642ef1a89 | |||
2df118022d | |||
95457c8f4c | |||
0a45b7787f | |||
b8c397e180 | |||
90105fa2b3 | |||
24859fef8a |
1
examples/ping_pong/.gitignore → .gitignore
vendored
1
examples/ping_pong/.gitignore → .gitignore
vendored
@ -1,2 +1 @@
|
||||
venv
|
||||
build
|
@ -10,6 +10,7 @@ set (CMAKE_CXX_STANDARD 14)
|
||||
set (CXX_STANDARD_REQUIRED ON)
|
||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# -Wshorten-64-to-32 does not work with clang
|
||||
if (NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
|
||||
endif()
|
||||
@ -113,3 +114,5 @@ set( IXWEBSOCKET_INCLUDE_DIRS
|
||||
.
|
||||
../../shared/OpenSSL/include)
|
||||
target_include_directories( ixwebsocket PUBLIC ${IXWEBSOCKET_INCLUDE_DIRS} )
|
||||
|
||||
add_subdirectory(ws)
|
||||
|
12
README.md
12
README.md
@ -15,7 +15,7 @@ communication channels over a single TCP connection. *IXWebSocket* is a C++ libr
|
||||
|
||||
## Examples
|
||||
|
||||
The examples folder countains a simple chat program, using a node.js broadcast server.
|
||||
The ws folder countains many interactive programs for chat and file transfers demonstrating client and server usage.
|
||||
|
||||
Here is what the client API looks like.
|
||||
|
||||
@ -144,16 +144,6 @@ Large frames are broken up into smaller chunks or messages to avoid filling up t
|
||||
* Automatic reconnection works at the TCP socket level, and will detect remote end disconnects. However, if the device/computer network become unreachable (by turning off wifi), it is quite hard to reliably and timely detect it at the socket level using `recv` and `send` error codes. [Here](https://stackoverflow.com/questions/14782143/linux-socket-how-to-detect-disconnected-network-in-a-client-program) is a good discussion on the subject. This behavior is consistent with other runtimes such as node.js. One way to detect a disconnected device with low level C code is to do a name resolution with DNS but this can be expensive. Mobile devices have good and reliable API to do that.
|
||||
* The server code is using select to detect incoming data, and creates one OS thread per connection. This isn't as scalable as strategies using epoll or kqueue.
|
||||
|
||||
## Examples
|
||||
|
||||
1. Bring up a terminal and jump to the examples folder.
|
||||
2. Compile the example C++ code. `sh build.sh`
|
||||
3. Install node.js from [here](https://nodejs.org/en/download/).
|
||||
4. Type `npm install` to install the node.js dependencies. Then `node broadcast-server.js` to run the server.
|
||||
5. Bring up a second terminal. `./cmd_websocket_chat bob`
|
||||
6. Bring up a third terminal. `./cmd_websocket_chat bill`
|
||||
7. Start typing things in any of those terminals. Hopefully you should see your message being received on the other end.
|
||||
|
||||
## C++ code organization
|
||||
|
||||
Here's a simplistic diagram which explains how the code is structured in term of class/modules.
|
||||
|
7
examples/CMakeLists.txt
Normal file
7
examples/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
add_subdirectory(broadcast_server)
|
||||
add_subdirectory(ping_pong)
|
||||
add_subdirectory(chat)
|
||||
add_subdirectory(echo_server)
|
||||
add_subdirectory(ws_connect)
|
||||
|
||||
# add_subdirectory(cobra_publisher)
|
9
examples/broadcast_server/.gitignore
vendored
9
examples/broadcast_server/.gitignore
vendored
@ -1,9 +0,0 @@
|
||||
CMakeCache.txt
|
||||
package-lock.json
|
||||
CMakeFiles
|
||||
ixwebsocket_unittest
|
||||
cmake_install.cmake
|
||||
node_modules
|
||||
ixwebsocket
|
||||
Makefile
|
||||
build
|
@ -1,30 +0,0 @@
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
project (broadcast_server)
|
||||
|
||||
# There's -Weverything too for clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshorten-64-to-32")
|
||||
|
||||
set (OPENSSL_PREFIX /usr/local/opt/openssl) # Homebrew openssl
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
include_directories(broadcast_server .)
|
||||
|
||||
add_executable(broadcast_server
|
||||
broadcast_server.cpp)
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(broadcast_server "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
target_link_libraries(broadcast_server ixwebsocket)
|
||||
install(TARGETS broadcast_server DESTINATION bin)
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* broadcast_server.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXWebSocketServer.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int port = 8080;
|
||||
if (argc == 2)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << argv[1];
|
||||
ss >> port;
|
||||
}
|
||||
|
||||
ix::WebSocketServer server(port);
|
||||
|
||||
server.setOnConnectionCallback(
|
||||
[&server](std::shared_ptr<ix::WebSocket> webSocket)
|
||||
{
|
||||
webSocket->setOnMessageCallback(
|
||||
[webSocket, &server](ix::WebSocketMessageType messageType,
|
||||
const std::string& str,
|
||||
size_t wireSize,
|
||||
const ix::WebSocketErrorInfo& error,
|
||||
const ix::WebSocketOpenInfo& openInfo,
|
||||
const ix::WebSocketCloseInfo& closeInfo)
|
||||
{
|
||||
if (messageType == ix::WebSocket_MessageType_Open)
|
||||
{
|
||||
std::cerr << "New connection" << std::endl;
|
||||
std::cerr << "Uri: " << openInfo.uri << std::endl;
|
||||
std::cerr << "Headers:" << std::endl;
|
||||
for (auto it : openInfo.headers)
|
||||
{
|
||||
std::cerr << it.first << ": " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Close)
|
||||
{
|
||||
std::cerr << "Closed connection" << std::endl;
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Message)
|
||||
{
|
||||
std::cerr << "Received " << wireSize << " bytes" << std::endl;
|
||||
for (auto&& client : server.getClients())
|
||||
{
|
||||
if (client != webSocket)
|
||||
{
|
||||
client->send(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
auto res = server.listen();
|
||||
if (!res.first)
|
||||
{
|
||||
std::cerr << res.second << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.start();
|
||||
server.wait();
|
||||
|
||||
return 0;
|
||||
}
|
3
examples/chat/.gitignore
vendored
3
examples/chat/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
build
|
||||
venv
|
||||
node_modules
|
@ -1,23 +0,0 @@
|
||||
#
|
||||
# cmd_websocket_chat.cpp
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
project (cmd_websocket_chat)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
add_executable(cmd_websocket_chat cmd_websocket_chat.cpp)
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(cmd_websocket_chat "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
target_link_libraries(cmd_websocket_chat ixwebsocket)
|
||||
install(TARGETS cmd_websocket_chat DESTINATION bin)
|
@ -1,39 +0,0 @@
|
||||
# Building
|
||||
|
||||
1. cmake -G .
|
||||
2. make
|
||||
|
||||
## Disable TLS
|
||||
|
||||
chat$ cmake -DUSE_TLS=OFF .
|
||||
-- Configuring done
|
||||
-- Generating done
|
||||
-- Build files have been written to: /Users/bsergeant/src/foss/ixwebsocket/examples/chat
|
||||
chat$ make
|
||||
Scanning dependencies of target ixwebsocket
|
||||
[ 16%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXSocket.cpp.o
|
||||
[ 33%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXWebSocket.cpp.o
|
||||
[ 50%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXWebSocketTransport.cpp.o
|
||||
[ 66%] Linking CXX static library libixwebsocket.a
|
||||
[ 66%] Built target ixwebsocket
|
||||
[ 83%] Linking CXX executable cmd_websocket_chat
|
||||
[100%] Built target cmd_websocket_chat
|
||||
|
||||
## Enable TLS (default)
|
||||
|
||||
```
|
||||
chat$ cmake -DUSE_TLS=ON .
|
||||
-- Configuring done
|
||||
-- Generating done
|
||||
-- Build files have been written to: /Users/bsergeant/src/foss/ixwebsocket/examples/chat
|
||||
(venv) chat$ make
|
||||
Scanning dependencies of target ixwebsocket
|
||||
[ 14%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXSocket.cpp.o
|
||||
[ 28%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXWebSocket.cpp.o
|
||||
[ 42%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXWebSocketTransport.cpp.o
|
||||
[ 57%] Building CXX object ixwebsocket/CMakeFiles/ixwebsocket.dir/ixwebsocket/IXSocketAppleSSL.cpp.o
|
||||
[ 71%] Linking CXX static library libixwebsocket.a
|
||||
[ 71%] Built target ixwebsocket
|
||||
[ 85%] Linking CXX executable cmd_websocket_chat
|
||||
[100%] Built target cmd_websocket_chat
|
||||
```
|
@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
# 'manual' way of building. You can also use cmake.
|
||||
|
||||
g++ --std=c++11 \
|
||||
../../ixwebsocket/IXSocket.cpp \
|
||||
../../ixwebsocket/IXWebSocketTransport.cpp \
|
||||
../../ixwebsocket/IXWebSocket.cpp \
|
||||
-I ../.. \
|
||||
cmd_websocket_chat.cpp \
|
||||
-o cmd_websocket_chat
|
@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
# 'manual' way of building. You can also use cmake.
|
||||
|
||||
clang++ --std=c++11 --stdlib=libc++ \
|
||||
../../ixwebsocket/IXSocket.cpp \
|
||||
../../ixwebsocket/IXWebSocketTransport.cpp \
|
||||
../../ixwebsocket/IXSocketAppleSSL.cpp \
|
||||
../../ixwebsocket/IXWebSocket.cpp \
|
||||
cmd_websocket_chat.cpp \
|
||||
-o cmd_websocket_chat \
|
||||
-framework Security \
|
||||
-framework Foundation
|
31
examples/chat/package-lock.json
generated
31
examples/chat/package-lock.json
generated
@ -1,31 +0,0 @@
|
||||
{
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"ultron": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"requires": {
|
||||
"async-limiter": "1.0.0",
|
||||
"safe-buffer": "5.1.2",
|
||||
"ultron": "1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"msgpack-js": "^0.3.0",
|
||||
"ws": "^3.3.3"
|
||||
}
|
||||
}
|
@ -15,8 +15,6 @@ set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
include_directories(cobra_publisher ${OPENSSL_PREFIX}/include)
|
||||
include_directories(cobra_publisher .)
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
project (echo_server)
|
||||
|
||||
# There's -Weverything too for clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshorten-64-to-32")
|
||||
|
||||
set (OPENSSL_PREFIX /usr/local/opt/openssl) # Homebrew openssl
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
include_directories(echo_server .)
|
||||
|
||||
add_executable(echo_server
|
||||
echo_server.cpp)
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(echo_server "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
target_link_libraries(echo_server ixwebsocket)
|
||||
install(TARGETS echo_server DESTINATION bin)
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* echo_server.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXWebSocketServer.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int port = 8080;
|
||||
if (argc == 2)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << argv[1];
|
||||
ss >> port;
|
||||
}
|
||||
|
||||
ix::WebSocketServer server(port);
|
||||
|
||||
server.setOnConnectionCallback(
|
||||
[&server](std::shared_ptr<ix::WebSocket> webSocket)
|
||||
{
|
||||
webSocket->setOnMessageCallback(
|
||||
[webSocket, &server](ix::WebSocketMessageType messageType,
|
||||
const std::string& str,
|
||||
size_t wireSize,
|
||||
const ix::WebSocketErrorInfo& error,
|
||||
const ix::WebSocketOpenInfo& openInfo,
|
||||
const ix::WebSocketCloseInfo& closeInfo)
|
||||
{
|
||||
if (messageType == ix::WebSocket_MessageType_Open)
|
||||
{
|
||||
std::cerr << "New connection" << std::endl;
|
||||
std::cerr << "Uri: " << openInfo.uri << std::endl;
|
||||
std::cerr << "Headers:" << std::endl;
|
||||
for (auto it : openInfo.headers)
|
||||
{
|
||||
std::cerr << it.first << ": " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Close)
|
||||
{
|
||||
std::cerr << "Closed connection" << std::endl;
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Message)
|
||||
{
|
||||
webSocket->send(str);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
auto res = server.listen();
|
||||
if (!res.first)
|
||||
{
|
||||
std::cerr << res.second << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.start();
|
||||
server.wait();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
project (ping_pong)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
add_executable(ping_pong ping_pong.cpp)
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(ping_pong "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(ping_pong wsock32 ws2_32)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_link_libraries(ping_pong ixwebsocket)
|
||||
install(TARGETS ping_pong DESTINATION bin)
|
@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
# 'manual' way of building. You can also use cmake.
|
||||
|
||||
g++ --std=c++11 \
|
||||
../../ixwebsocket/IXSocket.cpp \
|
||||
../../ixwebsocket/IXWebSocketTransport.cpp \
|
||||
../../ixwebsocket/IXWebSocket.cpp \
|
||||
-I ../.. \
|
||||
cmd_websocket_chat.cpp \
|
||||
-o cmd_websocket_chat
|
@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
async def hello(uri):
|
||||
async with websockets.connect(uri) as websocket:
|
||||
await websocket.send("Hello world!")
|
||||
response = await websocket.recv()
|
||||
print(response)
|
||||
|
||||
pong_waiter = await websocket.ping('coucou')
|
||||
ret = await pong_waiter # only if you want to wait for the pong
|
||||
print(ret)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(
|
||||
hello('ws://localhost:5678'))
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
import websockets
|
||||
|
||||
async def echo(websocket, path):
|
||||
async for message in websocket:
|
||||
print(message)
|
||||
await websocket.send(message)
|
||||
|
||||
if os.getenv('TEST_CLOSE'):
|
||||
print('Closing')
|
||||
# breakpoint()
|
||||
await websocket.close(1001, 'close message')
|
||||
# await websocket.close()
|
||||
break
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(
|
||||
websockets.serve(echo, 'localhost', 5678))
|
||||
asyncio.get_event_loop().run_forever()
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test -d build || {
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
}
|
||||
(cd build ; make)
|
||||
./build/ping_pong ws://localhost:5678
|
3
examples/ws_connect/.gitignore
vendored
3
examples/ws_connect/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
build
|
||||
venv
|
||||
node_modules
|
@ -1,22 +0,0 @@
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.4.1)
|
||||
project (ws_connect)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ixwebsocket)
|
||||
|
||||
add_executable(ws_connect ws_connect.cpp)
|
||||
|
||||
if (APPLE AND USE_TLS)
|
||||
target_link_libraries(ws_connect "-framework foundation" "-framework security")
|
||||
endif()
|
||||
|
||||
target_link_libraries(ws_connect ixwebsocket)
|
||||
install(TARGETS ws_connect DESTINATION bin)
|
@ -1,11 +0,0 @@
|
||||
# Building
|
||||
|
||||
1. mkdir build
|
||||
2. cd build
|
||||
3. cmake ..
|
||||
4. make
|
||||
|
||||
## Disable TLS
|
||||
|
||||
* Enable: `cmake -DUSE_TLS=OFF ..`
|
||||
* Disable: `cmake -DUSE_TLS=ON ..`
|
@ -1,25 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Author: Benjamin Sergeant
|
||||
# Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
# 'manual' way of building. You can also use cmake.
|
||||
|
||||
g++ --std=c++11 \
|
||||
-DIXWEBSOCKET_USE_TLS \
|
||||
-g \
|
||||
../../ixwebsocket/IXEventFd.cpp \
|
||||
../../ixwebsocket/IXSocket.cpp \
|
||||
../../ixwebsocket/IXSetThreadName.cpp \
|
||||
../../ixwebsocket/IXWebSocketTransport.cpp \
|
||||
../../ixwebsocket/IXWebSocket.cpp \
|
||||
../../ixwebsocket/IXDNSLookup.cpp \
|
||||
../../ixwebsocket/IXSocketConnect.cpp \
|
||||
../../ixwebsocket/IXSocketOpenSSL.cpp \
|
||||
../../ixwebsocket/IXWebSocketPerMessageDeflate.cpp \
|
||||
../../ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp \
|
||||
-I ../.. \
|
||||
ws_connect.cpp \
|
||||
-o ws_connect \
|
||||
-lcrypto -lssl -lz -lpthread
|
5
makefile
5
makefile
@ -1,7 +1,10 @@
|
||||
#
|
||||
# This makefile is just used to easily work with docker (linux build)
|
||||
#
|
||||
all: run
|
||||
all: brew
|
||||
|
||||
brew:
|
||||
mkdir -p build && (cd build ; cmake .. ; make -j install)
|
||||
|
||||
.PHONY: docker
|
||||
docker:
|
||||
|
@ -7,15 +7,14 @@ cmake_minimum_required (VERSION 3.4.1)
|
||||
project (ws)
|
||||
|
||||
# There's -Weverything too for clang
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wshorten-64-to-32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
option(USE_TLS "Add TLS support" ON)
|
||||
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/.. ixwebsocket)
|
||||
|
||||
include_directories(ws .)
|
||||
include_directories(ws ..)
|
||||
include_directories(ws ../third_party)
|
||||
|
||||
add_executable(ws
|
||||
@ -24,6 +23,11 @@ add_executable(ws
|
||||
ixcrypto/IXHash.cpp
|
||||
ixcrypto/IXUuid.cpp
|
||||
|
||||
ws_ping_pong.cpp
|
||||
ws_broadcast_server.cpp
|
||||
ws_echo_server.cpp
|
||||
ws_chat.cpp
|
||||
ws_connect.cpp
|
||||
ws_transfer.cpp
|
||||
ws_send.cpp
|
||||
ws_receive.cpp
|
||||
@ -34,3 +38,4 @@ if (APPLE AND USE_TLS)
|
||||
endif()
|
||||
|
||||
target_link_libraries(ws ixwebsocket)
|
||||
install(TARGETS ws RUNTIME DESTINATION bin)
|
||||
|
@ -28,6 +28,11 @@ g++ --std=c++14 \
|
||||
ixcrypto/IXBase64.cpp \
|
||||
ixcrypto/IXHash.cpp \
|
||||
ixcrypto/IXUuid.cpp \
|
||||
ws_ping_pong.cpp \
|
||||
ws_broadcast_server.cpp \
|
||||
ws_echo_server.cpp \
|
||||
ws_chat.cpp \
|
||||
ws_connect.cpp \
|
||||
ws_transfer.cpp \
|
||||
ws_send.cpp \
|
||||
ws_receive.cpp \
|
||||
|
61
ws/ws.cpp
61
ws/ws.cpp
@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
//
|
||||
//
|
||||
// Main drive for websocket utilities
|
||||
//
|
||||
|
||||
@ -13,16 +13,28 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <cli11/CLI11.hpp>
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
int ws_ping_pong_main(const std::string& url);
|
||||
|
||||
int ws_echo_server_main(int port);
|
||||
|
||||
int ws_broadcast_server_main(int port);
|
||||
|
||||
int ws_chat_main(const std::string& url,
|
||||
const std::string& user);
|
||||
|
||||
int ws_connect_main(const std::string& url);
|
||||
|
||||
int ws_receive_main(const std::string& url,
|
||||
bool enablePerMessageDeflate);
|
||||
|
||||
extern int ws_transfer_main(int port);
|
||||
int ws_transfer_main(int port);
|
||||
|
||||
extern int ws_send_main(const std::string& url,
|
||||
const std::string& path);
|
||||
int ws_send_main(const std::string& url,
|
||||
const std::string& path);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@ -30,8 +42,9 @@ int main(int argc, char** argv)
|
||||
CLI::App app{"ws is a websocket tool"};
|
||||
app.require_subcommand();
|
||||
|
||||
std::string url;
|
||||
std::string url("ws://127.0.0.1:8080");
|
||||
std::string path;
|
||||
std::string user;
|
||||
int port = 8080;
|
||||
|
||||
CLI::App* sendApp = app.add_subcommand("send", "Send a file");
|
||||
@ -44,8 +57,26 @@ int main(int argc, char** argv)
|
||||
CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server");
|
||||
transferApp->add_option("--port", port, "Connection url");
|
||||
|
||||
CLI::App* connectApp = app.add_subcommand("connect", "Connect to a remote server");
|
||||
connectApp->add_option("url", url, "Connection url")->required();
|
||||
|
||||
CLI::App* chatApp = app.add_subcommand("chat", "Group chat");
|
||||
chatApp->add_option("url", url, "Connection url")->required();
|
||||
chatApp->add_option("user", user, "User name")->required();
|
||||
|
||||
CLI::App* echoServerApp = app.add_subcommand("echo_server", "Echo server");
|
||||
echoServerApp->add_option("--port", port, "Connection url");
|
||||
|
||||
CLI::App* broadcastServerApp = app.add_subcommand("broadcast_server", "Broadcasting server");
|
||||
broadcastServerApp->add_option("--port", port, "Connection url");
|
||||
|
||||
CLI::App* pingPongApp = app.add_subcommand("ping", "Ping pong");
|
||||
pingPongApp->add_option("url", url, "Connection url")->required();
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
ix::Socket::init();
|
||||
|
||||
if (app.got_subcommand("transfer"))
|
||||
{
|
||||
return ix::ws_transfer_main(port);
|
||||
@ -59,6 +90,26 @@ int main(int argc, char** argv)
|
||||
bool enablePerMessageDeflate = false;
|
||||
return ix::ws_receive_main(url, enablePerMessageDeflate);
|
||||
}
|
||||
else if (app.got_subcommand("connect"))
|
||||
{
|
||||
return ix::ws_connect_main(url);
|
||||
}
|
||||
else if (app.got_subcommand("chat"))
|
||||
{
|
||||
return ix::ws_chat_main(url, user);
|
||||
}
|
||||
else if (app.got_subcommand("echo_server"))
|
||||
{
|
||||
return ix::ws_echo_server_main(port);
|
||||
}
|
||||
else if (app.got_subcommand("broadcast_server"))
|
||||
{
|
||||
return ix::ws_broadcast_server_main(port);
|
||||
}
|
||||
else if (app.got_subcommand("ping"))
|
||||
{
|
||||
return ix::ws_ping_pong_main(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
|
72
ws/ws_broadcast_server.cpp
Normal file
72
ws/ws_broadcast_server.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* ws_broadcast_server.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXWebSocketServer.h>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
int ws_broadcast_server_main(int port)
|
||||
{
|
||||
std::cout << "Listening on port " << port << std::endl;
|
||||
|
||||
ix::WebSocketServer server(port);
|
||||
|
||||
server.setOnConnectionCallback(
|
||||
[&server](std::shared_ptr<ix::WebSocket> webSocket)
|
||||
{
|
||||
webSocket->setOnMessageCallback(
|
||||
[webSocket, &server](ix::WebSocketMessageType messageType,
|
||||
const std::string& str,
|
||||
size_t wireSize,
|
||||
const ix::WebSocketErrorInfo& error,
|
||||
const ix::WebSocketOpenInfo& openInfo,
|
||||
const ix::WebSocketCloseInfo& closeInfo)
|
||||
{
|
||||
if (messageType == ix::WebSocket_MessageType_Open)
|
||||
{
|
||||
std::cerr << "New connection" << std::endl;
|
||||
std::cerr << "Uri: " << openInfo.uri << std::endl;
|
||||
std::cerr << "Headers:" << std::endl;
|
||||
for (auto it : openInfo.headers)
|
||||
{
|
||||
std::cerr << it.first << ": " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Close)
|
||||
{
|
||||
std::cerr << "Closed connection" << std::endl;
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Message)
|
||||
{
|
||||
std::cerr << "Received " << wireSize << " bytes" << std::endl;
|
||||
for (auto&& client : server.getClients())
|
||||
{
|
||||
if (client != webSocket)
|
||||
{
|
||||
client->send(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
auto res = server.listen();
|
||||
if (!res.first)
|
||||
{
|
||||
std::cerr << res.second << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.start();
|
||||
server.wait();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
/*
|
||||
* cmd_websocket_chat.cpp
|
||||
* ws_chat.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
* Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
//
|
||||
// Simple chat program that talks to the node.js server at
|
||||
// websocket_chat_server/broacast-server.js
|
||||
//
|
||||
|
||||
//
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <queue>
|
||||
@ -20,19 +19,13 @@
|
||||
// for convenience
|
||||
using json = nlohmann::json;
|
||||
|
||||
using namespace ix;
|
||||
|
||||
namespace
|
||||
namespace ix
|
||||
{
|
||||
void log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
class WebSocketChat
|
||||
{
|
||||
public:
|
||||
WebSocketChat(const std::string& user);
|
||||
WebSocketChat(const std::string& url,
|
||||
const std::string& user);
|
||||
|
||||
void subscribe(const std::string& channel);
|
||||
void start();
|
||||
@ -46,19 +39,27 @@ namespace
|
||||
std::pair<std::string, std::string> decodeMessage(const std::string& str);
|
||||
|
||||
private:
|
||||
std::string _url;
|
||||
std::string _user;
|
||||
|
||||
ix::WebSocket _webSocket;
|
||||
|
||||
std::queue<std::string> _receivedQueue;
|
||||
|
||||
void log(const std::string& msg);
|
||||
};
|
||||
|
||||
WebSocketChat::WebSocketChat(const std::string& user) :
|
||||
WebSocketChat::WebSocketChat(const std::string& url,
|
||||
const std::string& user) :
|
||||
_url(url),
|
||||
_user(user)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void WebSocketChat::log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
size_t WebSocketChat::getReceivedMessagesCount() const
|
||||
{
|
||||
return _receivedQueue.size();
|
||||
@ -76,11 +77,10 @@ namespace
|
||||
|
||||
void WebSocketChat::start()
|
||||
{
|
||||
std::string url("ws://localhost:8080/");
|
||||
_webSocket.setUrl(url);
|
||||
_webSocket.setUrl(_url);
|
||||
|
||||
std::stringstream ss;
|
||||
log(std::string("Connecting to url: ") + url);
|
||||
log(std::string("Connecting to url: ") + _url);
|
||||
|
||||
_webSocket.setOnMessageCallback(
|
||||
[this](ix::WebSocketMessageType messageType,
|
||||
@ -164,10 +164,11 @@ namespace
|
||||
_webSocket.send(encodeMessage(text));
|
||||
}
|
||||
|
||||
void interactiveMain(const std::string& user)
|
||||
int ws_chat_main(const std::string& url,
|
||||
const std::string& user)
|
||||
{
|
||||
std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
|
||||
WebSocketChat webSocketChat(user);
|
||||
WebSocketChat webSocketChat(url, user);
|
||||
webSocketChat.start();
|
||||
|
||||
while (true)
|
||||
@ -188,16 +189,3 @@ namespace
|
||||
webSocketChat.stop();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::string user("user");
|
||||
if (argc == 2)
|
||||
{
|
||||
user = argv[1];
|
||||
}
|
||||
|
||||
Socket::init();
|
||||
interactiveMain(user);
|
||||
return 0;
|
||||
}
|
@ -9,15 +9,8 @@
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
|
||||
using namespace ix;
|
||||
|
||||
namespace
|
||||
namespace ix
|
||||
{
|
||||
void log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
class WebSocketConnect
|
||||
{
|
||||
public:
|
||||
@ -32,6 +25,8 @@ namespace
|
||||
private:
|
||||
std::string _url;
|
||||
ix::WebSocket _webSocket;
|
||||
|
||||
void log(const std::string& msg);
|
||||
};
|
||||
|
||||
WebSocketConnect::WebSocketConnect(const std::string& url) :
|
||||
@ -40,6 +35,11 @@ namespace
|
||||
;
|
||||
}
|
||||
|
||||
void WebSocketConnect::log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
void WebSocketConnect::stop()
|
||||
{
|
||||
_webSocket.stop();
|
||||
@ -148,18 +148,12 @@ namespace
|
||||
std::cout << std::endl;
|
||||
webSocketChat.stop();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
int ws_connect_main(const std::string& url)
|
||||
{
|
||||
std::cerr << "Usage: ws_connect <url>" << std::endl;
|
||||
return 1;
|
||||
Socket::init();
|
||||
interactiveMain(url);
|
||||
return 0;
|
||||
}
|
||||
std::string url = argv[1];
|
||||
|
||||
Socket::init();
|
||||
interactiveMain(url);
|
||||
return 0;
|
||||
}
|
||||
|
68
ws/ws_echo_server.cpp
Normal file
68
ws/ws_echo_server.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* ws_broadcast_server.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <ixwebsocket/IXWebSocketServer.h>
|
||||
|
||||
namespace ix
|
||||
{
|
||||
int ws_echo_server_main(int port)
|
||||
{
|
||||
std::cout << "Listening on port " << port << std::endl;
|
||||
|
||||
ix::WebSocketServer server(port);
|
||||
|
||||
server.setOnConnectionCallback(
|
||||
[&server](std::shared_ptr<ix::WebSocket> webSocket)
|
||||
{
|
||||
webSocket->setOnMessageCallback(
|
||||
[webSocket, &server](ix::WebSocketMessageType messageType,
|
||||
const std::string& str,
|
||||
size_t wireSize,
|
||||
const ix::WebSocketErrorInfo& error,
|
||||
const ix::WebSocketOpenInfo& openInfo,
|
||||
const ix::WebSocketCloseInfo& closeInfo)
|
||||
{
|
||||
if (messageType == ix::WebSocket_MessageType_Open)
|
||||
{
|
||||
std::cerr << "New connection" << std::endl;
|
||||
std::cerr << "Uri: " << openInfo.uri << std::endl;
|
||||
std::cerr << "Headers:" << std::endl;
|
||||
for (auto it : openInfo.headers)
|
||||
{
|
||||
std::cerr << it.first << ": " << it.second << std::endl;
|
||||
}
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Close)
|
||||
{
|
||||
std::cerr << "Closed connection" << std::endl;
|
||||
}
|
||||
else if (messageType == ix::WebSocket_MessageType_Message)
|
||||
{
|
||||
std::cerr << "Received "
|
||||
<< wireSize << " bytes"
|
||||
<< std::endl;
|
||||
webSocket->send(str);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
auto res = server.listen();
|
||||
if (!res.first)
|
||||
{
|
||||
std::cerr << res.second << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.start();
|
||||
server.wait();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ping_pong.cpp
|
||||
* ws_ping_pong.cpp
|
||||
* Author: Benjamin Sergeant
|
||||
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
|
||||
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
@ -9,15 +9,8 @@
|
||||
#include <ixwebsocket/IXWebSocket.h>
|
||||
#include <ixwebsocket/IXSocket.h>
|
||||
|
||||
using namespace ix;
|
||||
|
||||
namespace
|
||||
namespace ix
|
||||
{
|
||||
void log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
class WebSocketPingPong
|
||||
{
|
||||
public:
|
||||
@ -33,6 +26,8 @@ namespace
|
||||
private:
|
||||
std::string _url;
|
||||
ix::WebSocket _webSocket;
|
||||
|
||||
void log(const std::string& msg);
|
||||
};
|
||||
|
||||
WebSocketPingPong::WebSocketPingPong(const std::string& url) :
|
||||
@ -41,6 +36,11 @@ namespace
|
||||
;
|
||||
}
|
||||
|
||||
void WebSocketPingPong::log(const std::string& msg)
|
||||
{
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
void WebSocketPingPong::stop()
|
||||
{
|
||||
_webSocket.stop();
|
||||
@ -124,7 +124,7 @@ namespace
|
||||
_webSocket.send(text);
|
||||
}
|
||||
|
||||
void interactiveMain(const std::string& url)
|
||||
int ws_ping_pong_main(const std::string& url)
|
||||
{
|
||||
std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
|
||||
WebSocketPingPong webSocketPingPong(url);
|
||||
@ -155,17 +155,3 @@ namespace
|
||||
webSocketPingPong.stop();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: ping_pong <url>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string url = argv[1];
|
||||
|
||||
Socket::init();
|
||||
interactiveMain(url);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user