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.
Related
Well I'm trying to write a C# server application which will receive files from several clients written in C++ and the main problem is I'm pretty new to C# .Net.
Got managed to write one code for sync socket C# server but couldn't figure out how to receve data for an async socket byte wise and write those to a single file inside OnDataReceive callback.
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
////Original code inside this function
//int iRx = socketData.m_currentSocket.EndReceive(asyn);
//char[] chars = new char[iRx + 1];
//System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
//int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
//System.String szData = new System.String(chars);
//richTextBoxReceivedMsg.AppendText(szData);
////My old code from Sync socket file transfer
//Receive data from client socket till it continues
byte[] bufferData = new byte[1024];
int recvBytesLen = 0;
BinaryWriter bWrite = new BinaryWriter(File.Open(m_strCurrFolder + "File", FileMode.Append));
do
{
recvBytesLen = clientSock.Receive(bufferData, bufferData.Length, 0);
bWrite.Write(bufferData, 0, recvBytesLen);
} while (recvBytesLen > 0);
//Closing file and socket once done
bWrite.Close();
// Continue the waiting for data on the Socket
WaitForData(socketData.m_currentSocket);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
Found this link to be helpful and does my job.
https://code.msdn.microsoft.com/windowsapps/Fixed-size-large-file-dfc3f45d
private static void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket clientSocket = state.WorkSocket;
BinaryWriter writer;
int bytesRead = clientSocket.EndReceive(ar);
if (bytesRead > 0)
{
//If the file doesn't exist, create a file with the filename got from server. If the file exists, append to the file.
if (!File.Exists(fileSavePath))
{
writer = new BinaryWriter(File.Open(fileSavePath, FileMode.Create));
}
else
{
writer = new BinaryWriter(File.Open(fileSavePath, FileMode.Append));
}
writer.Write(state.Buffer, 0, bytesRead);
writer.Flush();
writer.Close();
// Notify the progressBar to change the position.
Client.BeginInvoke(new ProgressChangeHandler(Client.ProgressChanged));
// Recursively receive the rest file.
try
{
clientSocket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch
{
if (!clientSocket.Connected)
{
MessageBox.Show(Properties.Resources.DisconnectMsg);
}
}
}
else
{
// Signal if all the file received.
receiveDone.Set();
}
}
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
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);
}
I'm bringing up a TCP async server using C# and I'm struggling on the right way to receive the correct amount of data from the server.
My question is this one: due to the nature of TCP being a STREAM protocol, there is no delimiter at the end of each message received so the only thing I can do is add at the beginning of the message the upcoming message size and react consequently; the thing is, how can I recv and be sure that I'm not reading the "next" message in the stream?
My pseudo code looks like this:
// client accepted, begin receiving
client.BeginReceive(state.buffer, 0, StateObject.bufferSize, 0, new AsyncCallback(_cbck_Read), state);
private void _cbck_Read(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.clientSocket;
int bytesRead = client.EndReceive(ar);
// if data have been received
if (bytesRead > 0)
{
state.bytesReceived += bytesRead;
// no message header received so far go on reading
if (state.bytesReceived < Marshal.SizeOf(header))
{
client.BeginReceive(state.buffer, 0, StateObject.bufferSize, 0, new AsyncCallback(_cbck_Read), state);
}
// ... go ahead reading
If the first recv does not get the whole message, could the next recv go far beyond the boundaries of the first and possibly add some unwanted bytes to the message I'm actually wanting to read?
Here is how it can be done using "async/await" with some helper extension methods.
Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp);
await s.ConnectTaskAsync("stackoverflow.com", 80);
await s.SendTaskAsync(Encoding.UTF8.GetBytes("GET /\r\n\r\n"));
var buf1 = await s.ReceiveExactTaskAsync(100); //read exactly 100 bytes
Console.Write(Encoding.UTF8.GetString(buf1));
var buf2 = await s.ReceiveExactTaskAsync(100); //read exactly 100 bytes
Console.Write(Encoding.UTF8.GetString(buf2));
public static class SocketExtensions
{
public static Task<int> ReceiveTaskAsync(this Socket socket, byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync<int>(
socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndReceive);
}
public static async Task<byte[]> ReceiveExactTaskAsync(this Socket socket, int len)
{
byte[] buf = new byte[len];
int totalRead = 0;
do{
int read = await ReceiveTaskAsync(socket, buf, totalRead, buf.Length - totalRead);
if (read <= 0) throw new SocketException();
totalRead += read;
}while (totalRead != buf.Length);
return buf;
}
public static Task ConnectTaskAsync(this Socket socket, string host, int port)
{
return Task.Factory.FromAsync(
socket.BeginConnect(host, port, null, null),
socket.EndConnect);
}
public static Task SendTaskAsync(this Socket socket, byte[] buffer)
{
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, socket),
socket.EndSend);
}
}
As you observe, TCP provides no native framing. Worse, the a sync I/O events are reported for each TCP segment received from the network stack, and may not even match the send calls.
While building up the contents of the received stream, you will need to use one of:
fixed length messages, possibly with some leading type discrimination,
explicit length prefix indication, or
an unambiguous message delimeter.
The choice will generally depend on non-technical factors.
if you know the pending length (which you say you do based on protocol header of some sort) then only read the known pending length. IN your case Marshal.Sizeof(header) - state.bytesReceived
I am trying to implement a class that can listen for incoming TCP data. I am trying to do so using tasks.
I have two central methods
private async void ReceiveAsync()
{
while (true)
{
int bytesRead = await Receive();
if (bytesRead > 0)
{
byte[] result = new byte[bytesRead];
Buffer.BlockCopy(_buffer, 0, result, 0, bytesRead);
Console.WriteLine(Encoding.UTF8.GetString(result));
}
}
}
and
private Task<int> Receive()
{
return Task.Run(() =>
{
if (sock.Poll(-1, SelectMode.SelectRead))
if (sock.Available > 0)
return sock.Receive(_buffer, _buffer.Length, SocketFlags.None);
return -1;
}
);
}
In my main program, I call ReceiveAsync() and then send some data down the TCP pipeline, to which the receiver responds. I do get this reply, but now I am caught in an endless loop inside the while(true), and further data sent from the "receiver" is not being received.
There is something completely wrong. What is it?
Try:
int bytesRead;
do {
bytesRead = await Receive();
if(bytesRead > 0) {...}
} while (bytesRead > 0);
i.e. use bytesRead as an exit condition.
Also: you can probably use async here very nicely:
// for illustration ONLY
TaskCompletionSource<int> source = new TaskCompletionSource<int>();
sock.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ar =>
{
try
{
int val = ((Socket)ar.AsyncState).EndReceive(ar);
source.SetResult(val);
}
catch (Exception ex)
{
source.SetException(ex);
}
}, sock);
return source.Task;