I'm new to WebSockets. I read a lot of info on the subject and i'm trying to build a simple server just to handle the handshake part, but still can't get my server to work properly. The client sends the request, the server sends a response back to the client, but it won't fire the onopen event for the WebSocket. But if I close the server, the websocket object fires it's onclose event.
The request I get from chrome is:
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 192.168.0.164:3215
Origin: http://lalala
Sec-WebSocket-Key: MyUY7duPdE1WbGXPOslYzw==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
The response I send back:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 4IVZgO4OosW/b7upp7Qbh2q6a4I=
The code i'm using in the server:
static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Parse("192.168.0.164"), 3215);
listener.Start();
Console.WriteLine(">> Started.");
var client = listener.AcceptTcpClient();
Console.WriteLine(">> Accepted.");
while (true)
{
try
{
var stream = client.GetStream();
var bytes = new byte[client.ReceiveBufferSize];
stream.Read(bytes, 0, client.ReceiveBufferSize);
var data = Encoding.ASCII.GetString(bytes);
Console.WriteLine(data.Remove(data.IndexOf("\0\0\0")));
var code = data.Remove(0, data.IndexOf("Sec-WebSocket-Key:") + 19);
code = code.Remove(code.IndexOf("==") + 2);
var response = string.Format(#"HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: " + GetServerResponseKey(code));
Console.WriteLine(response);
var encodedResponse = Encoding.UTF8.GetBytes(response);
stream.Write(encodedResponse, 0, encodedResponse.Length);
}
catch (IOException)
{
Console.WriteLine(">> Client Disconnected.");
Console.ReadKey();
return;
}
}
}
private static string GetServerResponseKey(string key)
{
var keyForHash = String.Concat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
var encoding = new UTF8Encoding();
var temp = encoding.GetBytes(keyForHash);
var hashProvider = new SHA1CryptoServiceProvider();
var keyForBase64 = hashProvider.ComputeHash(temp);
return Convert.ToBase64String(keyForBase64);
}
And the client script:
<script type="text/javascript">
var socket;
function connect()
{
socket = new WebSocket('ws://192.168.0.164:3215');
setTimeout(bindEvents, 1000);
setReadyState();
}
function bindEvents() {
socket.onopen = function() {
alert('handshake successfully established. May send data now...');
setReadyState();
};
socket.onclose = function() {
alert('connection closed');
};
}
function setReadyState() {
console.log('ws.readyState: ' + socket.readyState);
}
connect();
</script>
Some more questions:
1-Is there a way that I can find out which protocol my browser uses?
2-Which protocol Chrome 21 uses?
Your response needs to follow the rules for HTTP request/responses and have a carriage return + line feed between each header and a pair at the end. Instead of using new lines in the response I would escape encode them:
"header1\r\nheader2\r\nheader3\r\n\r\n"
The "Sec-WebSocket-Version: 13" header indicates that the browser is using version 13 of the protocol which is IETF 6455.
Related
My goal is when I open a new browser(client), the message sent from the server in the previous client gets updated as well.
Currently,
The clients send messages to the server, the server stores them in localStorage as an array and should send it back to all the clients. All clients should get the same array of messages. It works like ajax call.
As of right now, when I open the first browser, the message is sent to the server and received in the client successfully, and then I open the second one(it works) but the message is not updated in the first browser. PS this acts like a forum, when somebody posts a messages to server, all users should be able to see it.
Here's my code for server:
<html>
<head>
<!-- This is the websocket SERVER -->
<script src="http://localhost:5000/socket.io/socket.io.js"></script>
</head>
<body>
<div id="msg"></div>
<script>
// connect to WEBSOCKET server
var socket = io.connect('http://localhost:5000',{'forceNew':true} );
// Fire an event (that the server will handle
socket.emit('myEvent', 'Hello Message from the client');
// Attach event handler for event fired by server
socket.on('server', function(data) {
var elem = document.getElementById('msg');
console.log(data);
elem.innerHTML += "<br>" + data; // append data that we got back
});
</script>
</body>
</html>
Here's for client:
//---------------------------------------------------------------
// The purpose is to introduce you to websockets
// This is a SERVER that is SEPARATE from the http server.
//
// Your webpage (in this case the index.html in this directory)
// will be SERVED by the http server. THEN, it will connect to the
// websocket server. Then - they will talk to each other!
//
// Note that in regular http - the server cannot initiate a conversation
// Here, the websocket server sends a message to the client browser.
//
// This example has THREE parts
// 1) The http server code (which is same as what we did earlier)
// 2) This code - this is the web socket server
// It prints what it got from client. It also sends a message to the
// client after every 1 second.
// 3) The html or client code. Note how it connects to the websocket
// and how it sends and receives messages
//
// To RUN THIS EXAMPLE
// First, run node httpServer.js on one terminal
// Next, run node 1_ws.js on another terminal
// Next, type localhost:4000/index.html on some browser
//
//---------------------------------------------------------------
var items=[];
var io = require('socket.io').listen(5000);
if (typeof localStorage === "undefined" || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./scratch');
}
io.sockets.on('connection', function(socket) {
socket.on('myEvent', function(content) {
//i need to store the content
items.push(content);
localStorage.setItem("list",JSON.stringify(items));
socket.emit('server', JSON.parse(localStorage.getItem("list")));
});
});
I'm running on the local server:( you can ignore the local server if you want, the above code can function on their own)
//---------------------------------------------------------------
// The purpose is to serve a file!
//---------------------------------------------------------------
var util = require('util');
var path = require('path');
var http = require('http');
var fs = require('fs');
var server = http.createServer();
// attach handler
server.on('request', function (req,res) {
var file = path.normalize('.' + req.url);
fs.exists(file, function(exists) {
if (exists) {
var rs = fs.createReadStream(file);
rs.on('error', function() {
res.writeHead(500); // error status
res.end('Internal Server Error');
});
res.writeHead(200); // ok status
// PIPE the read stream with the RESPONSE stream
rs.pipe(res);
}
else {
res.writeHead(404); // error status
res.end('NOT FOUND');
}
});
}); // end server on handler
server.listen(4000);
console.log("start");
You are sending response to only client who sent message to sever only,
To send to all clients which are connected you must use this,
io.emit('server', JSON.parse(localStorage.getItem("list")));
Visit this answer for all
Responses
I am trying to send sensor data to artik cloud via node.js. (using web socket and serial port). But its sending null. Anyone knows the reason? I just copied the code from tutorial so there is no syntax error.
var webSocketUrl = "wss://api.artik.cloud/v1.1/websocket?ack=true";
var device_id = "####";
var device_token = "#####";
var isWebSocketReady = false;
var ws = null;
var serialport = require("serialport");
var portName = 'COM5';
var sp= new serialport.SerialPort(portName, {
baudRate: 9600,
parser: serialport.parsers.readline("\r\n")
});
var WebSocket = require('ws');
/**
* Gets the current time in millis
*/
function getTimeMillis(){
return parseInt(Date.now().toString());
}
/**
* Create a /websocket bi-directional connection
*/
function start() {
//Create the websocket connection
isWebSocketReady = false;
ws = new WebSocket(webSocketUrl);
ws.on('open', function() {
console.log("Websocket connection is open ....");
register();
});
ws.on('message', function(data, flags) {
console.log("Received message: " + data + '\n');
});
ws.on('close', function() {
console.log("Websocket connection is closed ....");
});
}
/**
* Sends a register message to the websocket and starts the message flooder
*/
function register(){
console.log("Registering device on the websocket connection");
try{
var registerMessage = '{"type":"register", "sdid":"'+device_id+'", "Authorization":"bearer '+device_token+'", "cid":"'+getTimeMillis()+'"}';
console.log('Sending register message ' + registerMessage + '\n');
ws.send(registerMessage, {mask: true});
isWebSocketReady = true;
}
catch (e) {
console.error('Failed to register messages. Error in registering message: ' + e.toString());
}
}
/**
* Send one message to ARTIK Cloud
*/
function sendData(temperature){
try{
// ts = ', "ts": '+getTimeMillis();
var data = {
"temp": temperature
};
var payload = '{"sdid":"'+device_id+'", "data": '+JSON.stringify(data)+', "cid":"'+getTimeMillis()+'"}';
console.log('Sending payload ' + payload);
ws.send(payload, {mask: true});
} catch (e) {
console.error('Error in sending a message: ' + e.toString());
}
}
/**
* All start here
*/
start(); // create websocket connection
sp.on("open", function () {
sp.on('data', function(data) {
if (!isWebSocketReady){
console.log("WebSocket is not ready. Skip sending data to ARTIK Cloud (data:" + data +")");
return;
}
console.log("Serial port received data:" + data);
//var parsedStrs = data.split(",");
var temperature = parseInt(data);
sendData(temperature);
});
});
If you reference our First IoT Sample:
https://developer.artik.cloud/documentation/tutorials/your-first-iot-device.html
The node.js sample sends the value from the temperature sensor. As a dependency it requires a connected Arduino, Raspberry Pi, and a DHT temperature sensor located at the right pin. If you are seeing null "before" sending the data to ARTIK Cloud, you are not getting any value from the sensor.
In particular, output and print to console the "temperature" value from the following function in case of any parsing errors:
function sendData(temperature) //...
Email us at developer#artik.cloud if you need additional information.
Thanks!
In this line:
var temperature = parseInt(data);
If you're getting empty or non numeric data (you can verify this in the previous line where you're logging the variable's content), then temperature will be NaN (not a number). Then, when you build the JSON payload for Artik Cloud, you'll end up with something like:
{
"sdid": "cbd3f844967d464da3c4f4989f80f86c",
"data": {
"temp":null
},
"cid":"1495817841624"
}
Because the JSON.stringify of:
{"temp":NaN}
would be translated to:
{"temp":null}
I need to convert a csv file to json format and send it to a client requesting to ws server in nodejs ,
the file will be updated so many times so i need to send updated data to client
i am able to send data once it is loaded completely(like when app is started it sends all data in file to client) but when i update data in the file the updated data is being printed out on console but it is not being sent to client is their any thing wrong in my code
my node.js code:
var ts = require('tail-stream');
var Converter = require("csvtojson").Converter;
var converter = new Converter({constructResult:false}); //for big csv data
var WebSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
// process HTTP request. Since we're writing just WebSockets server
// we don't have to implement anything.
response.write('hello');
console.log('in http server \n');
});
server.listen(1337, function() { });
// create the server
wsServer = new WebSocketServer({
httpServer: server
});
// WebSocket server
wsServer.on('request', function(request) {
var connection = request.accept(null, request.origin);
console.log('wsserver');
connection.send('ws server');
converter.on("record_parsed", function (jsonObj) {
console.log(jsonObj); //here is your result json object
connection.send(jsonObj);
});
var tstream = ts.createReadStream('log.csv', {
beginAt: 0,
onMove: 'follow',
detectTruncate: false,
onTruncate: 'end',
endOnError: false
});
tstream.pipe(converter);
});
Right now you are creating a new read stream and adding a listener to the converter on every new connection, that will cause trouble once you have more than one client (same event emitted multiple times, etc..). Instead of that you should keep just one reader and notify all open connections when there's a new record.
Also notice that the library you are using only accepts UTF-8 strings or binary type messages, row objects sent the way you're sending them now will be received as a "[object Object]" string after toString() is called on them. You should probably send just send the row string or use JSON.stringify / JSON.parse.
Try this:
var http = require("http");
var tailStream = require("tail-stream");
var Converter = require("csvtojson").Converter;
var WebSocketServer = require("websocket").server;
var server = http.createServer();
var wsServer = new WebSocketServer({ httpServer: server });
var converter = new Converter({constructResult:false});
var logStream = tailStream.createReadStream("log.csv", { detectTruncate : false });
var connections = [];
server.listen(1337);
logStream.pipe(converter);
//----------------------------------------------------
converter.on("record_parsed", function (jsonObj) {
connections.forEach(function(connection){
connection.send(JSON.stringify(jsonObj));
});
});
//----------------------------------------------------
wsServer.on("request", function(request) {
var connection = request.accept(null, request.origin);
connection.on("close", function() {
connections.splice(connections.indexOf(connection), 1);
});
connections.push(connection);
});
The code above works, tested like this on the client side:
var socket = new WebSocket('ws://localhost:1337/');
socket.onmessage = function (event) {
console.log(JSON.parse(event.data));
}
Note: this doesn't send the whole content of the file at the beginning, just the updates, but you can easily achieve this storing the records and sending them on new connections.
The situation
I have a scanner that has been working with a compiled application which I don't have the source. It still works and can be tested to make sure the scanner is working. I need to convert the data entry process to my web based system.
So I'm building a chrome app that read serial port information incoming from the com port. I first tried setting it up with a com port emulator and a virtual null modem. This allowed me to test the connection and the receive data. I can't find why I am receiving only 1 byte.
The problem
When I connected to the actual scanner, I am able to connect without any issue, but when I receive the dataArray it's only one byte long. After reveiving the first data, I'm unable to receive any other data until I restart the connection.
The Code
var connectionId = -1;
var e_dtr, e_rts, e_dcd, e_cts, e_ri, e_dsr;
var dtr, rts;
chrome.app.runtime.onLaunched.addListener(function(launchData) {
chrome.serial.getDevices(function(objs,arg2){
chrome.serial.connect(objs[0].path, {ctsFlowControl:true}, onConnect)
});
});
chrome.serial.onReceive.addListener(function(info){
chrome.serial.getInfo(info.connectionId, output);
var uint8View = new Uint8Array(info.data);
var value = String.fromCharCode.apply(null, uint8View);
console.log(value);
});
chrome.serial.onReceiveError.addListener(function(info){
var uint8View = new Uint8Array(info.data);
var value = String.fromCharCode.apply(null, uint8View);
console.log(value);
});
function readSignals() {
chrome.serial.getControlSignals(connectionId,onGetControlSignals);
}
function onSetControlSignals(result) {
console.log("onSetControlSignals: " + result);
};
function changeSignals() {
chrome.serial.setControlSignals(connectionId, { dtr: dtr, rts: rts }, onSetControlSignals);
}
function onGetControlSignals(signals) {
console.log(signals);
}
function onConnect(connectionInfo) {
console.log(connectionInfo);
if (!connectionInfo) {
console.log('Could not open');
return;
}
connectionId = connectionInfo.connectionId;
console.log('Connected');
dtr = false;
rts = false;
changeSignals();
setInterval(readSignals, 1000);
};
I'm new to node.js/socket.io so I don't really know what I'm doing, but I've got this for my server side:
var app = require('net')
, fs = require('fs')
var server = app.createServer(function (socket) {
socket.write("Echo server\r\n");
socket.pipe(socket);
socket.on('data', function(data) {
console.log(data);
});
});
var io = require('socket.io').listen(server)
server.listen(81);
So the tcp server works when I use nc localhost 81 and send it data. However, I don't know how to connect and send data to the tcp server on a website from the server side using script tags. So what would the client side be to connect to this tcp server and send data to it?
Thanks!
Newly added code:
Server:
var app = require('net')
, fs = require('fs')
var sockets_list = [];
var server = app.createServer(function (socket) {
sockets_list.push(socket);
socket.write("Echo server\r\n");
socket.on('data', function(data) {
console.log(data);
for (var i = 0; i < sockets_list.length; i++) {
sockets_list[i].write(data);
}
});
socket.on('end', function() {
var i = sockets_list.indexOf(socket);
sockets_list.splice(i, 1);
});
});
server.listen(81);
Client:
<script type="text/javascript" src="http://localhost:82/socket.io/socket.io.js"> </script>
<script>
var socket = io.connect('http://localhost:81');
socket.on('connect', function () {
socket.send('hi');
});
socket.send('hi1');
socket.emit('hi2');
alert('here');
</script>
What happened:
I have a webpage loading which takes one socket and a nc localhost 81 which takes up another socket. So the nc displays everything the web page sends. After I connect the webpage, the alert('here'); is executed and the nc shows the http request, however, nothing else is sent to the tcp server, and the webpage is in constant refresh status. Why does the webpage never fully load, the 'hi' messages never get sent, and what about the http request to a tcp server? Why doesn't my tcp client fail with my tcp server?
Socket.io's how to use page shows you exactly how to do that.
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost/');
socket.on('connect', function () {
socket.send('hi');
socket.on('message', function (msg) {
// my msg
});
});
</script>