Loosing one Byte over TCP Socket - c#

So I'm trying to make a chatroom. I use TCP Sockets to send all information. But when I send a byte array the receiving socket's buffer has the last byte missing. it's 0 cause the byte array is 255 big, so the left over bytes are 0. I've checked through debug mode, at the point when the packet was sent, the array is correct. But at the break point when the sockets finished receiving it's missing that last byte. Any reason why this would be happening? I saw another thread which said you had to stop the thread till the sockets finished receiving, but I'm using AsyncCallBack which to my knowledge is called when the socket has finished receiving.
Also the first byte in each packet is supposed to be the string size (To account for the extra empty bytes).
PacketClass:
public class Packet
{
public byte[] Buffer;
public Packet(string message)
{
Buffer = new byte[255];
byte[] messageArray = Encoding.ASCII.GetBytes(message);
Buffer[0] = (byte)messageArray.GetLength(0);
for (int i = 0; i < messageArray.GetLength(0); i++)
{
Buffer[i+1] = messageArray[i];
}
}
public Packet(byte[] buffer)
{
Buffer = buffer;
}
public string GetMessage()
{
List<byte> messageBuffer = new List<byte>();
for (int i = 1; i <= Buffer[0]; i++)
{
messageBuffer.Add(Buffer[i]);
}
return Encoding.ASCII.GetString(messageBuffer.ToArray());
}
}
SocketClass:
class Client
{
public static List<Client> connectedClients = new List<Client>();
public Socket Sock;
public byte[] Buffer = new byte[255];
public Client(Socket pSock)
{
Sock = pSock;
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
public void Send(byte[] pBuffer)
{
Sock.BeginSend(pBuffer, 0, pBuffer.GetLength(0), SocketFlags.None, new AsyncCallback(SendCallBack), null);
}
public void SendCallBack(IAsyncResult AR)
{
Console.WriteLine("Sent");
Sock.EndSend(AR);
}
public void RecieveCallBack(IAsyncResult AR)
{
Sock.EndReceive(AR);
Packet recPacket = new Packet(Buffer);
Console.WriteLine(recPacket.GetMessage());
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
}
Main Server Program
`class Client
{
public static List connectedClients = new List();
public Socket Sock;
public byte[] Buffer = new byte[255];
public Client(Socket pSock)
{
Sock = pSock;
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
public void Send(byte[] pBuffer)
{
Sock.BeginSend(pBuffer, 0, pBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), null);
}
public void SendCallBack(IAsyncResult AR)
{
Console.WriteLine("Sent");
Sock.EndSend(AR);
}
public void RecieveCallBack(IAsyncResult AR)
{
Sock.EndReceive(AR);
Packet recPacket = new Packet(Buffer);
Console.WriteLine(recPacket.GetMessage());
Sock.BeginReceive(Buffer, 0, 255, SocketFlags.None, new AsyncCallback(RecieveCallBack), null);
}
}`

Solved
The error was in the send method which I didn't include.
sock.BeginSend(sentBuffer[0].Buffer, 0, sentBuffer[0].Buffer[0], SocketFlags.None, new AsyncCallback(SendCallBack), null);
sentBuffer is a list, to be a queue. I changed it to 255 and it workd

Related

.NET performance new byte[] buffer for each operation

I am receiving bytes from a socket to a buffer. Right now, the buffer is a byte array field that's large enough to handle any message I expect.
byte[] recvBuffer = new byte[10000];
public void Receive1(int len)
{
client.Receive(recvBuffer, len, SocketFlags.None);
}
I could make improvements to the "elegance" my design by creating a new buffer each time instead
public void Receive2(int len)
{
byte[] buffer = new byte[len];
client.Receive(buffer);
}
My question is: would the latter lead to reduced performance?
Here's my attempt at answering the question myself. Let me know if this looks reasonable. I made a test client/server setup on my local machine using this code
class SocketTester
{
private const string IP = "127.0.0.1";
private const int PORT = 1776; // how patriotic
Socket serv = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
Socket client = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
public SocketTester()
{
Socket listener = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
listener.SetSocketOption(
SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress,
true);
listener.Bind(new IPEndPoint(IPAddress.Parse(IP), PORT));
listener.Listen(1);
listener.BeginAccept((IAsyncResult ar) =>
{
serv = listener.EndAccept(ar);
}, null);
/* fill it with junk data (i don't care about the actual values) */
for (int i = 0; i < sendBuffer.Length; i++)
{
sendBuffer[i] = (byte)i;
}
}
public void Connect()
{
client.Connect(IP, PORT);
if (!client.Connected)
{
throw new Exception();
}
}
byte[] sendBuffer = new byte[4096];
public void StartSending()
{
/* This blocks at 670 sends if nothing is received.*/
Task.Run(() =>
{
int i = 0;
while (true)
{
serv.Send(sendBuffer);
i++;
}
});
}
byte[] recvBuffer = new byte[10000];
public void Receive1(int len)
{
client.Receive(recvBuffer, len, SocketFlags.None);
}
public void Receive2(int len)
{
byte[] buffer = new byte[len];
client.Receive(buffer);
}
public void LoopReceive1(int tries, int len)
{
for (int i = 0; i < tries; i++)
{
Receive1(len);
}
}
public void LoopReceive2(int tries, int len)
{
for (int i = 0; i < tries; i++)
{
Receive2(len);
}
}
}
I then used the VS debugger to step over each line.
SocketTester s = new SocketTester();
s.Connect();
Thread.Sleep(100);
s.StartSending();
Thread.Sleep(100);
s.LoopReceive1(500, 4096);
s.LoopReceive2(500, 4096);
Both lines seem to execute between 3 and 5 ms with seemingly random variations. I manally moved the execution point back several times (so order shouldn't be an issue). This seems more than fast enough for my application and seems to indicate little to no significant difference.
Am I missing anything here? I'm not particularly familiar with memory management and optimization, nor how it's affected by creating new variables in .NET. If there's something I should read on this topic, I'd love a link :)

How receive a complete screenshot in Async socket?

I have a Java android code that sends data (image or text) to a C# application, to receive these data I'm using Async socket. But exists a problem that is relative to BeginReceive() function is not receiving the complete data when is sent an image.. Then how I can make a kind of "loop" to receive full data and after show the image on Picturebox (for example)?
Form
private Listener listener;
private Thread startListen;
private Bitmap _buffer;
public frmMain()
{
InitializeComponent();
}
private void serverReceivedImage(Client client, byte[] image)
{
try
{
byte[] newImage = new byte[image.Length - 6];
Array.Copy(image, 6, newImage, 0, newImage.Length);
using (var stream = new MemoryStream(newImage))
{
using (var msInner = new MemoryStream())
{
stream.Seek(2, SeekOrigin.Begin);
using (DeflateStream z = new DeflateStream(stream, CompressionMode.Decompress))
{
z.CopyTo(msInner);
}
msInner.Seek(0, SeekOrigin.Begin);
var bitmap = new Bitmap(msInner);
Invoke(new frmMain.ImageCompleteDelegate(ImageComplete), new object[] { bitmap });
}
}
}
catch (Exception)
{
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
}
private delegate void ImageCompleteDelegate(Bitmap bitmap);
private void ImageComplete(Bitmap bitmap)
{
if (_buffer != null)
_buffer.Dispose();
_buffer = new Bitmap(bitmap);
pictureBox1.Size = _buffer.Size;
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_buffer == null) return;
e.Graphics.DrawImage(_buffer, 0, 0);
}
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
startListen = new Thread(listen);
startListen.Start();
}
private void listen()
{
listener = new Listener();
listener.BeginListen(101);
listener.receivedImage += new Listener.ReceivedImageEventHandler(serverReceivedImage);
startToolStripMenuItem.Enabled = false;
}
Listener
class Listener
{
private Socket s;
public List<Client> clients;
public delegate void ReceivedImageEventHandler(Client client, byte[] image);
public event ReceivedImageEventHandler receivedImage;
private bool listening = false;
public Listener()
{
clients = new List<Client>();
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public bool Running
{
get { return listening; }
}
public void BeginListen(int port)
{
s.Bind(new IPEndPoint(IPAddress.Any, port));
s.Listen(100);
s.BeginAccept(new AsyncCallback(AcceptCallback), s);
listening = true;
}
public void StopListen()
{
if (listening == true)
{
s.Close();
listening = false;
}
}
void AcceptCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
Socket sock = handler.EndAccept(ar);
Client client = new Client(sock);
clients.Add(client);
sock.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), client);
client.Send("REQUEST_PRINT" + Environment.NewLine);
handler.BeginAccept(new AsyncCallback(AcceptCallback), handler);
}
void ReadCallback(IAsyncResult ar)
{
Client client = (Client)ar.AsyncState;
try
{
int rec = client.sock.EndReceive(ar);
if (rec != 0)
{
string data = Encoding.UTF8.GetString(client.buffer, 0, rec);
if (data.Contains("SCREEN"))
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
receivedImage(client, bytes);
}
else // not is a image, is a text
{
// prepare text to show in TextBox
}
}
else
{
Disconnected(client);
return;
}
client.sock.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), client);
}
catch
{
Disconnected(client);
client.sock.Close();
clients.Remove(client);
}
}
}
Client
class Client
{
public Socket sock;
public byte[] buffer = new byte[8192];
public Client(Socket sock)
{
this.sock = sock;
}
public void Send(string data)
{
byte[] buffer = Encoding.ASCII.GetBytes(data);
sock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback((ar) =>
{
sock.EndSend(ar);
}), buffer);
}
}
Android code
private byte[] compress(byte[] data) {
Deflater deflater = new Deflater();
deflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
return output;
}
public static DataOutputStream dos;
public static byte[] array;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
array = compress(bos.toByteArray());
//...
dos = new DataOutputStream(SocketBackgroundService.clientSocket.getOutputStream());
byte[] header = ("SCREEN").getBytes(StandardCharsets.UTF_8);
byte[] dataToSend = new byte[header.length + array.length];
System.arraycopy(header, 0, dataToSend, 0, header.length);
System.arraycopy(array, 0, dataToSend, header.length, array.length);
dos.writeInt(dataToSend.length);
dos.write(dataToSend, 0, dataToSend.length);
dos.flush();
EDITION
i'm always getting the error Invalid Parameter in this line
var bitmap = new Bitmap(msInner);
and using compression also happens the same here
z.CopyTo(msInner);
IvalidDataException
on ServerReceivedImage() method respectively.
using this
File.WriteAllBytes(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "image.png"), newImage);
i noted that is receiving only 15KB (size of file without use compression).
I was writing a comment but it does not give me enough space to express my frustration with your code.
My main points are
You try to recompress and perfectly compressed image. PNG is portable network graphics. It was designed for network transfers. If it is acceptable you should use something like jpeg.
You just decode received buffer using UTF8.GetString and search for a text, then re-encode that string and try to decompress and read an image from it, by starting from index 6 which is pretty meaningless considering you added a two byte size field to the start of stream and you really do not know position of "SCREEN".
You do not check if you have received ALL of the stream data.
All of the code looks like you have scoured the SO questions and answers and created a copy pasta.
Now my recommendations.
When transferring data from network, do not try to invent wheels. Try something like gRPC which has both android java and c# packages.
If you will use raw data, please, please know your bytes.
I assume you will extend your code by adding new command pairs. Since you have no magic markers of some kind of signal system, it will be very hard for you to distinguish data from header. For a simple implementation add some kind of magic data to your header and search for that data, then read header and then read data. You may need to read from socket again and again until you receive all of the data.
424A72 0600 53435245454E 008E0005 ..... 724A42
B J r 6 S C R E E N 36352 ..... rJB
this sample data shows that we have a valid stream by looking at "BJr". Then read a 2 byte unsigned integer to read command size which is 6 for SCREEN. Read command and then read four bytes unsigned length for command data. For our sample it is 36352. Just to be safe I've added an end of command marker "rJB".
For a bonus point try reducing memory allocations / copies, you can look at System.Span<T>

