我写了一个简单的异步TcpClient。这里是代码的相关部分:
data = [
{u'Value': u'nine', u'Key': u'nine'}, {u'Value': u'six', u'Key': u'six'},
{u'Value': u'four', u'Key': u'four'}, {u'Value': u'one', u'Key': u'one'},
{u'Value': u'seven', u'Key': u'seven'}, {u'Value': u'ten', u'Key': u'ten'},
{u'Value': u'two', u'Key': u'two'}, {u'Value': u'three', u'Key': u'three'},
{u'Value': u'five', u'Key': u'five'}, {u'Value': u'eight', u'Key': u'eight'}
]
s = ''
for x in data:
s += x['Value'] + ':' + x['Key'] + ' '
s = s[:-1] #this remove the last space from the string
print(s)
#output
nine:nine six:six four:four one:one seven:seven ten:ten two:two three:three five:five eight:eight
在另一个应用程序中,我有一个等待连接的TcpListener。 连接成功后,服务器会向客户端发送一些数据。从ReadAsync正确接收数据。然后,如果我尝试从服务器发送更多数据,客户端将在第二次调用ReadAsync时永远等待。
我非常确定服务器正在运行,因为我收到发送正确字节的SendCallback。
我是否错误地使用了ReadAsync?
我在这里添加了我服务器的完整代码:
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;
}
}
}
答案 0 :(得分:1)
我查看了您的服务器代码,并进行了一些修改。首先,有一个名为&#34; queue&#34;的变量。我没有理解它的目的,因为你并没有把它排在任何地方,你试图在BeginReceive
方法中阻止它在无限范围内。 while语句阻塞主线程并阻止从客户端接收数据,防止接受其应完成的其他客户端和其他操作。如果你从某个地方将它排队并且想要将出列数据发送到tcp客户端,则可以在收到完成后执行此操作,并且不要为主线程使用无限while循环。我提供了这样的修改方法;
public void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
if (Connected != null)
{
Connected.Invoke(this, new EventArgs());
}
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
BeginReceive(handler);
//while (handler.Connected)
//{
// if (queue.TryDequeue(out String data))
// {
// try
// {
// SendData(handler, data);
// }
// catch (Exception ex)
// {
// throw;
// }
// }
// Thread.Sleep(0);
//}
}
public void BeginReceive(Socket handler)
{
StateObject state = new StateObject
{
workSocket = handler
};
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
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();
if (queue.TryDequeue(out String data))
{
try
{
SendData(handler, data);
}
catch (Exception ex)
{
throw;
}
}
//SendData(handler, content);
Debug.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
}
BeginReceive(handler);
}