I have a small program to receive UPD Packets. I have some bit problem in receiving packets . I actually need to revce packets by id for example "position (packet id: 196) , Location :187 etc" With my code i get some data but i dont know how to find the id and how to get real data inside the packet.
Packet Header
|SYNC Byte|SYNC Byte|Data Length|Identifier|Data Bytes|Checkssum|
|1(0x24) |2(0x40) |Byte |Bye | |Byete |
Field :Sync Bytes SIZE: 2 Bytes
Field :Data Length SIZE: 1 Byte
Field :Packet Identifier SIZE: 1 byte
Field :Data SIZE: 0-255 bytes
Field :Checksum SIZE: 1 byte
enter code here
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace SimpleUdpReciever
{
class pProgram
{
static void Main(string[] args)
{
int localPort = 18006;
IPEndPoint remoteSender = new IPEndPoint(IPAddress.Any, 0);
bool flag = false;
for (int i = 0; i < args.Length; i++)
{
string cmd = args[i];
string value;
int tempInt;
IPAddress tempAddress;
switch (cmd)
{
case "-lp":
value = GetValue(args, ref i);
if (int.TryParse(value, out tempInt))
localPort = tempInt;
break;
case "-rp":
value = GetValue(args, ref i);
if (int.TryParse(value, out tempInt))
remoteSender.Port = tempInt;
break;
case "-rh":
value = GetValue(args, ref i);
if (IPAddress.TryParse(value, out tempAddress))
remoteSender.Address = tempAddress;
else if (int.TryParse(value, out tempInt) && tempInt == 0)
remoteSender.Address = IPAddress.Any;
break;
case "-?":
default:
PrintHelpText();
flag = true;
break;
}
}
// Exit application after help text is displayed
if (flag)
return;
// Create UDP client
UdpClient client = new UdpClient(localPort);
UdpState state = new UdpState(client, remoteSender);
// Start async receiving
client.BeginReceive(new AsyncCallback(DataReceived), state);
// Wait for any key to terminate application
Console.ReadKey();
client.Close();
}
private static void DataReceived(IAsyncResult ar)
{
UdpClient c = (UdpClient)((UdpState)ar.AsyncState).c;
IPEndPoint wantedIpEndPoint = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = c.EndReceive(ar, ref receivedIpEndPoint);
bool isRightHost = (wantedIpEndPoint.Address.Equals(receivedIpEndPoint.Address)) || wantedIpEndPoint.Address.Equals(IPAddress.Any);
bool isRightPort = (wantedIpEndPoint.Port == receivedIpEndPoint.Port) || wantedIpEndPoint.Port == 0;
if (isRightHost && isRightPort)
{ string test5 = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("test5 = {0}", test5);
}
// Restart listening for udp data packages
c.BeginReceive(new AsyncCallback(DataReceived), ar.AsyncState);
}
private static string GetValue(string[] args, ref int i)
{
string value = String.Empty;
if (args.Length >= i + 2)
{
i++;
value = args[i];
}
return value;
}
private static void PrintHelpText()
{
Console.WriteLine("Simple Udp Receiver is an application that prints incoming data to screen.");
Console.WriteLine("Data is converted to ASCII before printing.");[![enter image description here][1]][1]
Console.WriteLine("Command switches:");
Console.WriteLine("-? : Displays this text.");
Console.WriteLine("-lp : Set local receiving port. \"-lp 4001\" Default: 11000");
Console.WriteLine("-rp : Set remote sender port. \"-rp 4001\" Default: 0 (Any port)");
Console.WriteLine("-rh : Set remote sender ip. \"-rh 192.168.1.10\" Default: 0 (Any ip)");
Console.WriteLine("\n Example of usage:\nSimpleUdpReciver.exe -lp 11000 -rh 192.168.10.10 -rp 4001");
}
}
}
Out put Looks like this whiole running this program : $# za� �X
�� �
Related
I am Sending 68bytes of data using UDP Protocol.
68bytes of data consist of 4byte of int and random 64byte of byte array. uint seq starts with zero and it will increase if client send datagram to server once at a time. I used BitConverter.GetBytes for data's seq to make byte array.
public class NewData
{
public uint seq;
public byte[] data = new byte[64];
public NewData()
{
seq = 0;
data = null;
}
public NewData(uint seq, byte[] data)
{
this.seq = seq;
this.data = data;
}
}
Server has 2 Threads. 1 Thread will Enqueue and the other thread will Dequeue. (Producer and Consumer Thread)
I tried to check the data is coming well.
private readonly ConcurrentQueue<NewData> queue = new ConcurrentQueue<NewData>();
private void ReceiveThread()
{
int recv;
uint seq = 0;
byte[] datagram = new byte[1024];
List<byte> list = new List<byte>(); // for enqueue seq test
while (true)
{
autoresetevent.WaitOne();
if (Dispatcher.Invoke(() => (string)StartButton.Content == "Stop"))
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(endpoint);
socket.Blocking = false;
IPEndPoint sender = new IPEndPoint(IPAddress.Any, Dispatcher.Invoke(() => Convert.ToInt32(portTextBox.Text)));
EndPoint tmpRemote = (EndPoint)sender;
while (true)
{
try
{
recv = socket.ReceiveFrom(datagram, ref tmpRemote);
}
catch (SocketException e)
{
Thread.Sleep(threadSleep);
continue;
}
////------------------------------------------------------------------------
//// To Test Datagram Sequence
////------------------------------------------------------------------------
//for (int i = 0; i < 4; i++)
//{
// list.Add(datagram[i]);
//}
//Debug.Write(Convert.ToString(BitConverter.ToUInt32(list.ToArray(), 0)) + " ");
//list.Clear();
NewData newdata = new NewData(seq, datagram);
queue.Enqueue(newdata);
////------------------------------------------------------------------------
//// To check queue Count. if, queue Count = Client packet sent, no packet lost
////------------------------------------------------------------------------
//Debug.Write(Convert.ToString(queue.Count()) + " ");
seq++;
if (Dispatcher.Invoke(() => (string)StartButton.Content == "Start"))
{
socket.Close();
break;
}
Thread.Sleep(threadSleep);
}
}
}
}
private void FileSaveThread()
{
uint packet_lost = 0;
uint oldValue = 0;
uint currentValue = 0;
int j = 0; // for index
List<byte> sequenceList = new List<byte>(); // sequenceList
while (true)
{
autoresetevent2.WaitOne()
NewData newdata = new NewData();
if (queue.TryDequeue(out newdata))
{
for (j = 0; j < 4; j++)
sequenceList.Add(newdata.data[j]);
oldValue = BitConverter.ToUInt32(sequenceList.ToArray(), 0); // oldValue에 현재값 저장
queue.TryPeek(out newdata);
for (j = 0; j < 4; j++)
sequenceList.Add(newdata.data[j]);
currentValue = BitConverter.ToUInt32(sequenceList.ToArray(), 0); // oldValue에 현재값 저장
//Debug.Write(Convert.ToString(currentValue) + " ");
sequenceList.Clear();
if (!(currentValue == oldValue + 1))
{
packet_lost++;
Dispatcher.Invoke(() => dataResultTextBox.Text += " Packet_Lost : " + packet_lost + "\n");
}
}
Thread.Sleep(threadSleep);
}
}
The datagram's seq missing after 973.
Debug.Write () says
... 970 971 972 974 977 981 984 987 991 994 998 1001 1004 1007 1010 1014 1017 1021 1023 1027 1030 1034 1037 ...
Why does interval changed since the datagram sequence increased 1 at a time?
Or Should I think about other way to change byte array to Int?
Edit) I am sending data per 10ms. It works when i send data per 100ms.
client code
private async void DataSender(int num, int cycle, string ip, int port)
{
uint dataSequence = 0;
byte[] data = new byte[64]; // 64byte data
byte[] byteDataSeq = new byte[4]; // int sequence to byte
byte[] datagram = new byte[1024]; // seq + data
List<byte> datagramList = new List<byte>();
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port); // 서버의 주소 지정
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // udp 소켓 client 선언
while (true)
{
if ((string)startButton.Content == "Start")
{
break;
}
random.NextBytes(data);
byteDataSeq = BitConverter.GetBytes(dataSequence);
datagramList.AddRange(byteDataSeq);
datagramList.AddRange(data);
datagram = datagramList.ToArray();
datagramList.Clear();
client.SendTo(datagram, ep);
dataSequence++;
await Task.Delay(cycle);
}
}
If Client sends data and sleep for 10ms,
Dequeue Thread should not sleep more than 10ms. It should be more faster than sender.
For example, If you send data per 5ms, transaction per second will be 200 data. Then your Dequeue Thread should not sleep. Even 1 ms sleep will cause error.
Debug.Write will cause error too. If you try to print every data that socket received, Dequeue thread won't work properly.
I have a TCPListener in C# and the client in Unix C. I use TcpClient.Client.SendFile for transmitting a file to client socket in Unix and it works fine for plain txt file. It fails to produce the full file on the unix end, when I send JPEG files. Any Idea?
C# code part
============
static void Main(string[] args)
{
TcpListener serverSocket = new TcpListener(10001);
TcpClient clientSocket = default(TcpClient);
serverSocket.Start();
Console.WriteLine(" >> Server Started");
clientSocket = serverSocket.AcceptTcpClient();
Console.WriteLine(" >> Accept connection from client");
while ((true))
{
try
{
NetworkStream networkStream = clientSocket.GetStream();
byte[] bytesFrom = new byte[10025];
networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom).TrimEnd('\0');
Console.WriteLine(" >> Data from client - " + dataFromClient +" Length "+ dataFromClient.Length);
string a1 = "C:\\MRTD\\PICTURE\\abc.jpg";
clientSocket.Client.SendFile(a1);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
}
}
}
}
Unix C code to read the file
============================
char *tcp_recv( int id_type )
{
register int nbytes;
static char readbuf[MAXLINE];
static char tempbuf[980000];
int ngot = 0, bulk_data=0, p_read_val;
char * x, * y, * z, *j, *k, *x1, *bar;
char bulk_buf[180000], tempstr1[180000] , fstr[40], termtor[40];
int fd_ready;
fd_set read_fds; /* Read file descriptors */
int fd_port = gfd_sock;
struct timeval timeout;
timeout.tv_sec = 3600;
timeout.tv_usec = 0;
while (TRUE)
{
FD_ZERO( &read_fds );
FD_SET( fd_port, &read_fds );
strcpy(fstr,"FAIL");
if((fd_ready = select(fd_port+1,&read_fds,NULL,NULL,&timeout))< 0)
{
if( errno == EINTR ) { continue; }
logmsg("ERROR select() returned errno %d", errno );
logmsg("Select error waiting for packet." );
return fstr;
}
else if( fd_ready == 0 )
{
logmsg("Timeout waiting for packet.");
strcpy(fstr,"TIMEOUT");
return fstr;
}
memset( readbuf, 0x00, sizeof( readbuf ));
memset( br_kde, 0x00, sizeof( br_kde ));
if((nbytes = read( fd_port, readbuf, sizeof(readbuf)-1 )) < 0 )
{
logmsg( "tcp_recv: nbytes %d, errno %d, %s", nbytes, errno, strerror( errno ) );
if (errno == EINTR || errno == EAGAIN )
{
errno = 0;
continue; /* assume SIGCLD */
}
else
{
/*
* connection failer.
*/
logcon( "Desko connection failed. Pier link is DOWN!" );
logmsg( "Desko connection failed. Pier link is DOWN!" );
close_files();
exit (1);
break;
} /* end else if */
}
else
{
logmsg("tcp_recv: readbuf is %s, bytes %d", readbuf, nbytes);
strcat(tempbuf, readbuf);
logmsg("tempbuf is %s", tempbuf );<== full file listing is missing in case of JPEG
}
return tempbuf;
}
}
I am working on a new machine at my works which is controlled via a PC. Current stuck on talking to a camera system that is connected via Ethernet.
Here is my code of opening a connection.
TcpClient client;
NetworkStream stream;
public bool OpenConnection()
{
client = new TcpClient();
try
{
//Camera.Open();
client.Connect("192.168.0.10", 8500);
stream = client.GetStream();
}
catch (Exception ex)
{
return false;
}
return true;
}
So far so good. Once the connection is open I then request some information from the camera
The message format I am using has STX(0x02) to indicate the start of the message and ETX(0x03) as the end of the message.
char StartOfPacket = (char)0x02;
char EndOfPacket= (char)0x03;
public bool RetrieveDigits(out string Digits)
{
// Send the trigger cammand to the vision system
Digits = "";
bool EverythingOK = true;
string DataToSend = StartOfPacket + "T1" + EndOfPacket;
byte[] buff = Encoding.ASCII.GetBytes(DataToSend);
if (LogCameraEvent != null)
LogCameraEvent(">> " + DataToSend);
try
{
stream.Write(buff, 0, buff.Length);
}
catch (Exception ex)
{
Logging.Instance.LogExceptionToFile(MethodBase.GetCurrentMethod(), ex);
EverythingOK = false;
}
Thread.Sleep(100);
byte[] buffer;
if (EverythingOK)
{
// Check the response
buffer = ReadCamera(10);
// Process the packets
string[] packets = ProcessPackets(buffer);
if (packets != null)
{
if (packets.Length > 0)
{
bool TriggerFound = false;
for (int i = 0; i < packets.Length; i++)
{
if (packets[i] == "T1")
{
TriggerFound = true;
continue;
}
else if (TriggerFound)
{
// If we are here then we should now be the data that was requested
if (string.IsNullOrEmpty(packets[i]))
{
Digits = packets[i-1]; // previous packet may have data from previous trigger. Need to look into why this happens.
}
else
Digits = packets[i];
EverythingOK = true;
break;
}
else
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
return EverythingOK;
}
Here is the part where I think the issue may lie, getting the response.
private byte[] ReadCamera(int ExpectedLength)
{
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
int chunk;
while(stream.DataAvailable)
{
chunk = stream.Read(Buffer, read, Buffer.Length-read);
read += chunk;
// If we have reached the end of our buffer, check to see if theres any more information
if(read == Buffer.Length)
{
if(!stream.DataAvailable)
return Buffer;
// Nope. Resize the buffer, put the byte we've just read and continue
byte[] newBuffer = new byte[Buffer.Length * 2];
Array.Copy(Buffer, newBuffer, Buffer.Length);
Buffer = newBuffer;
//read++;
}
else if(!stream.DataAvailable)
return Buffer;
Thread.Sleep(50);
}
// Buffer is now too big, shrink it
byte[] ret = new byte[read];
Array.Copy(Buffer, ret, read);
return ret;
}
private string[] ProcessPackets(byte[] data)
{
// look for the stat char
List<string> Packets = new List<string>();
byte Start = 0x02;
bool StartFound = false;
byte End = 0x03;
StringBuilder sb = new StringBuilder();
for(int i =0; i<data.Length; i++)
{
if(StartFound)
{
// Check to see if its the end
if (data[i] == End)
{
Packets.Add(sb.ToString());
sb.Clear();
}
else
sb.Append(Encoding.ASCII.GetChars(data, i, 1));
}
// Find the start
if (!StartFound)
{
if (data[i] == Start)
{
StartFound = true;
}
}
}
return Packets.ToArray();
}
Let me explain what should happen and then what is happening. Through RetrieveDigits method I am sending "T1" to the camera. What the camera will do is respond with "T1" followed by 2 ascii characters, for now we will say AA. Using a diagnostic app on the camera system I can monitor the Ethernet and I see the following.
(>> means Received by Camera)
(<< means Sent from Camera)
>>[STX]T1[ETX]
<<[STX]T1[ETX][STX]AA[ETX]
So I see what the camera has sent. I confirmed the PC has has received the data using wire shark.
Now further down in the RetrieveDigits method you can see I process the packets received, loop through the packets until I find "T1" and then assume the next packet will be the data I am after and I set Digits to this value.
What I am finding is that sometimes when I run the app I see that Digits is set to "".
I am also finding that sometimes my data received will be "AA" then "T1" rather than "T1" then "AA". What I suspect is happening is that when its back to front, the "AA" is actually from the previous data sent from the camera and for some reason it was missed when reading from the stream.
Any idea why this could be happening as I am reading the data until Stream.Available is false.
Edit:
Modified the ReadCamera code to process the packets, reading 1 byte at a time.
private string[] ReadCamera(int ExpectedLength, int ExpectedPackets)
{
List<string> Packets = new List<string>();
bool StartFound = false;
StringBuilder sb = new StringBuilder();
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
while (true)
{
read += stream.Read(Buffer, read, 1);
// Check to see if the byte read is the start of a packet
if (Buffer[read - 1] == StartOfPacket)
{
StartFound = true;
}
else if (StartFound)
{
// Check to see if the byte read is the end of a packet
if (Buffer[read - 1] == EndOfPacket)
{
Packets.Add(sb.ToString());
sb.Clear();
StartFound = false;
if (Packets.Count == ExpectedPackets)
break;
}
else
{
sb.Append(Encoding.ASCII.GetChars(Buffer, read - 1, 1));
}
}
}
// For Debuggin purposes
foreach(string s in Packets)
if (LogCameraEvent != null)
LogCameraEvent("<< " + s);
return Packets.ToArray();
}
and modified calling the method like so
// Check the response
string[] packets = ReadCamera(10,2);
// Process the packets
//string[] packets = ProcessPackets(buffer);
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.
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