Testing node httpServer and webSocketServer(ws)
Trying to implement a http-ws server that will close after a client is connected as illustrated below:
var HTTPserver =
httpServer(require('path')
.join(__dirname, 'www'));
HTTPserver
.on('listening', function()
{
console.log('HTTP listening:');
//---------------
var WebSocket = require('ws');
var webSocketServer =
new WebSocket.Server(
{
server: HTTPserver
});
webSocketServer
.on('connection',
function(ws)
{
console.log('client connected');
setTimeout(function()
{
console.log('trying to close webSocketserver');
webSocketServer.close();
setTimeout(function()
{
console.log('trying to close HTTPserver');
HTTPserver.close();
}, 1000);
}, 1000);
});
})
.on('close', function()
{
console.log('server closed'); // never happens
})
.on('error', function()
{
console.log('server error');
})
.listen(8000);
// this works when no Client Connection
/*
setTimeout(function()
{
HTTPserver.close();
}, 3000);
*/
I uploaded the full test project.
https://github.com/kenokabe/http-ws-test
HTTPserver.close(); works just as expected without ws client connections.
HTTPserver.close(); does not work (fails to close) with ws client connections.
Any idea what is going on and how to fix this issue? Thanks.
**PS. Please note that what I need to close is
NOT only ws connections but also httpServer.
I need to open and close whole frequently.
The reason to close httpServer is that the project is for plugin, and need to shut down httpServer in a specific case.**
UPDATE
I modified the code to close webSocketServer before httpServer, but still httpServer is alive.
I updated my gitHub
https://github.com/kenokabe/http-ws-test
Finding
How do I shutdown a Node.js http(s) server immediately?
Force close all connections in a node.js http server
connection->socket needs to be destroyed for each.
For my sample code, I use ES6 observe method.
http://wiki.ecmascript.org/doku.php?id=harmony:observe#object.observe
http://wiki.ecmascript.org/doku.php?id=harmony:observe_api_usage
https://github.com/jdarling/Object.observe
var IO = {
terminate:
{
val: false
}
};
var trigger = function(obj)
{
obj.val = !obj.val;
};
var HTTPserver =
httpServer(require('path')
.join(__dirname, 'www'));
var webSocketServer;
HTTPserver
.on('listening', function()
{
console.log('HTTP listening:');
//---------------
var WebSocket = require('ws');
webSocketServer =
new WebSocket.Server(
{
server: HTTPserver
})
.on('connection',
function(ws)
{
console.log('client connected');
});
})
.on('close', function()
{
console.log('server closed'); // never happens
})
.on('error', function()
{
console.log('server error');
})
.on('connection', function(socket)
{
console.log('connection');
Object.observe(IO.terminate, function(changes)
{
console.log('now!2');
socket.destroy();
});
})
.listen(8000);
setTimeout(function()
{
console.log('now');
HTTPserver.close();
webSocketServer.close();
trigger(IO.terminate);
}, 15000);
Related
I have a two webservers both running https with the same certificates, I have a main shard that the user connects to example.com, they retrieve some data and try to connect to an ip address on the 2nd shard via websocket.
But no matter what I configure I get an Error 1006 on the client side when connecting to the 2nd shard. Firefox devtooling gives me multiple errors - ssl_error_bad_cert_domain, SSL_ERROR_RX_RECORD_TOO_LONG.
The certificates are issued and signed, I was wondering where I should go from here. Thanks :)
SHARD2
const options = {
key: './server.key',
cert: './server.cert'
};
var https = require('https').Server(options);
https.listen(443, function () {
// console.log('Https listening on *: 443');
});
let WebSocket = require('ws');
let socket = new WebSocket.Server({ server:https });
socket.on('connection', function (ws, req) {
ws.on('message', (msgRaw) =>{
});
ws.on('close', function(code, reason) {
});
ws.on('error', function(error) {
console.log(error);
ws.close();
});
});
CLIENT
function connect() {
"use strict";
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
alert('Your browser doesn\'t support WebSocket');
return;
}
wss = new WebSocket('wss://123.123.123.120/:443');
wss.onmessage = function(event) {
};
wss.onerror = function(event) {
console.log(`wss error: ${JSON.stringify(event)}`);
};
wss.onclose = function(event) {
};
}
Useful sys diagram?
I am using nodejs to run the server, there is no log file
This is my server.js
const https = require('https');
const fs = require('fs');
const ws = require('ws');
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
const wss = new ws.Server({noServer: true});
function accept(req, res) {
// all incoming requests must be websockets
if (!req.headers.upgrade || req.headers.upgrade.toLowerCase() != 'websocket') {
res.end();
return;
}
// can be Connection: keep-alive, Upgrade
if (!req.headers.connection.match(/\bupgrade\b/i)) {
res.end();
return;
}
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onConnect);
}
function onConnect(ws) {
ws.on('message', function (message) {
let name = message.match(/([\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]+)$/gu) || "Guest";
ws.send(`${name}!`);
//setTimeout(() => ws.close(1000, "Bye!"), 5000);
});
}
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
This is my code in react
componentDidMount() {
var connection = new WebSocket('wss://localhost:8000/');
connection.onopen = function(e) {
connection.send("add people");
};
connection.onmessage = function(event) {
// alert(`[message] Data received from server: ${event.data}`);
console.log("output ", event.data);
};
}
While I am trying to connect with web-socket with my jsx file its give me an error which is Firefox can’t establish a connection to the server at wss://localhost:8000/.
Your implementaion needs some changes. In the backend server, you forgot to call the onConnect function. So your ws.on method will never call.
Also, you imported the ws and create a WebSocket server wss, but you add some event listener on ws wrongly, you should add listener on your Websocket instance (wss):
// rest of the codes ...
const was = new ws.Server({noServer: true})
wss.on('connection`) {
// do something here ...
}
// rest of the codes ...
https.createServer(options, () => {
// do something here ...
})
There are some examples of how to create the WebSocket server along with the HTTP server on ws npm page.
So what I am trying is to establish a socket.io connection between an express server and a react client. Maybe also mentionable the client is hosted on netlify and the server on heroku.
The actual problem is the client seems to connect and receives the upgrade protocol to websocket messages with a HTTP 101. But nothing else happens afterwards. No "connection" or "connected" event is emitted. Maybe some one spots a mistake in the code or can guide me to the solution.
Server
/**
* App Configuration
*/
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server, {
cors: {
origin: process.env.CLIENT_URL,
methods: ["GET", "POST"],
credentials: true
}
});
/**
* Socket IO
*/
io.on("connection", (socket: any) => {
console.log("Client Connected via Socket");
// Join a conversation
const { deviceId } = socket.handshake.query;
socket.join(deviceId);
// Leave the room if the user closes the socket
socket.on("disconnect", () => {
socket.leave(deviceId);
});
});
/**
* Server Activation
*/
app.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
});
Client
const socketRef = useRef();
useEffect(() => {
// Creates a WebSocket connection
socketRef.current = io(process.env.REACT_APP_API, {
transports: ['websocket'],
query: { deviceId: 'test-id' }
});
socketRef.current.on('connect', () => {
console.log("connected");
});
// Listens for incoming messages
socketRef.current.on("message", (message) => {
console.log(message);
});
// Destroys the socket reference
// when the connection is closed
return () => {
socketRef.current.disconnect();
};
}, []);
Edit:
Adding an image of the recurring http message about the websocket upgrade.
HTTP Message
Change Server activation line to below
server.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
})
I think what I need to do is reset Socket.io entirely after each test using socket.io.
Any ideas? Here's what I'm doing:
I have a test using Socket.IO's Client library, an angular service (github.com/chrisenytc/ng-socket), requireJS, and a local test server. When using karma's watch feature, it runs fine the first time, but fails subsequent attempts (event listeners aren't triggered, debug logging shows an 'xhr poll error').
the simple version of the test is (full version):
define(['services/serviceModule', 'angular-mocks'], function() {
describe('ILC Server Services', function() {
var socket;
beforeEach(module('ignisLibriColloqui.services', function(Config, $socketProvider) {
$socketProvider.setUrl(Config.ilcTestServerUrl);
Config.ilcServerUrl = Config.ilcTestServerUrl;
url = Config.ilcTestServerUrl;
}));
beforeEach(inject(function(ILCServerService, $socket) {
ilcServerService = ILCServerService;
socket = $socket;
}));
it('expects emit(\'ping\') to trigger on(\'pong\')', function(done) {
socket.emit('ping',{})
socket.on('pong',function(data) {
done();
});
});
});
});
and the simple server is (full version)
var httpPort = 10999;
var socketPort = 5001;
var restify = require('restify');
var socketio = require('socket.io')(socketPort);
var fs = require('fs');
var server = restify.createServer({
name: 'ilcServer Mock'
});
var io = socketio.listen(server);
server.get(/.*/, restify.serveStatic({
'directory': __dirname,
'default': './app/index.html',
'maxAge': 0
}));
io.sockets.on('connection', function(socket) {
var socketId = socket.id;
console.log('user connected');
socket.on('ping', function(data) {
console.log('ping');
socket.emit('pong', data);
});
socket.on('disconnect',function() {
console.log('disconnect');
socket.disconnect();
});
});
server.listen(httpPort, function() {
console.log('restify server listening at %s', server.url, 'socket port:', socketPort);
});
Edit
After carefully exploring the connections using the logging described by the Socket.io docs it has become clear to me that disconnecting the client is not enough. The client logs the "pong" events without firing the socket.on('pong',event), even when using an afterEach to cause socket.disconnect() and socket.io.connect(function(){done()}) to trigger, the new calls to socket.emit are not triggered.
I'm using the code below to test websockets on my browser:
this.webSocket = new WebSocket("ws://echo.websocket.org");
this.webSocket.onopen = function(evt) {
cc.log("Send Text WS was opened.");
};
this.webSocket.onmessage = function(evt) {
this.socketSendTextTimes++;
var textStr = "response text msg: " + evt.data + this.socketSendTextTimes;
cc.log(textStr);
};
The code works well, but if I connect to my own server running the code below:
var http = require('http');
var io = require('socket.io');
var server = http.createServer(function(req, res) {
// Send HTML headers and message
res.writeHead(200,{ 'Content-Type': 'text/html' });
res.end('<h1>Hello!</h1>');
});
var socket = io.listen(server);
socket.set('destroy upgrade', false);
socket.on('connection', function(client) {
client.on('message', function(event) {
console.log('Received message from client!', event);
});
client.on('disconnect', function() {
console.log('Server has disconnected');
});
});
server.listen(8080);
console.log('start to listen');
My browser displays:
hello!
But the listening socket does not do anything. How can I connect to the Socket.IO server using websockets?
Socket.IO uses alternate transport methods than the native websocket, even when emulating websockets themselves. You will need the client library to connect to Socket.IO sockets.