how to receive data from a Socket in .NET Core?

I'm currently porting a hardware library to .NET Core. The communication works over TCP. I have problems with the 'Socket.BeginReceive' method. MSDN
It seems there is no equivalent method in .NET Core. How can I receive data from a TCP Socket?
private void InternalDataReceived(IAsyncResult ar)
{
int dataCount = 0;
byte[] buffer;
try
{
if (_client != null && _client.Client != null)
{
dataCount = _client.Client.EndReceive(ar);
}
if (dataCount > 0)
{
try
{
buffer = new byte[dataCount];
Array.Copy(_inBuffer, buffer, dataCount);
if (DataReceived != null)
{
DataReceived(buffer);
}
}
catch (Exception exc)
{
if (exc is System.Net.Sockets.SocketException)
{
Disconnect();
return;
}
}
_client.Client.BeginReceive(_inBuffer, 0, _inBuffer.Length, SocketFlags.None, InternalDataReceived, null);
}
}
catch
{
Disconnect();
}
}
I found another way to do it. Hope this helps someone else.
Basically I just ended up using the NetworkStream class. You can get an instance by calling TcpClient.GetStream(). If you use a using block with GetStream your connection will get closed after the using. This is why I'm not using it in my example because I need the connection to stay alive.
MSDN NetworkStream.Read
My example code:
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Client.Connect(IPAddress.Parse("192.168.100.5"), 8000);
//Task.Run(() => ReadData(client));
Task.Run(() => ReadDataLoop(client));
client.Client.Send(Encoding.ASCII.GetBytes("{\"TID\":1111,\"blabla\":{}}"));
while (true)
{
}
}
private static void ReadDataLoop(TcpClient client)
{
while (true)
{
if (!client.Connected)
break;
string xxx = "";
xxx = ReadData(client);
Console.WriteLine(xxx);
}
}
private static string ReadData(TcpClient client)
{
string retVal;
byte[] data = new byte[1024];
NetworkStream stream = client.GetStream();
byte[] myReadBuffer = new byte[1024];
StringBuilder myCompleteMessage = new StringBuilder();
int numberOfBytesRead = 0;
do
{
numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);
myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
}
while (stream.DataAvailable);
retVal = myCompleteMessage.ToString();
return retVal;
}

