I successfully made a WebSocket server in C# which I can connect to. I make the handshake as RFC 6455 requires it.
Whatever I send (via WebSocket.send()) to it (for example "asd") the stream only has 9 bytes of data which is "unrepresentable" by UTF8.
using System.Net.Sockets;
using System.Net;
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
class Server
{
public static void Main()
{
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream stream = client.GetStream();
Boolean isHandshaked = false;
while (true)
{
while (!stream.DataAvailable)
{
}
Byte[] bytes = new Byte[client.Available];
stream.Read(bytes, 0, bytes.Length);
if (!isHandshaked)
{
Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + Environment.NewLine
+ "Connection: Upgrade" + Environment.NewLine
+ "Upgrade: websocket" + Environment.NewLine
+ "Sec-WebSocket-Accept: " + Convert.ToBase64String(
SHA1.Create().ComputeHash(
Encoding.UTF8.GetBytes(
new Regex("Sec-WebSocket-Key: (.*)").Match(
Encoding.UTF8.GetString(bytes)
).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
)
)
) + Environment.NewLine
+ Environment.NewLine);
stream.Write(response, 0, response.Length);
isHandshaked = true;
}
else
{
Console.WriteLine(Encoding.UTF8.GetString(bytes));
}
}
}
}
Where I missed something?
Messages between client and server are not sent as plain text. See the data framing section of the standard for how to encode/decode them.
For your example of a client sending a 3 byte string, this will result in a message of
1 byte - 0x81 - saying that this is a non-fragmented text message
1 byte - 0x83 - saying that the message body is 3 bytes long and it's contents are masked (all client -> server messages use masking. server -> client messages must not be masked). The top bit (byte_val & 0x80) is set if a message is masked. The remaining 7 bits (byte_val & 0x7F) gives the length of the messages up to 125 bytes. See link below for how to determine the length of longer messages.
4 bytes - mask. Always 4 bytes. Content determined by the client and should change for each message
3 bytes - message. Can be decoded using the mask and algorithm in section 5.3 of the spec.
You can unmask a message using code like the following
byte mask[4];
byte[] msg_data;
// read message, initialising mask, msg_data
for (int i=0; i<msg_data.Length; i++)
{
msg_data[i] = msg_data[i] ^ mask[i%4]
}
If you need more detail, this previous post explains message sending/receiving and includes some helpful pseudo code.
Having an empty loop to check for data i.e. while (!stream.DataAvailable){} is really a bad practice that you can avoid.
The read method is a blocking method, so it will wait until the data is available
int bufferSize = 1024; // change it as you want
byte[] message = new byte[bufferSize];
readLength = stream.Read(message, 0, bufferSize);
You can try code below and see if it works, i suspect you are not reading full response.
byte[] buffer = new byte[4155];
int bytesRead = 0;
using (var input = client.GetStream())
{
while (true)
{
bytesRead = input.Read(buffer, 0, buffer.Length);
totalBytes += bytesRead;
if (bytesRead > 0)
// keep processing ur data here, add it to another buffer maybe
else
break; // come out of while loop if there is no data
}
}
}
Related
here is my code to send TCP request coded in SSL and get the answer from server, but it doesn't work. Debugging and trying to catch exceptions didn't work.
public void SendRequest(string request)
{
byte[] buffer = new byte[2048];
int bytes = -1;
sslStream.Write(Encoding.ASCII.GetBytes(request));
bytes = sslStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytes));
}
I took that from stackoverflow answer so I'm suprised it doesn't work. Here is my code that receives greeting from server (it works properly):
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = 0;
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
Console.Write(messageData.ToString());
If the sslStream.Read(buffer, 0, buffer.Length); is hanging, it's because the server hasn't sent a response.
Taking a look at your code on github (linked from your other question), it looks like you are using Console.ReadLine() to read commands and then write them to your network stream.
What is happening is that ReadLine() strips off the "\r\n" in the string that it returns, so what you'll need to do when sending it to the server is to add back the "\r\n" so that the server knows that the command is finished (it waits until it gets an EOL sequence before it will respond).
What you could do is in SendRequest(), you could do:
sslStream.Write(Encoding.ASCII.GetBytes(request + "\r\n"));
In my client/server application my client wiil communicate with the server for 2 functions: the client will either request data from the server or it will send data so the server will save it. I'm using one socket for both methods, and the method to be used is defined by the first byte sent. If the first byte is "1" it is requesting data. If it is "2", it will send data (data bytes are sent after the "2" byte). It works perfectly for sending data. But when I'm requesting data it works, as long as I don't read the socket stream in the client. It's like if I make the client read data after sending data, the server will have no data to read, and it just crashes when trying to read the data.
Here is my server code:
private const int BufferSize = 1024;
NetworkStream netstream = null;
byte[] RecData = new byte[BufferSize];
int RecBytes;
try {
netstream = clientSocket.GetStream();
int totalrecbytes = 0;
using (MemoryStream ms = new MemoryStream()) {
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
byte[] bytes = ms.ToArray();
byte b = bytes[0];
switch (b) {
case 1:
//Here I gather data and put it in "stream" variable
byte[] SendingBuffer = null;
int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(stream.Length) / Convert.ToDouble(BufferSize)));
int TotalLength = (int)stream.Length, CurrentPacketLength, counter = 0;
for (int i = 0; i < NoOfPackets; i++) {
if (TotalLength > BufferSize) {
CurrentPacketLength = BufferSize;
TotalLength = TotalLength - CurrentPacketLength;
}
else
CurrentPacketLength = TotalLength;
SendingBuffer = new byte[CurrentPacketLength];
stream.Read(SendingBuffer, 0, CurrentPacketLength);
netstream.Write(SendingBuffer, 0, (int)SendingBuffer.Length);
}
netstream.Flush();
}
catch (Exception e) {
Console.WriteLine("EXCEPTION:\n" + e.ToString());
}
break;
case 2:
//Code to read data
break;
}
}
netstream.Close()
clientSocket.Close();
And here is my client code:
using (System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient()) {
string returnData = "";
IAsyncResult ar = clientSocket.BeginConnect("127.0.0.1", 8080, null, null);
System.Threading.WaitHandle wh = ar.AsyncWaitHandle;
try {
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false)) {
clientSocket.Close();
Console.WriteLine("Timeout");
return;
}
System.Net.Sockets.NetworkStream serverStream = clientSocket.GetStream();
byte b = 1;
byte[] outStream = { b };
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
//If I comment following lines, the server can read sent data, but server can't otherwise
byte[] RecData = new byte[1024];
int RecBytes;
int totalrecbytes = 0;
MemoryStream MS = new MemoryStream();
while ((RecBytes = serverStream.Read(RecData, 0, RecData.Length)) > 0) {
MS.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
serverStream.Close();
clientSocket.Close();
clientSocket.EndConnect(ar);
}
catch (Exception ex) {
Console.WriteLine("Exceção: " + ex.ToString());
}
finally {
wh.Close();
}
}
So, how can I send data to server and read the response? (I tried even putting the thread to sleep after sending data, with no luck.)
Thanks in advance.
EDIT:
With some debug messages I discovered that the server do read the "1" byte that was sent, but somehow it gets stuck inside the while loop, like, the server just stops there, no more loops and it does not leave the while loop. I saw that after writing "loop" in console inside the while loop, and writing read bytes also in console. It wrote "loop" once, and the read byte.
This code worries me:
//When I get here, there is no data to read
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0) {
ms.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
You are reading until the client closes the connection (or shuts down sending, which you don't do). But the client only closes when the server has replied. The server reply will never come. It is a deadlock.
Solution: Read a single byte to determine the requests command (b).
Unrelated to the question, your "packetised" sending (NoOfPackets, ...) does not seem to serve any purpose. Just use Stream.Copy to write. TCP does not have packets.
An even better solution would be to abandon your custom TCP protocol and use an HTTP library. All these concerns just go away. There are various smaller problems with your code that are very typical to see in TCP code.
I send the serialized data over LAN network but sometimes the information is lost! Process is the following:
Sender:
string mydata is being serialized
string mydata is converted to byte[] bytes_of_mydata
int size_of_mydata is the length of byte[] bytes_of_mydata
int size_of_mydata itself is turned into byte[] bytes_size_of_mydata
byte[] bytes_of_mydata and byte[] bytes_size_of_mydata are sent
Receiver:
i first receive byte[] bytes_size_of_mydata
retrieve length int size_of_mydata of the second message from byte[] bytes_size_of_mydata
i then receive byte[] bytes_of_mydata, knowing exact length!
i then convert byte[] bytes_of_mydata to string mydata
deserialize string mydata
This approach usually works in most situations, but sometimes my data is not transmitted fully, so the string can't be deserialized.
I've debugged the received byte[] on the "receiver" and here is what happens:
I get the size of second message:
int size_of_second_message = BitConverter.ToInt32(dataByteSize, 0); // 55185
I start to receive the second message to byte array:
Byte[] dataByte = new Byte[55185];
But starting from position 5840 I start to receive 0 (nulls), so the part "5840 - 55185" are all "0":
byte[5836] = 53;
byte[5837] = 57;
byte[5838] = 54;
byte[5839] = 49;
byte[5840] = 0; // information ends to flow
byte[5841] = 0;
byte[5842] = 0;
byte[5843] = 0;
//....
byte[55185] = 0;
The example from the above is taken from an actual debugger!
So what's the problem? It's like the connection is being lost during transmission!! Why is it happening and how do I counter this problem? It doesn't happen on "every-time" basis.
And here comes the code
Send:
//text_message - my original message
//Nw - network stream
MemoryStream Fs = new MemoryStream(ASCIIEncoding.Default.GetBytes(text_message));
Byte[] buffer = Fs.ToArray(); // total 55185 bytes (as in example)
Byte[] bufferSize = BitConverter.GetBytes(Fs.Length); // 32 bytes represent size
bufferSize = GetNewByteSize(bufferSize);
Nw.Write(bufferSize, 0, bufferSize.Length); // send size
Nw.Flush();
Nw.Write(buffer, 0, buffer.Length); // send message
Nw.Flush();
Receive:
//get first(SIZE) bytes:
int ReadSize = 0; int maxSize = 32; // 32 - constant!
Byte[] dataByteSize = new Byte[maxSize];
int origsize;
using (var strm = new MemoryStream())
{
ReadSize = Nw.Read(dataByteSize, 0, maxSize);
strm.Write(dataByteSize, 0, ReadSize);
strm.Seek(0, SeekOrigin.Begin);
origsize = BitConverter.ToInt32(dataByteSize, 0); // origsize = 55185
}
Nw.Flush();
//get next(MESSAGE) bytes:
string message = ""; int thisRead = 0;
int max = Convert.ToInt32(origsize); // origsize = 55185
Byte[] dataByte = new Byte[max];
using (var strm = new MemoryStream())
{
thisRead = Nw.Read(dataByte, 0, max);
strm.Write(dataByte, 0, thisRead);
strm.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(strm))
{
message = reader.ReadToEnd();
}
}
Nw.Flush();
// message - the message that is being transmitted partly (sometimes)!
I didn't want to post the code but you guys usually ask "show us what you've done", so here it is!
Edit
Temporary fix is to switch to StreamWriter, reader.
Receive + send (server):
NetworkStream Nw = new NetworkStream(handlerSocket.Client);
string toreceive = "";
StreamReader reader = new StreamReader(Nw);
toreceive = reader.ReadLine();
string text_message = "to send back";
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine(text_message);
writer.Flush();
Nw.Close();
Send + receive (client):
NetworkStream Nw = new NetworkStream(handlerSocket.Client);
StreamWriter writer = new StreamWriter(Nw);
writer.WriteLine("to send");
writer.Flush();
string toreceive = new StreamReader(Nw).ReadLine();
writer.Close();
Nw.Close();
I'm looking for a solution regarding original problem, but so far everything is working due to temporary fix.
TCP is a stream based protocol which lets you read as much data has yet been received. Just because you send data in one step, there is no guarantee that the data will be received in the same block. You have to loop on the receiving side until you have received all the data you anticipate.
By the way I think that your protocol with an explicit length field at the start is really good, it makes up for simple client code (as simple as it gets at least).
Some time back I asked a question on built in functionality to wait until X bytes of data is available: .NET blocking socket read until X bytes are available?. The answer is unfortunately no.
I have a server that streams data out on a TCP port once you connect to it. You can see this if you telnet to the TCP port and data starts flowing.
I am looking for an example that will let me connect to an IP address and port and receive the data in a stream in the application.
All examples I can find are with a client-server model with the client sending (which is not what I need) and the server binding to a port on itself and receiving.
I need this to be asynchronous and believe this can be done, but I could do with a good leg up!
If you are using a TcpClient, using GetStream for getting the NetworkStream and then use the stream for reading the data sent by the server. You can always use the stream asynchronously, using BeginRead.
If you are using a plain old Socket, you can use BeginReceive to receive asynchronously once connected.
Either way, as soon as you have a NetworkStream or a Socket object that is bound and connected, there is no difference between the server or the client. You can use the server example of reading in the client code, most often with no (or little) modification.
For an example:
byte[] readBuffer = new byte[1000];
{
TcpClient tcpClient = new TcpClient(serverHost, serverPort);
NetworkStream stream = tcpClient.GetStream();
stream.BeginRead(readBuffer, 0, 1000, readHandler, tcpClient);
}
...
byte[] tempBuff = new byte[1000];
int tempBuffSize = 0;
// This is a rough example of reading and handling data
// that is delimited by \r\n. This code most probably is
// missing many edge case handling, so use it only as a starting
// point
void readHandler(IAsyncResult result)
{
TcpClient tcpClient = (TcpClient)result.AsyncState;
int dataLen = tcpClient.GetStream().EndRead();
int currStart = 0;
int currEnd = -1;
for (int i = 0; i < dataLen; i++)
{
if (readBuffer[i] == '\r' && i < (readBuffer.Length - 1) &&
readBuffer[i + 1] == '\n')
{
// Set the end of the data
currEnd = i - 1;
// If we have left overs from previous runs:
if (tempBuffSize != 0)
{
// Allocate enough space for the joined buffer
byte[] joinedData = new byte[tempBuffSize + (currEnd - currStart + 1)];
// Get the leftover from the previous read
Array.Copy(tempBuff, 0, joinedData, 0, tempBuffSize);
// And add the current read as well
Array.Copy(readBuffer, currStart, joinedData, tempBuffSize, (currEnd - currStart + 1));
// Now handle it
HandleData(joinedData, 0, joinedData.Length);
// Mark that we don't have any leftovers anymore
tempBuffSize = 0;
}
else
{
// Handle the data, from the start to the end, between delimiter
HandleData(readBuffer, currStart, currEnd);
}
// Set the new start - after our delimiter
currStart = i + 2;
}
}
// See if we still have any leftovers
if (currStart < dataLen)
{
Array.Copy(readBuffer, currStart, tempBuff, 0, dataLen - currStart);
tempBuffSize = dataLen - currStart;
}
// Set the asynchronous read again
stream.BeginRead(readBuffer, 0, 1000, readHandler, tcpClient);
}
i am developing application which send and receive data between two computers but there is problem which i am facing when i send data the file size would be 4.56 kb but when i receive data on other side the file size reduce to 1.42 kb and data write in file also in complete my receiving byte size is 1024 * 5000.i am using c#.i am using TCP
here is my code
i am first sending data to tell other computer what file i want to receive
private void GetLoginFile()
{
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
char[] delimiter = splitter.ToCharArray();
byte[] fileName = Encoding.UTF8.GetBytes(myIP + "_GetLoginFile"); //file name
byte[] fileData;
fileData = Encoding.UTF8.GetBytes("null");
//byte[] fileData = reads.ReadToEnd().to; //file
byte[] fileNameLen = BitConverter.GetBytes(fileName.Length); //lenght of file name
clientData = new byte[4 + fileName.Length + fileData.Length];
fileNameLen.CopyTo(clientData, 0);
fileName.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + fileName.Length);
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse(serverIP);
IPEndPoint ipEnd = new IPEndPoint(ipAdd, 9050);
clientSock.Connect(ipEnd); //target machine's ip address and the port number
clientSock.Send(clientData);
byte[] clientData1 = new byte[1024 * 5000];
string receivedPath = mypath + "XML\\";
int receivedBytesLen = clientSock.Receive(clientData1);
int fileNameLen1 = BitConverter.ToInt32(clientData1, 0);
string fileName1 = Encoding.ASCII.GetString(clientData1, 4, fileNameLen1);
//string file = Encoding.UTF8.GetString();
BinaryWriter bWrite = new BinaryWriter(File.Open(receivedPath + fileName1, FileMode.Append));
bWrite.Write(clientData1, 4 + fileNameLen1, receivedBytesLen - 4 - fileNameLen1);
//clientSock.Shutdown(SocketShutdown.Send);
bWrite.Close();
clientSock.Close();
}
catch (Exception ex)
{
clientSock.Close();
MessageBox.Show(ex.Message);
}
}
can anyone help me out to solve this problem.
Well, you haven't given any code... but I suspect it's your receiving code which is wrong.
You should be looping round, reading until a Read call on the stream returns 0. Don't assume you'll get all the data in one call.
EDIT: Yup, look at your receiving code:
int receivedBytesLen = clientSock.Receive(clientData1);
What makes you think you've received all the data you need in that one call? You need to loop round, receiving until either the other end closes the connection, or you've read all the data you need.
Are you using UDP sockets? If so, then everything is fine: udp is not reliable. Use TCP to get every single byte sent.