我想使用 StreamReader 和 StreamWriter 通过 TCPClient.NetworkStream 接收和发送数据。代码如下所示:
客户端代码:
using (TcpClient client = new TcpClient())
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001);
client.Connect(localEndPoint);
client.NoDelay = true;
using(NetworkStream stream = client.GetStream())
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.AutoFlush = true;
using (StreamReader reader = new StreamReader(stream))
{
string message = "Client says: Hello";
writer.WriteLine(message);
// If I comment the line below, the server receives the first message
// otherwise it keeps waiting for data
string response = reader.ReadToEnd();
Console.WriteLine(response);
}
;
}
}
}
注意:如果我评论 reader.ReadToEnd();然后服务器接收消息,否则服务器一直等待客户端的数据。 ReadToEnd 是问题吗?
服务器代码异步接受连接,但以同步方式处理数据:
class Program
{
private static AsyncCallback tcpClientCallback;
static void Main(string[] args){
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"),9001);
TcpListener listener = new TcpListener(localEndPoint);
listener.Start();
tcpClientCallback = new AsyncCallback(ConnectCallback);
AcceptConnectionsAysnc(listener);
Console.WriteLine("Started Aysnc TCP listener, press any key to exit (server is free to do other tasks)");
Console.ReadLine();
}
private static void AcceptConnectionsAysnc(TcpListener listener)
{
listener.BeginAcceptTcpClient(tcpClientCallback, listener);
}
static void ConnectCallback(IAsyncResult result)
{
Console.WriteLine("Received a conenct request");
TcpListener listener = (TcpListener)result.AsyncState;
// We are starting a thread which waits to receive the data
// This is not exactly scalable
Task recieveTask = new Task(() => { HandleRecieve(result, listener); });
recieveTask.Start();
AcceptConnectionsAysnc(listener);
}
// This makes a blocking call - that means until the client is ready to
// send some data the server waits
private static void HandleRecieve(IAsyncResult result, TcpListener listener)
{
Console.WriteLine("Waiting for data");
using (TcpClient client = listener.EndAcceptTcpClient(result))
{
client.NoDelay = true;
using (NetworkStream stream = client.GetStream())
{
using (StreamReader reader = new StreamReader(stream))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.AutoFlush = true;
Stopwatch watch = new Stopwatch();
watch.Start();
string data = reader.ReadToEnd();
watch.Stop();
Console.WriteLine("Time: " + watch.Elapsed.TotalSeconds);
Console.WriteLine(data);
// Send a response to client
writer.WriteLine("Response: " + data);
}
}
}
}
}
}
流不会结束,直到它结束closed。目前,客户端和服务器都保持连接open,并且两人都在尝试阅读到最后远离对方——当他们这样做时,就会封闭自己。这是一个僵局:两个都不会到达终点,所以两个都不会关闭(这将允许另一个到达终点)。
Options:
-
使用原始套接字,并让客户端关闭outbound发送后流:
socket.Shutdown(SocketShutdown.Send);
这让server读到完成,这让服务器关闭,这让客户端读到完成;客户端仍然可以读取inbound关闭出站套接字后的流。
使用不同的终止隐喻ReadToEnd
;对于基于文本的协议,行尾是最常见的(因此:ReadLine
);对于二进制协议,消息的长度前缀是最常见的。这允许每一端读取下一条消息,而不必读到流的末尾。在这种情况下,它只会be虽然只有一条消息,但该策略仍然有效。
- 如果您发现上述问题很棘手,请使用不同的协议; http 适合单个请求/响应操作,并且可以通过以下方式在服务器上处理
HttpListener
.
此外,我会非常小心地使用ReadToEnd
在服务器上(甚至ReadLine
) - 这可能是锁定服务器上线程的好方法。如果服务器需要应对高吞吐量和大量连接,那么基于原始套接字的异步IO将是首选。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)