ASync TCP Client/Server issue

I have this Server method called when client connected:
class Server {
protected override void clientIn(TcpClient client)//Called when a Client comes in
{
NetworkStream stream = client.GetStream();
byte[] y = new byte[client.ReceiveBufferSize];
objectState state = new objectState();
state.buffer = y;
state.user = client;
stream.BeginRead(y, 0, y.Length, read, state);
}
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
byte[] buffer = state.buffer;
TcpClient client = state.user;
int byte=client.GetStream().EndRead(ar);
client.GetStream().BeginRead(buffer, 0, client.ReceiveBufferSize, read, state);
String text = Encoding.ASCII.GetString(buffer);
Console.WriteLine(text);
}
}
class objectState
{
public TcpClient user;
public byte[] buffer;
}
I send two data from two different client and my problem is this:
If I don't execute the instruction "Console.WriteLine(text);", in Console I get 2 times the message "GetData"(it means that I get the data from 2 clients),
but If I execute the instruction "Console.WriteLine(text);", in Console I get 1 time the message "GetData" and below the data just got. It's the first client's data and the second client's data was lost but I don't understand why.
Can you help me?
Thank you for your time
UPDATE:
I edited the code in this way and it works fine , but I don't understand why:
protected override void clientIn(TcpClient client)
{
objectState state = new objectState();
state.user = client;
state.buffer= new byte[client.ReceiveBufferSize];
client.Client.BeginReceive(state.buffer, 0, client.ReceiveBufferSize, 0, new AsyncCallback(read), state);
}
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
TcpClient client = stato.user;
int dataSize = client.Client.EndReceive(ar);
String data = "";
data = Encoding.ASCII.GetString(state.buffer, 0,dataSize);
Console.WriteLine("\n "+data);
client.Client.BeginReceive(stato.buffer, 0, client.ReceiveBufferSize, 0, new AsyncCallback(read), state);
}
I don't understand where was wrong before.
UPDATE 2:
public void read(IAsyncResult ar)
{
Console.WriteLine("GetData");
objectState state = (objectState)ar.AsyncState;
byte[] buffer = state.buffer;
TcpClient client = state.user;
int dataSize=client.GetStream().EndRead(ar);
String text = Encoding.ASCII.GetString(buffer);
state.buffer = new byte[client.ReceiveBufferSize];//new buffer
client.GetStream().BeginRead(state.buffer, 0, client.ReceiveBufferSize, read, state);
Console.WriteLine(text);
}

