Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 数据为动态类型时TCP服务器未正确接收_C#_Tcp_.net 4.0_Tcpclient_Networkstream - Fatal编程技术网

C# 数据为动态类型时TCP服务器未正确接收

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

我正在开发一个简单的TCP服务器应用程序,它从流接收数据并将其存储在列表中

每次连接发送一条消息时,我已成功获取数据。我的问题似乎是在从命令行使用telnet进行测试时。我将开始打字,程序将根据我的打字速度抓取一到两个字符,然后将不再从该流接收任何内容。我真不知道为什么。如果我在stream.DataAvailable循环中放入一个thread.sleep,那么它将获得更多的字符,但会再次停止。感谢您的帮助。我的班级如下:

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
不好用?