I am trying to make a demonstration for web socket communication for one of our new projects at work, and I've been trying to revise an old web socket server program I wrote quite a while ago.
It does a proper handshake and can send data to the client properly (which is all it REALLY needs to do), but the client data that comes back is in the special web socket communication protocol, and I am not that good with working with binary or hex or encryption algorithms.
I know from research that the text I'm receiving back contains a frame around it, and that it is sha1 encrypted, but my problem is that I have no idea how to read or remove this frame or unencrypt it.
Here is the full code of the web server so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Web;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Threading;
using System.Security.Cryptography;
namespace WebSocks
{
public class WebSockServer
{
/// <summary>
/// Port number to listen on
/// </summary>
private const int PortNumber = 8181;
/// <summary>
/// Socket which awaits connections
/// </summary>
private Socket ListenerSocket;
/// <summary>
/// Thread in which we await for incomming connections.
/// </summary>
private System.Threading.Thread _serverThread;
public delegate void ClientConnectedHandler (Socket Sock);
public delegate void ReceivedDataHandler(Socket Sock, string Message);
public event ClientConnectedHandler ClientConnected;
public event ReceivedDataHandler ReceivedData;
static WebSockServer() { }
/// <summary>
/// Starts thread with listening socket.
/// </summary>
public void Start()
{
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(Listen);
_serverThread = new System.Threading.Thread(ts);
_serverThread.Start();
}
/// <summary>
/// Stops listening for connections.
/// </summary>
public void End()
{
_serverThread.Abort();
ListenerSocket.Dispose();
}
public void Listen()
{
//Start listening
ListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint ep = new IPEndPoint(IPAddress.Parse("0.0.0.0"), PortNumber);
ListenerSocket.Bind(ep);
ListenerSocket.Listen(5);
while (true)
{
//New client
Socket client = ListenerSocket.Accept();
//Receiving clientHandshake
string clientHandshake = String.Empty;
byte[] buffer = null;
int readBytes = 0;
do
{
buffer = new byte[client.Available];
readBytes = client.Receive(buffer);
clientHandshake += Encoding.UTF8.GetString(buffer);
}
while (client.Available > 0);
//Last eight bytes are body of requets (we should include it in response)
byte[] secKey3 = buffer.Skip(readBytes - 8).Take(8).ToArray();
//Variables we can extract from clientHandshake
string clientOrigin = String.Empty;
string secKey1 = String.Empty;
string secKey2 = String.Empty;
string WebSocketVersion = String.Empty;
int WSV = 0;
string WebSocketKey = String.Empty;
//Extracting values from headers (key:value)
string[] clientHandshakeLines = Regex.Split(clientHandshake, Environment.NewLine);
foreach (string hline in clientHandshakeLines)
{
int valueStartIndex = hline.IndexOf(':') + 2;
if (valueStartIndex > 0)
{
if (hline.StartsWith("Origin"))
{
clientOrigin = hline.Substring(valueStartIndex, hline.Length - valueStartIndex);
}
else if (hline.StartsWith("Sec-WebSocket-Key2"))
{
secKey2 = hline.Substring(valueStartIndex, hline.Length - valueStartIndex);
}
else if (hline.StartsWith("Sec-WebSocket-Key1"))
{
secKey1 = hline.Substring(valueStartIndex, hline.Length - valueStartIndex);
}
if (hline.StartsWith("Sec-WebSocket-Version"))
{
WebSocketVersion = hline.Replace("Sec-WebSocket-Version: ", "");
WSV = Convert.ToInt32(WebSocketVersion);
}
if (hline.StartsWith("Sec-WebSocket-Key"))
{
WebSocketKey = hline.Replace("Sec-WebSocket-Key: ", "");
}
}
}
if (!String.IsNullOrEmpty(WebSocketVersion)) //WebSocketVersion 8 and up handshake check
{
//New WebSocketVersion number, included after Version 8
StringBuilder mResponse = new StringBuilder();
mResponse.AppendLine("HTTP/1.1 101 Switching Protocols");
mResponse.AppendLine("Upgrade: WebSocket");
mResponse.AppendLine("Connection: Upgrade");
mResponse.AppendLine(String.Format("Sec-WebSocket-Accept: {0}", ComputeWebSocketHandshakeSecurityHash09(WebSocketKey)) + Environment.NewLine);
byte[] HSText = Encoding.UTF8.GetBytes(mResponse.ToString());
client.Send(HSText, 0, HSText.Length, 0);
}
else
{
//This part is common for all websockets editions (v. 75 & v.76)
client.Send(Encoding.UTF8.GetBytes("HTTP/1.1 101 Web Socket Protocol Handshake" + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes("Upgrade: WebSocket" + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes("Connection: Upgrade" + Environment.NewLine));
if (String.IsNullOrEmpty(secKey1) && String.IsNullOrEmpty(secKey2)) //75 or less handshake check
{
client.Send(Encoding.UTF8.GetBytes(String.Format("WebSocket-Origin: {0}", clientOrigin) + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes("WebSocket-Location: ws://localhost:8181/websock" + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes(Environment.NewLine));
}
else //76 handshake check
{
//Keys present, this means 76 version is used. Writing Sec-* headers
client.Send(Encoding.UTF8.GetBytes(String.Format("Sec-WebSocket-Origin: {0}", clientOrigin) + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes("Sec-WebSocket-Location: ws://localhost:8181/websock" + Environment.NewLine));
client.Send(Encoding.UTF8.GetBytes(Environment.NewLine));
//Calculating response body
byte[] secret = CalculateSecurityBody(secKey1, secKey2, secKey3);
client.Send(secret);
}
}
if (ClientConnected != null)
{
ClientConnected(client);
}
Thread t = new Thread(new ParameterizedThreadStart(WaitForMessages));
t.Start(client);
}
}
private static void SendMessage(string Msg, Socket client, int WebSockVersion)
{
if (WebSockVersion >= 8)
{
bool IsFinal = true;
int OpCode = 1;
int? Mask = null;
byte[] payload = Encoding.UTF8.GetBytes(Msg);
int PayloadLength = payload.Length;
byte[] buffer = new byte[64]; // for working out the header
int offset = 0;
buffer[offset++] = (byte)((IsFinal ? 128 : 0) | ((int)OpCode & 15));
if (PayloadLength > ushort.MaxValue)
{ // write as a 64-bit length
buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | 127);
buffer[offset++] = 0;
buffer[offset++] = 0;
buffer[offset++] = 0;
buffer[offset++] = 0;
buffer[offset++] = (byte)(PayloadLength >> 24);
buffer[offset++] = (byte)(PayloadLength >> 16);
buffer[offset++] = (byte)(PayloadLength >> 8);
buffer[offset++] = (byte)(PayloadLength);
}
else if (PayloadLength > 125)
{ // write as a 16-bit length
buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | 126);
buffer[offset++] = (byte)(PayloadLength >> 8);
buffer[offset++] = (byte)(PayloadLength);
}
else
{ // write in the header
buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | PayloadLength);
}
if (Mask.HasValue)
{
int mask = Mask.Value;
buffer[offset++] = (byte)(mask >> 24);
buffer[offset++] = (byte)(mask >> 16);
buffer[offset++] = (byte)(mask >> 8);
buffer[offset++] = (byte)(mask);
}
// you might want to manually combine these into 1 packet
client.Send(buffer, 0, offset, SocketFlags.None);
client.Send(payload, 0, payload.Length, SocketFlags.None);
}
else
{
client.Send(new byte[] { 0x00 });
client.Send(Encoding.UTF8.GetBytes(Msg));
client.Send(new byte[] { 0xFF });
}
}
private void WaitForMessages(object client)
{
Socket sock = (Socket)client;
byte[] buffer = new byte[1024];
while (true)
{
sock.Receive(buffer);
ReceivedData(sock, Encoding.UTF8.GetString(buffer));
}
}
public byte[] CalculateSecurityBody(string secKey1, string secKey2, byte[] secKey3)
{
//Remove all symbols that are not numbers
string k1 = Regex.Replace(secKey1, "[^0-9]", String.Empty);
string k2 = Regex.Replace(secKey2, "[^0-9]", String.Empty);
//Convert received string to 64 bit integer.
Int64 intK1 = Int64.Parse(k1);
Int64 intK2 = Int64.Parse(k2);
//Dividing on number of spaces
int k1Spaces = secKey1.Count(c => c == ' ');
int k2Spaces = secKey2.Count(c => c == ' ');
int k1FinalNum = (int)(intK1 / k1Spaces);
int k2FinalNum = (int)(intK2 / k2Spaces);
//Getting byte parts
byte[] b1 = BitConverter.GetBytes(k1FinalNum).Reverse().ToArray();
byte[] b2 = BitConverter.GetBytes(k2FinalNum).Reverse().ToArray();
//byte[] b3 = Encoding.UTF8.GetBytes(secKey3);
byte[] b3 = secKey3;
//Concatenating everything into 1 byte array for hashing.
List<byte> bChallenge = new List<byte>();
bChallenge.AddRange(b1);
bChallenge.AddRange(b2);
bChallenge.AddRange(b3);
//Hash and return
byte[] hash = MD5.Create().ComputeHash(bChallenge.ToArray());
return hash;
}
public String ComputeWebSocketHandshakeSecurityHash09(String secWebSocketKey)
{
const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
String secWebSocketAccept = String.Empty;
// 1. Combine the request Sec-WebSocket-Key with magic key.
String ret = secWebSocketKey + MagicKEY;
// 2. Compute the SHA1 hash
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));
// 3. Base64 encode the hash
secWebSocketAccept = Convert.ToBase64String(sha1Hash);
return secWebSocketAccept;
}
}
}
I know its very crude, it doesn't clean up after itself, and it doesn't separate the different connections properly and hold them in a list or anything, this is purely for a demonstration project.
So the main section I need help with is the WaitForMessages function:
private void WaitForMessages(object client)
{
Socket sock = (Socket)client;
byte[] buffer = new byte[1024];
while (true)
{
sock.Receive(buffer);
//Remove Frame and decrypt here
ReceivedData(sock, Encoding.UTF8.GetString(buffer));
}
}
I really just want to drop some code in here that will work, if you point me to a "demonstration that is kind of like your code and you should be able to figure it out from this" I'm really not going to understand it, I can almost guarantee you. I'm an app developer, not an API developer, I just don't want to wait until Microsoft finally gets around to writing an API into .NET 6.0 or something for this feature.
Related
I've been working the last weeks with a tcp protocol to send packet from arduino to unity using this code:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPConnection : MonoBehaviour
{
public string IP_Seat = "192.168.137.161";
public int port = 34197;
#region private members
private TcpClient socketConnection;
private Thread clientReceiveThread;
public float a, b, c, vel;
public float test = 0.0f;
#endregion
// Use this for initialization
void Awake()
{
ConnectToTcpServer();
}
/// <summary>
/// Setup socket connection.
/// </summary>
private void ConnectToTcpServer()
{
try
{
clientReceiveThread = new Thread(new ThreadStart(ListenForData));
clientReceiveThread.IsBackground = true;
clientReceiveThread.Start();
}
catch (Exception e)
{
Debug.Log("On client connect exception " + e);
}
}
/// <summary>
/// Runs in background clientReceiveThread; Listens for incoming data.
/// </summary>
private void ListenForData()
{
var aold = 0.0f;
var bold = 0.0f;
var cold = 0.0f;
var velold = 0.0f;
try
{
socketConnection = new TcpClient(IP_Seat, port);
//cketConnection.ConnectAsync(IP_Seat, port); // non si connette
//socketConnection.Client.Blocking = false;
//socketConnection.Client.ConnectAsync(IP_Seat,port);
Byte[] bytes = new Byte[16];
while (socketConnection.Connected)
{
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream())
{
int length;
// Read incoming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
//Debug.Log("I'm receiving Data");
if (length == 16)
{
//Debug.Log("I'm receiving len 16 and I like it");
var incomingData = new byte[length];
var A = new Byte[4];
var B = new Byte[4];
var C = new Byte[4];
var VEL = new Byte[4];
Array.Copy(bytes, 0, incomingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incomingData);
Array.Copy(bytes, 0, A, 0, 4);
Array.Copy(bytes, 4, B, 0, 4);
Array.Copy(bytes, 8, C, 0, 4);
Array.Copy(bytes, 12, VEL, 0, 4);
a = BitConverter.ToSingle(A, 0) < 0 ? BitConverter.ToSingle(A, 0) : aold;
b = BitConverter.ToSingle(B, 0) < 0 ? BitConverter.ToSingle(B, 0) : bold;
c = BitConverter.ToSingle(C, 0) < 0 ? BitConverter.ToSingle(C, 0) : cold;
vel = BitConverter.ToSingle(VEL, 0); //< 0 ? BitConverter.ToSingle(C, 0) : 0;
//Debug.Log("server message received as: " + serverMessage +a +" "+b + " " + c + " " + vel);
aold = a;
bold = b;
cold = c;
velold = vel;
}
else {
//evitare che bilancia aspetti ack di tcp
}
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
}
and right now i'm having blocking issues: i'd like to use the async method for the TCP but the tcpClient.ConnectAsync but it returns a SocketEXception and I can't figure out why.
The arduino sends 4 float in 16 bytes packet and 98-99% of them arrive correctly, but the missing 1-2% causes the system to block and an undesirable behaviour ( since i'm programming a device I need no delay waiting for an ack or a packet)
How can I make this sokcet async?
EDIT:
Using NET 4.X: how can I use the connectASync(ip,port) method in this script?
As already said TCP is just an undefined stream of data you need to implement an according protocol for knowing when a message ends (is fully received) and when a new one starts.
Now in your case you seem to already know that you have exactly 16 bytes.
NetworkStream.Read however, does not necessarily wait until actually 16 bytes where received. If for some reason (delay in the network) at the moment it is called there are less bytes in the stream then it will receive only the amount that is available.
Now let's say your sender sends 3 packages รก 16 bytes (so 48 bytes).
It might happen that the first time you read only 8 bytes. From now on every following read call receives 16 bytes.
=> Result: You get two complete buffers, but with invalid data since you always started reading at the middle of a message.
Note the second parameter of Read
int offset -> The location in buffer to begin storing the data to.
what you want to do is wait until the buffer is actually full like
var receivedBytes = 0;
while (receivedBytes < bytes.Length)
{
receivedBytes += stream.Read(bytes, receivedBytes, bytes.Length - receivedBytes);
}
// Use bytes
Now this will fill exactly one buffer of 16 bytes before continuing since at the same time we increase the offset we also decrease the maximum amount of bytes to read.
And another note: you have a huge amount of redundant array creations, copies and BitConverter going on!
I would rather use
var bytes = new byte[16];
var floats = new float[4];
And then later on after receiving the bytes do
Buffer.BlockCopy(bytes, 0, floats, 0, 16);
This copies the bytes over into floats directly in the underlaying byte layer.
And then you can simply do
a = floats[0] < 0 ? floats[0] : aold;
b = floats[1] < 0 ? floats[1] : bold;
c = floats[2] < 0 ? floats[2] : cold;
v = floats[3];
Note: Typed on the phone but I hope the idea gets clear
I am trying to test a flash memory chip on an electronic device having USB comms. Using SerialPort (USB VCP).
I am sitting in a for loop scanning through the memory addresses in sequence with a small delay following each read. However I want to get rid of the delay and have this run as follows:
C# App sends byte command to i.e. read address 0 and return 32 bytes (address 0 to 31)
When C# app receives the 32 bytes then immediately send request for address 31 etc
repeat...
So how do I do it in this fast manner and not having to have a delay giving the serial port time to receive the bytes but rather have the next request send immediately following receipt of previous request results ?
Update #2
async private void buttonMemoryTest_Click(object sender, EventArgs e)
{
byte[] bytes = new byte[6];
memoryAddress = 0x00000000;
bytes[0] = 0x90;
bytes[1] = 0x01;
try
{
sendStopWatch.Stop();
sendStopWatch.Reset();
sendStopWatch.Start();
//2097152
for (UInt32 counter = 0; counter < 100; counter++)
{
bytes[2] = (byte)(memoryAddress >> 24);
bytes[3] = (byte)(memoryAddress >> 16);
bytes[4] = (byte)(memoryAddress >> 8);
bytes[5] = (byte)(memoryAddress);
serialPortComms.Write(bytes, 0, 6);
await Task.Delay(1);
memoryAddress += 32;
time = sendStopWatch.Elapsed;
textBoxMemoryTestTime.Text = Math.Round(time.TotalSeconds, 2) + "s";
textBoxPageCounter.Text = Convert.ToString(counter);
}
}
catch (InvalidOperationException)
{
}
catch (TimeoutException)
{
}
}
void serialPortComms_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = serialPortComms.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = serialPortComms.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
string newStr = "";
//See if there was data send back
try
{
if (selfTestClicked == 1)
{
if (selfTestResponseASCII == 1)
{
newStr = Encoding.ASCII.GetString(data, 0, data.Length);
}
else
{
newStr = BitConverter.ToString(data).Replace("-", " ");
}
textBoxReceiveByte_AppendText(newStr);
}
else
{
//
if (checkBoxASCII.Checked)
{
//newStr = Encoding.UTF8.GetString(data, 0, data.Length);
newStr = Encoding.ASCII.GetString(data, 0, data.Length);
}
else
{
newStr = BitConverter.ToString(data).Replace("-", " ");
}
if (checkBoxCR_LF.Checked)
{
newStr += "\r\n";
}
textBoxReceiveByte_AppendText(newStr);
//textBoxReceiveByte_ChangeText(newStr);
//processRxData(data);
}
}
catch (IndexOutOfRangeException)
{
}
}
I am looking for a little help.
I have a program to communicate with a controller through Modbus TCP.
The only problem is I cannot extend the Nop from 125 to 400 because I got Illegal Data Address error message.
Could you please help me with this?
try
{
byte slaveid = 1;
byte function = 4;
ushort id = function;
ushort startAddress = 0;
uint NoP = 125;
byte[] frame = ReadInputRegistersMsg(id, slaveid, startAddress, function, NoP);
this.Write(frame); //data send to controller
Thread.Sleep(100);
byte[] buffReceiver = this.Read(); //data recieving from controller
int SizeByte = buffReceiver[8]; // Data what I got from the controller
UInt16[] temp = null;
if (function != buffReceiver[7])
{
byte[] byteMsg = new byte[9];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg);
byte[] errorbytes = new byte[3];
Array.Copy(buffReceiver, 6, errorbytes, 0, errorbytes.Length);
this.CheckValidate(errorbytes); // check the answer -> error message
}
else
{
byte[] byteMsg = new byte[9 + SizeByte];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg); // Show received messages in windows form app
Array.Copy(buffReceiver, 9, data, 0, data.Length);
temp = Word.ConvertByteArrayToWordArray(data); // Convert Byte[]-> Word[]
}
// Result
if (temp == null) return;
string result = string.Empty;
//foreach (var item in temp) // show all the data
for(int i=0;i<100;i++) // show the first 100 data
{
//result += string.Format("{0} ", item);
result += temp[i];
}
textBox3.Text = result; // insert the result into the textbox (windows form app)
}
catch
{
}
The ReadInputRegister Message is the following:
private byte[] ReadInputRegistersMsg(ushort id, byte slaveAddress, ushort startAddress, byte function, uint NoP)
{
byte[] frame = new byte[12];
frame[0] = (byte)(id >> 8); // Transaction Identifier High
frame[1] = (byte)id; // Transaction Identifier Low
frame[2] = 0; // Protocol Identifier High
frame[3] = 0; // Protocol Identifier Low
frame[4] = 0; // Message Length High
frame[5] = 6; // Message Length Low(6 bytes to follow)
frame[6] = slaveAddress; // Slave address(Unit Identifier)
frame[7] = function; // Function
frame[8] = (byte)(startAddress >> 8); // Starting Address High
frame[9] = (byte)startAddress; // Starting Address Low
frame[10] = (byte)(NoP >> 8); // Quantity of Registers High
frame[11] = (byte)NoP; // Quantity of Registers Low
return frame;
}
The hard limit for modbus is 125 NoP
So i decided to start learning it by giving myself some interesting task.
As a web developer i wanted to have my very own WebSocket server.
So i've written it but it only accepts the first request. After that there is Arithmetic operation onverflow.
Here is some code for you to see what am i doing wrong :S I'm really out of ideas.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using WebSocket.Utils;
namespace WebSocket
{
class SocketReader
{
public EndPoint ipAddr { get; set; }
private Socket userSocket;
private byte[] buffer;
private string SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
public SocketReader(Socket socket)
{
userSocket = socket;
ipAddr = socket.RemoteEndPoint;
Read();
}
private void Read()
{
//Read packet size
buffer = new byte[2];
userSocket.BeginReceive(buffer, 0, 2, SocketFlags.None, ReadCallbackStatic, null);
}
private void ReadCallbackStatic(IAsyncResult ar)
{
try
{
if (userSocket.EndReceive(ar) >= 1)
{
int bufferSize = BitConverter.ToInt16(buffer, 0);
buffer = new byte[bufferSize - 2];
//Read Packet
userSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReadCallback, null);
}
}
catch (Exception se)
{
Console.WriteLine("Something blew on ReadCallbackStatic");
Console.WriteLine(se.Message);
Console.WriteLine(se.StackTrace);
Disconnect();
}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
//Copy the buffer so we can receive the next packet ASAP
byte[] buff = new byte[buffer.Length];
Array.Copy(buffer, buff, buffer.Length);
Read();
string handshakeStr = System.Text.Encoding.UTF8.GetString(buff);
string[] list = Regex.Split(handshakeStr, "\r\n");
//Sec-WebSocket-Key: S5o6fCVLRMJhdXTF3H9w3Q==
//Sec-WebSocket-Version: 8
string key = "";
string clientProtocol = "0";
foreach (string str in list)
{
if (String.IsNullOrEmpty(str)) { continue; }
if (str.Length > 20 && str.Substring(0, 19) == "Sec-WebSocket-Key: ")
{
key = str.Substring(19);
continue;
}
if (str.Length > 20 && str.Substring(0, 23) == "Sec-WebSocket-Version: ")
{
clientProtocol = str.Substring(23);
continue;
}
}
if (String.IsNullOrEmpty(key))
{
Disconnect();
}
SHA1 shaEnc = new SHA1CryptoServiceProvider();
byte[] byteString = ASCIIEncoding.ASCII.GetBytes(key + SOCKET_GUID);
byte[] hash = shaEnc.ComputeHash(byteString, 0, byteString.Length);
string acceptKey = Convert.ToBase64String(hash);
List<string> headers = new List<string>();
headers.Add("HTTP/1.1 101 Switching Protocols");
headers.Add("Upgrade: websocket");
headers.Add("Connection: Upgrade");
headers.Add("Sec-WebSocket-Accept: " + acceptKey);
foreach (string header in headers)
{
SendString(header + "\r\n");
}
Console.WriteLine(acceptKey);
SendString("\r\n");
}
catch (SocketException se)
{
Console.WriteLine("Something blew on ReadCallback");
Console.WriteLine(se.Message);
Disconnect();
}
}
private void SendString(string str)
{
userSocket.Send(Encoding.UTF8.GetBytes(str));
}
private void Disconnect()
{
userSocket.Disconnect(false);
Console.WriteLine("Client with ip {0} Disconnected", ipAddr);
}
}
}
It's shortened version of my class but the problem that is bugging me appears in "ReadCallbackStatic" on this line:
buffer = new byte[bufferSize - 2];
i really don't know what am i doing wrong :S.
The thing is that ... i actually handshake properly but then when i sent some information from the client to my server this exception is thrown
I did some debugging and it appears that somehow the buffer variable becomes negative number O.O
My guess would be that you're blowing up when the MSB is set, i.e. maybe the client is sending a number >= 32768 and < 65536, which (via your ToInt16) is becoming a large negative 16-bit number (or, alternatively, throwing an arithmetic overflow issue). I would try using ToUInt16 instead.
To be honest, you really don't need BitConverter here; depending on the endianness this is either:
int bufferSize = (buffer[0] << 8) | buffer[1];
or
int bufferSize = buffer[0] | (buffer[1] << 8);
I believe problem could be in case when buffer contains of zero numbers, so:
int bufferSize = BitConverter.ToInt16(buffer, 0); // 0
buffer = new byte[bufferSize - 2]; // 0 - 2 == -2
Which results in the overflow exception whilst executing new byte[-2]
I do not know the logic behind your code but I believe you should allocate a new buffer considering buffer.Length value
I am a newbie to modbus and need some help. I am trying to connect using modbus and serial communication. so far i managed to send data but i am unable to get any. the following is my code.
Building packet
private byte[] BuildPacket(int meter_address,int function,int table_name,int table_offset,int high_byte, int low_byte)
{
try
{
byte[] packet = new byte[6];
packet[0] = Convert.ToByte(meter_address);
packet[1] = Convert.ToByte(function);
packet[2] = Convert.ToByte(table_name);
packet[3] = Convert.ToByte(table_offset);
packet[4] = Convert.ToByte(high_byte);
packet[5] = Convert.ToByte(low_byte);
byte[] checksum = DoCheckSum(packet);
byte[] sendPacket = new byte[8];
sendPacket[0] = packet[0];
sendPacket[1] = packet[1];
sendPacket[2] = packet[2];
sendPacket[3] = packet[3];
sendPacket[4] = packet[4];
sendPacket[5] = packet[5];
sendPacket[6] = checksum[0];
sendPacket[7] = checksum[1];
return sendPacket;
}
catch (Exception)
{
throw;
}
}
Checksum for modbus
try
{
ushort CRCFull = 0xFFFF;
byte CRCHigh = 0xFF, CRCLow = 0xFF;
char CRCLSB;
for (int i = 0; i < (packet.Length); i++)
{
CRCFull = (ushort)(CRCFull ^ packet[i]);
for (int j = 0; j < 8; j++)
{
CRCLSB = (char)(CRCFull & 0x0001);
CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
if (CRCLSB == 1)
CRCFull = (ushort)(CRCFull ^ 0xA001);
}
}
byte[] crcByte = new byte[2];
crcByte[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
crcByte[0] = CRCLow = (byte)(CRCFull & 0xFF);
return crcByte;
}
catch (Exception ex)
{
throw ex;
}
}
Connection through serial and modbus
public void ConnectSerialModBus(string COM, int baud)
{
SerialPort port = new SerialPort(COM, baud, Parity.None, 8, StopBits.One);
if (!(port.IsOpen))
{
byte[] sendPacket = BuildPacket(3, 4, 11, 0, 1, 200);
port.Open();
port.RtsEnable = false;
port.Handshake = Handshake.None;
//SEND PACKET TO DEVICE
port.Write(sendPacket, 0, sendPacket.Length);
#region RECEIVE DATA FROM SERIAL
//MAKE PROCESS STOP FOR 5sec
Thread.Sleep(3000);
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.RtsEnable = true;
int size = port.ReadBufferSize;
byte[] readingbyte = new byte[size];
port.Read(readingbyte, 0, readingbyte.Length);
string reading = Encoding.GetEncoding("Windows-1252").GetString(readingbyte);
port.Close();
port.Dispose();
#endregion
}
}
The problem is when it comes to reading the response, the program gets stuck. if possible please help me out figure what is wrong with it.
found a solution to the problem, the problem was with the thread.sleep. was giving it 3secs which is too much for the rtf to receive the packet. changed to 10ms and worked fine.