Async socket confusion

My socket client does not appear to be handling situations where the buffer is full and there is more data to be received.
Here is my on receive method, simple version:
private void Recieve()
{
this._clientSocket.BeginReceive(this._buffer, 0, this._buffer.Length, 0,
new AsyncCallback(OnReceive), this._clientSocket);
}
private void OnReceive(IAsyncResult result)
{
Socket clientSocket = (Socket)result.AsyncState;
int bytesRead = clientSocket.EndReceive(result);
this.Recieve();
string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
}
This doesn't handle situations where there is more data to be received at all. So then I tried this (http://msdn.microsoft.com/en-us/library/bew39x2a.aspx):
private string receivedString = string.Empty;
private void OnReceive(IAsyncResult result)
{
Socket clientSocket = (Socket)result.AsyncState;
int bytesRead = clientSocket.EndReceive(result);
if (bytesRead > 0)
{
receivedString += Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
this.Recieve();
}
else
{
ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), this.receivedString);
this.receivedString = string.Empty;
}
}
But the problem i'm having with this is that when bytesRead > 0 and I call BeginReceive again I do not get another callback. Did I make some kind of mistake ?
Thanks
In the first code, you have a race condition. Consider:
private void OnReceive(IAsyncResult result)
{
Socket clientSocket = (Socket)result.AsyncState;
int bytesRead = clientSocket.EndReceive(result);
this.Recieve();
string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
}
You call Receive again, which could overwrite buffer before you send the data to your HandleDataReceived method. I think you want to move that Receive call to after you've converted the data:
private void OnReceive(IAsyncResult result)
{
Socket clientSocket = (Socket)result.AsyncState;
int bytesRead = clientSocket.EndReceive(result);
string data = Encoding.ASCII.GetString(this._buffer, 0, bytesRead);
ThreadPool.QueueUserWorkItem(new WaitCallback(this.HandleDataReceived), data);
this.Recieve();
}
In the second case, you never read 0 bytes because the socket is waiting for data. If there is no data, Socket.Receive will block until there is data available, or until the connection is closed. BeginReceive is waiting for data.

Categories