I wrote a simple async TcpClient. Here the relevant part of the code:
public class AsyncTcpClient : IDisposable
{
private TcpClient tcpClient;
private Stream stream;
private int bufferSize = 8192;
bool IsReceiving = false;
public event EventHandler<string> OnDataReceived;
public event EventHandler OnDisconnected;
public event EventHandler OnConnected;
public event EventHandler<Exception> OnError;
public bool IsConnected
{
get
{
return tcpClient != null && tcpClient.Connected;
}
}
public AsyncTcpClient() { }
public async Task ConnectAsync(string host, int port, CancellationToken token = default(CancellationToken))
{
try
{
if (IsConnected) Close();
tcpClient = new TcpClient();
if (!tcpClient.ConnectAsync(host, port).Wait(250))
{
throw new TimeoutException();
}
stream = tcpClient.GetStream();
OnConnected?.Invoke(this, EventArgs.Empty);
await Receive();
}
catch (Exception)
{
OnDisconnected?.Invoke(this, EventArgs.Empty);
}
}
public async Task Receive(CancellationToken token = default(CancellationToken))
{
try
{
if (!IsConnected || IsReceiving) throw new InvalidOperationException();
IsReceiving = true;
byte[] buffer = new byte[bufferSize];
while (IsConnected)
{
token.ThrowIfCancellationRequested();
// First time it reads the incoming data, then it hangs here forever
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (bytesRead > 0)
{
byte[] data = new byte[bytesRead];
Array.Copy(buffer, data, bytesRead);
OnDataReceived?.Invoke(this, Encoding.ASCII.GetString(data));
}
buffer = new byte[bufferSize];
}
}
catch (ObjectDisposedException) { }
catch (IOException)
{
throw;
}
finally
{
IsReceiving = false;
}
}
}
On another application I have a TcpListener that waits for connections. After a successful connection, the server sends some data to the client. The data is received correcly from ReadAsync. Then if I try to send more data from the server, the client waits forever in the second call for ReadAsync.
I'm pretty sure the server is working because I receive the SendCallback with the correct bytes sent.
Am I using ReadAsync wrongly?
UPDATE
I add here the complete code of my server:
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 4096;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
public class TcpServerAsync
{
public readonly ConcurrentQueue<String> queue = new ConcurrentQueue<String>();
public ManualResetEvent allDone = new ManualResetEvent(false);
private Boolean _isRunning = true;
public event EventHandler Connected;
public TcpServerAsync(Int32 port)
{
}
public void Start()
{
Thread t = new Thread(Run);
t.Start();
}
public void Run()
{
IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[1];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5000);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(1);
while (_isRunning)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
public void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Connected.Invoke(this, new EventArgs());
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject
{
workSocket = handler
};
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
while (handler.Connected)
{
if (queue.TryDequeue(out String data))
{
try
{
SendData(handler, data);
}
catch (Exception ex)
{
throw;
}
}
Thread.Sleep(0);
}
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
content = state.sb.ToString();
Debug.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
}
}
public void SendData(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
Debug.WriteLine("Sent {0} bytes to client.", bytesSent);
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
}
NetworkStreamfrom theTcpClientand use the async methods on that? And why did you write the code the way you did, such that theConnectAsync()method won't return until the connection has been closed? That's a very confusing design. Not to mention that it would be better for yourReceive()method to follow convention (i.e. have...Asyncin the name), and to not mix the EAP model with the TPL model. But mostly, if you want help with your code, you need to provide a good minimal reproducible example that reproduces the problem. - Peter Duniho