Am now using websocket in HTML5 to build my web app.
Because my previous work was based on TCP and I used CRC16 algorithm to wrap the content that will transfer to server side;
Construct message with CRC16 code below:
public static byte[] ConstructMessageWithCRC(string message)
{
//Message with a |
var messageToConstruct = message + "|";
//calculate CRC value
var crcCode = CRC16.CalculateCrc16(messageToConstruct);
var crcCodeShort = ushort.Parse(crcCode);
//CRC high value
var crcHigh = byte.Parse((crcCodeShort / 256).ToString());
//CRC low value
var crcLow = byte.Parse((crcCodeShort % 256).ToString());
var messageBytes = Encoding.Default.GetBytes(messageToConstruct);
var messageLength = messageBytes.Length;
var messageBytesWithCRC = new byte[messageLength + 2];
Array.Copy(messageBytes, 0, messageBytesWithCRC, 0, messageLength);
//append crc value to the message
messageBytesWithCRC[messageLength] = crcHigh;
messageBytesWithCRC[messageLength + 1] = crcLow;
return messageBytesWithCRC;
}
After server side received the data, it will calculate the content via CRC16 algorithm also to ensure that the data is correct.
Check CRC code below:
public static bool CheckMessageCRC(byte[] message, out string messageReceived)
{
//message length that received
var messageLength = message.Length;
//message received without crc value
var messageReceivedStrBytes = new byte[messageLength - 2];
Array.Copy(message, 0, messageReceivedStrBytes, 0, messageLength - 2);
//crc value received
var messageReceivedCrcBytes = new byte[2];
Array.Copy(message, messageLength - 2, messageReceivedCrcBytes, 0, 2);
//get the received message with correct decoding
var messageCalculatedString = Encoding.Default.GetString(messageReceivedStrBytes);
messageReceived = messageCalculatedString;
//get the received crc value
var currentCRC = byte.Parse(messageReceivedCrcBytes[0].ToString()) * 256 + byte.Parse(messageReceivedCrcBytes[1].ToString());
//crc value recalculate
var result = ushort.Parse(CRC16.CalculateCrc16(messageCalculatedString));
//comparison
if (currentCRC == result)
return true;
return false;
}
From above code, you can see what I did.
But in some articles that using websocket: Working with Websockets, it will use below code to handle the message directly:
//When the server is sending data to this socket, this method is called
ws.onmessage = function (evt) {
//Received data is a string; We parse it to a JSON object using jQuery
//http://api.jquery.com/jQuery.parseJSON/
var jsonObject = $.parseJSON(evt.data);
//Do something with the JSON object
};
//Creates an object that will be sent to the server
var myObject = {
Property: "Value",
AnotherProperty: "AnotherValue"
};
//We need to stringify it through JSON before sending it to the server
ws.send(JSON.stringify(myJsonObject));
It will directly send the data out without any check mechanism with the data. So if the data is intercepted by others and we won't know the data has been changed. Also, because of poor network, the data will arrival out of order, then below code won't work correctly, maybe we wanted data as ABC, but we got BCA:
var jsonObject = $.parseJSON(evt.data);
So for evt.data, just wonder how should we check the data transfer complete, data order correct, data content correct and so on.
I have googled a lot and didn't see any info regarding this, just want use this question to declare the right way to transfer data via websocket, thx.
EDIT:
My friend send me this: https://www.rfc-editor.org/rfc/rfc6455, in section 5.2
I think the protocol seems do this work already. Need more of your discusses on it. thx
Related
Trying to convert JSON data into int in order to perform calculations, multiply by numbers or percentages (or whichever method is best recommended)
Tried performing calculation on the object (using addition for example), but it only added numbers on to the end of the resulting string. I have seen suggestions on using JSON parse (reviver) but can't seem to get my head round getting the desired data when it is only one specific part of the JSON data required rather than multiple items of data from the JSON link.
var xmlhttp = new XMLHttpRequest();
var url = "https://api.coindesk.com/v1/bpi/currentprice.json";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
function parseJson(json) {
var gbpValue = "1 BTC equals to £" + json["bpi"]["GBP"]["rate"];
document.getElementById("data").innerHTML =
gbpValue;
As mentioned, have tried performing calculations on the result but it only adds numbers to the end of the string. Thanks for any advice or help.
What I can see in your code is that you are adding your json variable with a string which would always result in string concatenation in below line:
var gbpValue = "1 BTC equals to £" + json["bpi"]["GBP"]["rate"];
First check your json object if it a number or string.
You could use the Number() or parseInt() functions to convert a string to number.
Example:
var num=Number("23");
or
var num=parseInt("23");
Hope it helps. :)
I downloaded as3crypto and have been trying to integrate it into my project.
I'm trying to do a simple test to match the decrypt results I'm getting in the demo - http://crypto.hurlant.com/demo/ but I'm getting the above error.
I'm working on the Secret Key tab. I'm using AES, CBC, PKCS5 and prepending the IV.
Both the Key and Cipher text is set to HEX.
I first did an Encrypt and then copy the key and the cipher text to my function to test the decrypt to see if it match. I copied the code direct from the SecretTab.mxml and modified it a little to take the hard coded values.
I wrote a small program in C# to decrypt it using the same values and it works fine.
I verified the key and cipher text many times and it is correct.
public static function decrypt2():void
{
// 2: get a key
var k:String = Hex.fromString("e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c");
var kdata:ByteArray = Hex.toArray(k);
//trace(String.fromCharCode(kdata[0]));
// 3: get an output
var txt:String = Hex.fromString("691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a");
var data:ByteArray = Hex.toArray(txt);
// 1: get an algorithm..
var name:String = "simple-aes-cbc";
var pad:IPad = new PKCS5; //:new NullPad;
//var pad:IPad = new NullPad();
var mode:ICipher = Crypto.getCipher(name, kdata, pad);
pad.setBlockSize(mode.getBlockSize());
// if an IV is there, set it.
if (mode is IVMode) {
trace("mode is IVMode");
var ivmode:IVMode = mode as IVMode;
//ivmode.IV = Hex.toArray(iv.text);
}
mode.decrypt(data);
trace(Hex.fromArray(data));
}
You need to explicitly set both byte arrays, the data and the IV, before decrypting. I don't think as3crypto will break it out for you, even if the simple flag is used on the name.
I don't know what your example states, however the error indicates that the byte array is not correct. Example with the IV explicitly set.
var cipher:ICipher = Crypto.getCipher("aes256-cbc", keydata);;
var dataBA:ByteArray = Hex.toArray(Hex.fromString(data));
var data:ByteArray = Hex.toArray(Hex.fromString("some data"));
(cipher as IVMode).IV = Hex.toArray(Hex.fromString("some IV"));
cipher.decrypt(data);
I found my typos. I had to change the following lines
var k:String = Hex.fromString("e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c");
to
var k:String = "e5693983c5c21e0f6191eb025d12803d6d17c5359994bf435b964cd0c107fc2c";
v
and
var txt:String = Hex.fromString("691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a");
to
var txt:String = "691682969f1946a1465ccfe19d429ace4188ee254425caa7fa84db5b1fba44a77f1dedfba7a1ffe516cb0646638e28f8ae6422b3cd63d380b21f8b8dcfbe067a";
and
trace(Hex.fromArray(data));
to
trace(Hex.toString(Hex.fromArray(data)));
Trying to store indexReferences per user, I've found that when I store one (or more) directly in a map, it works fine. However, when stored in an object (or a custom realtime object), the realtime API generates Circular JSON errors.
This works fine:
function doRegisterTypes() {
gapi.drive.realtime.custom.registerType(MyCustomType, "MyCustomType");
MyCustomType.prototype.startPoints = gapi.drive.realtime.custom.collaborativeField('startPoints');
MyCustomType.prototype.endPoints = gapi.drive.realtime.custom.collaborativeField('endPoints');
MyCustomType.prototype.elements = gapi.drive.realtime.custom.collaborativeField('elements');
gapi.drive.realtime.custom.setInitializer(MyCustomType, initializeMyCustomType);
}
function initializeMyCustomType() {
var model = gapi.drive.realtime.custom.getModel(this);
this.startPoints = model.createMap();
this.endPoints = model.createMap();
this.elements = model.createList();
}
function initializeModel(model) {
var o = model.create("MyCustomType");
o.elements.pushAll(["foo", "bar"]);
var startIndex = o.elements.registerReference(0, false);
var endIndex = o.elements.registerReference(0, false);
o.startPoints.set(UserId, startIndex);
o.endPoints.set(UserId, endIndex);
model.getRoot().set("MyCustomObject", o);
}
But this doesn't, failing with circular JSON errors when storing the range object in the map:
function doRegisterTypes() {
gapi.drive.realtime.custom.registerType(MyCustomType, "MyCustomType");
MyCustomType.prototype.ranges = gapi.drive.realtime.custom.collaborativeField('ranges');
MyCustomType.prototype.elements = gapi.drive.realtime.custom.collaborativeField('elements');
gapi.drive.realtime.custom.setInitializer(MyCustomType, initializeMyCustomType);
}
function initializeMyCustomType() {
var model = gapi.drive.realtime.custom.getModel(this);
this.ranges = model.createMap();
this.elements = model.createList();
}
function initializeModel(model) {
var o = model.create("MyCustomType");
o.elements.pushAll(["foo", "bar"]);
var startIndex = o.elements.registerReference(0, false);
var endIndex = o.elements.registerReference(0, false);
// FAILS:
o.ranges.set(UserId, {start:startIndex, end:endIndex});
model.getRoot().set("MyCustomObject", o);
}
I should stress the error appears for a single indexReference, and whether the object is a specific custom type or not, and also WHENEVER the value is set into the map: while initializing the model or later. It's as if the indexReferences cannot be stored at anything but a "top level", though that makes little sense.
Feature? Bug? User stoopidity?
You can't store CollaborativeObjects within arbitrary json within a CollaborativeObject. CollaborativeObjects (including IndexReferences) must be stored directly in other CollaborativeObjects.
(There are a few reasons for this, mostly having to do with how the collaboration works.. json objects are treated as arbitrary blobs whose contents are ignored.)
In this case, you could create a Range custom object type that has a start and end CollaborativeField. (Or a CollaborativeList with 2 elements..)
i need some help for extract data from response socket. Precisely the output of the Trace() in the onResponse function.
var socket:Socket = new Socket();
var codehtml:String = "test";
function onConnect(e:Event):void {
socket.writeUTFBytes("GET / HTTP/1.1\n");
socket.writeUTFBytes("Host: 192.168.1.2\n");
socket.writeUTFBytes("\n");
}
function onResponse(e:ProgressEvent):void {
if (socket.bytesAvailable>0) {
var tmpcode:String = socket.readUTFBytes(socket.bytesAvailable);
trace(tmpcode);
}
}
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecError);
socket.connect("www.google.fr", 80);
The problem with sockets is that the information can be too big for a single packet. So you can receive half of the message, and then receive the rest of it.
Commonly this is handled with a 'EOF' (end of file) delimiter - a single special character that will match the ending of the message. For example you can receive those two packets:
<start><body>some text
</body></start>$
This should be a regular xml data, but you won't be able to get it from the first packet only. So you need to wait for everything to come. But how can you know that it happened? By waiting for this special $ sign.
This is needed because sometimes the info is not enough to be casted to something readable. Here's a simple solution:
const EOL_DELIMITER:String = '$';
var _buffer:String = "";
_socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
function onSocketData(event:ProgressEvent):void
{
var data:String = _socket.readUTFBytes(_socket.bytesAvailable);
_buffer += data; // add everything to a buffer that will store all info until now
var msg:String;
var index:int;
// this will search for the delimeter
// as long as there is one - there is a message
// it's in a loop as there might be several messages in one packet
// if there is no message, this loop will fail and only the buffer will get filled
while((index = _buffer.indexOf(EOL_DELIMITER)) > -1)
{
msg = _buffer.substring(0, index);
_buffer = _buffer.substring(index + 1); // clear the message from the buffer
// new message has arrived -> msg var
}
}
Hope that helps!
Let me clarify, this is kind of complicated.
I'm implementing a form to insert data in the database.
I have two websockets connections in the same client side, connecting on the same nodejs server.
One connection is triggered after the user inserts a name on the "name" textfield of the form. Sends the data to the server, server checks the database if the name already exists and responces back "This already exists. Mayde you are inserting something that is already there".
The other connection is triggered if all the fields of the form are not blank and sends the data to server to insert them in the database.
I thought it was a good idea to distinguish on server-side ,the different connections using arrays. If the first element of the array is "name" call the checkName function, or if it is "insert" , call the insertInDB function.
I created two small testing files. They do not work. Connections are open and the client sends the data. I get no errors inte server nor the client side. But server never responces. I dont get the expected numbers, back in the client side. I dont think this is the right anyway. This is complecated, I hope the code helps you.
Is it possible, what I am trying to do? Any hints or alternatives?
Thanks
the code....
server-side
function WebSocketTest1(){
var a=1;
var b=2;
var c = [a,b];
var so = new WebSocket("ws://localhost:1337");
so.onerror=function (evt)
{message.textContent = evt;}
so.onopen = function(){
message.textContent = "opened";
so.send(c);
message.textContent = "sended";
}
so.onmessage = function (evt) {
var received_msg = evt.data;
document.getElementById("message").innerHTML=received_msg;
}
}
function WebSocketTest2(){
var d=3;
var e=4;
var f = [d,e];
var sa = new WebSocket("ws://localhost:1337");
sa.onerror=function (evt)
{message2.textContent = evt;}
sa.onopen = function(){
message2.textContent = "opened";
sa.send(f);
message2.textContent = "sended";
}
sa.onmessage = function (evt) {
var received_msg = evt.data;
document.getElementById("message2").innerHTML=received_msg;
}
}
</script>
</head>
<input type="button" value="one" onClick="WebSocketTest1()"><br/>
<input type="button" value="two" onClick="WebSocketTest2()"><br/>
<body>
<div id="message"></div>
mesage2</br>
<div id="message2"></div>
</body>
</html>
on the server side I am listing the sessions, to communicate only with a specific session, code found here
and the server side (snippets)
var connections = {};
var connectionIDCounter = 0;
var connection = request.accept(null, request.origin);
// Store a reference to the connection using an incrementing ID
connection.id = connectionIDCounter ++;
connections[connection.id] = connection;
console.log((new Date()) + ' Connection accepted.');
connection.on('message', function(message) {
var ja=message;
if(ja[0]==1)
{ja[1]=7;}
else if(ja[0]==3)
{ja[1]=8;}
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
delete connections[connection.id];
});
});
// Send a message to a connection by its connectionID
function sendToConnectionId(connectionID, data) {
var connection = connections[connectionID];
if (connection && connection.connected) {
connection.send(ja[1]);
}
I wonder why you need 2 connections.
Open one connection and send the payload as JSON.
e.g.
var ws = new WebSocket("ws://localhost:1336");
ws.send(JSON.stringify({ command: "checkname", params: "xxxx"; });
ws.send(JSON.stringify({ command: "submit", params: { ... });
At the server side, you just have to parse the payload and determine which command is executed.
I am just wondering why you need websocket. It seems that you need to validate user presence in the application. If user is not present then you need to insert in the database else throw error.
you can go through jquery post and jquery form validation
http://api.jquery.com/jQuery.post/