C# 数据为动态类型时TCP服务器未正确接收
我正在开发一个简单的TCP服务器应用程序,它从流接收数据并将其存储在列表中 每次连接发送一条消息时,我已成功获取数据。我的问题似乎是在从命令行使用telnet进行测试时。我将开始打字,程序将根据我的打字速度抓取一到两个字符,然后将不再从该流接收任何内容。我真不知道为什么。如果我在stream.DataAvailable循环中放入一个thread.sleep,那么它将获得更多的字符,但会再次停止。感谢您的帮助。我的班级如下:C# 数据为动态类型时TCP服务器未正确接收,c#,tcp,.net-4.0,tcpclient,networkstream,C#,Tcp,.net 4.0,Tcpclient,Networkstream,我正在开发一个简单的TCP服务器应用程序,它从流接收数据并将其存储在列表中 每次连接发送一条消息时,我已成功获取数据。我的问题似乎是在从命令行使用telnet进行测试时。我将开始打字,程序将根据我的打字速度抓取一到两个字符,然后将不再从该流接收任何内容。我真不知道为什么。如果我在stream.DataAvailable循环中放入一个thread.sleep,那么它将获得更多的字符,但会再次停止。感谢您的帮助。我的班级如下: public class TCPServer { private
public class TCPServer
{
private TcpListener listener;
public List<string> messages;
public TCPServer(IPAddress ip, int port)
{
try
{
messages = new List<string>();
listener = new TcpListener(ip, port);
listener.Start();
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
private void ClientConnected(IAsyncResult ar)
{
TcpClient client;
try
{
client = listener.EndAcceptTcpClient(ar);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
return;
}
try
{
NetworkStream stream = client.GetStream();
string message = "";
while (!stream.DataAvailable)
{
}
while (stream.DataAvailable)
{
byte[] readBytes = new byte[65536];
stream.Read(readBytes, 0, readBytes.Length);
message += Encoding.ASCII.GetString(readBytes).TrimEnd('\0');
}
if (message != null)
{
messages.Add(message);
message = "";
}
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
public void Stop()
{
listener.Stop();
}
}
公共类TCPServer
{
私有TcpListener侦听器;
公开列表信息;
公共TCP服务器(ip地址ip,int端口)
{
尝试
{
消息=新列表();
侦听器=新的TcpListener(ip,端口);
listener.Start();
BeginAcceptTcpClient(ClientConnected,listener);
}
捕获(例外情况除外)
{
Console.WriteLine(“错误:+ex.Message”);
}
}
私有无效客户端连接(IAsyncResult ar)
{
TCP客户机;
尝试
{
client=listener.endAcceptCpcClient(ar);
}
捕获(例外情况除外)
{
Console.WriteLine(“错误:+ex.Message”);
返回;
}
尝试
{
NetworkStream=client.GetStream();
字符串消息=”;
而(!stream.DataAvailable)
{
}
while(stream.DataAvailable)
{
字节[]readBytes=新字节[65536];
stream.Read(readBytes,0,readBytes.Length);
message+=Encoding.ASCII.GetString(readBytes.TrimEnd('\0');
}
如果(消息!=null)
{
消息。添加(消息);
message=“”;
}
BeginAcceptTcpClient(ClientConnected,listener);
}
捕获(例外情况除外)
{
Console.WriteLine(“错误:+ex.Message”);
}
}
公共停车场()
{
listener.Stop();
}
}
读取循环非常不正确
您误解了DataAvailable
没有告诉您将到达多少字节。它会给你一个下限,并可能在任何时候说0。循环将提前中止。使用DataAvailable
几乎总是不正确的
这将一事无成,而且是一个繁忙的等待,这将给您带来危险:
while (!stream.DataAvailable)
{
}
正确的阅读方法是简单地调用read
。您需要使用Read
中的返回值来查看已到达的字节数。修剪零是不正确的(你不能以这种方式接收零),而且一次黑客攻击应该再次引起心理上的危险!这不可能是正确的方法
插座很难安装正确。不要进行可疑的黑客攻击,这只会增加非确定性故障的可能性。因此,我通过深入研究NetworkStream类,设法解决了这个问题。在来自BeginReceiveTcpClient的回调中,我从tcpclient提取了网络流,以便可以访问BeginReceive异步方法。相关代码如下:
private void ClientConnected(IAsyncResult ar)
{
byte[] readBytes = new byte[65536];
TcpClient client;
try
{
client = listener.EndAcceptTcpClient(ar);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
return;
}
try
{
NetworkStream stream = client.GetStream();
stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream);
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
private void ReadStream(IAsyncResult ar)
{
try
{
NetworkStream stream = (NetworkStream)ar.AsyncState;
int bytesRead = stream.EndRead(ar);
content += Encoding.ASCII.GetString(buffer, 0, bytesRead);
dataProcessor.ProcessData(messages);
stream.BeginRead(buffer, 0, buffer.Length, ReadStream, stream);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
如果这不是正确的方法(我相信),你能指出正确的方法吗?这并没有真正回答问题。好吧,它回答了为什么它不起作用。您可能应该尝试设置一个读取循环。如果您的协议是基于行的,您可以尝试StreamReader.ReadLine。在web上搜索套接字教程(不包含单词DataAvailable:))。无需在此处重复该内容。DataAvailable是NetworkStreams中的布尔值,而不是整数值usr。所以检查它是真是假肯定会起作用。OP甚至从未在检查要接收多少字节的上下文中使用它。
Socket.DataAvailable
和NetworkStream.DataAvailable
之间存在差异。它可能错误地返回false,导致您停止读取。如果您针对零进行测试,bool和int版本是等效的。如果你理解这个问题,我不确定你是否理解,你会发现他的阅读循环可能会错误地提前中止。根据您的具体操作,检查可用数据可能是安全的,但总是不必要的。取决于网络速度和时间,您可能也会侥幸逃脱,并且不会看到故障,除非非常罕见。你可以称之为幸运,我可以称之为不幸,因为虫子就在那里,最终会攻击@VisualVenti已使用检查NetworkStream.DataAvailable
的应用程序发送了700 MB文件,并且所有数据都已正确发送和接收;)。另外,根据Socket.DataAvailable实际上表明当前有多少数据可读取(已在网络缓冲区中排队)。因此,它不会指示所有数据,而是它目前拥有的数据。所以我不明白为什么Socket.DataAvailable
不好用?