C# 奇怪的tcp连接场景

C# 奇怪的tcp连接场景,c#,tcp,C#,Tcp,我使用TCP作为保持活动的机制,以下是我的代码: 客户端 TcpClient keepAliveTcpClient = new TcpClient(); keepAliveTcpClient.Connect(HostId, tcpPort); //this 'read' is supposed to blocked till a legal disconnect is requested //or till the server unexpectedly dissapears int numb

我使用TCP作为保持活动的机制,以下是我的代码:

客户端

TcpClient keepAliveTcpClient = new TcpClient();
keepAliveTcpClient.Connect(HostId, tcpPort);

//this 'read' is supposed to blocked till a legal disconnect is requested
//or till the server unexpectedly dissapears
int numberOfByptes = keepAliveTcpClient.GetStream().Read(new byte[10], 0, 10);

//more client code...
服务器

TcpListener _tcpListener = new TcpListener(IPAddress.Any, 1000);
_tcpListener.Start();
_tcpClient = _tcpListener.AcceptTcpClient();
Tracer.Write(Tracer.TraceLevel.INFO, "get a client");

buffer = new byte[10];
numOfBytes = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
if(numOfBytes==0)
{
    //shouldn't reach here unless the connection is close...
}
我只放了相关的代码。。。现在发生的情况是,客户端代码按预期在读取时被阻塞,但是服务器读取立即返回,numobytes等于0,即使我尝试在服务器上执行读取,它也会立即返回。。。但是客户端读取仍然是块!因此,在服务器端,我错误地认为客户端与服务器断开连接,但客户端认为它已连接到服务器。。。有人能说出这是怎么可能的吗?或者我的机制出了什么问题

编辑:失败后,我将以下属性写入日志:

\u tcpClient:\u tcpClient.Connected=true

套接字:(\u tcpClient.Client属性)

_tcpClient.Client.Available=0
_tcpClient.Client.Blocking=true
_tcpClient.Client.Connected=true
_tcpClient.Client.IsBound=true
流详细信息

_tcpClient.GetStream().DataAvailable=false;

正如我所看到的,您正在读取服务器和客户端两侧的数据。您需要将一些数据从服务器写入客户机,以确保您的客户机具有可读取的内容。您可以在下面找到一个小的测试程序(任务只是在同一个程序中运行服务器和客户机)


正如我所看到的,您正在读取服务器和客户端两侧的数据。您需要将一些数据从服务器写入客户机,以确保您的客户机具有可读取的内容。您可以在下面找到一个小的测试程序(任务只是在同一个程序中运行服务器和客户机)


即使正确实施,这种方法也只能检测一些远程服务器故障。考虑中间网络对两台机器进行分区的情况。然后,只有当底层TCP堆栈发送传输级别keep-alive时,系统才会检测到故障。这是对问题的一个很好的描述。这是一个附带问题。指示该功能是可选的


要可靠地确认另一方仍然活着,唯一确定的方法是偶尔在两个端点之间发送实际数据。这将导致TCP及时检测到故障并将其报告回应用程序。

即使正确实施,这种方法也只会检测到一些远程服务器故障。考虑中间网络对两台机器进行分区的情况。然后,只有当底层TCP堆栈发送传输级别keep-alive时,系统才会检测到故障。这是对问题的一个很好的描述。这是一个附带问题。指示该功能是可选的

要可靠地确认另一方仍然活着,唯一确定的方法是偶尔在两个端点之间发送实际数据。这将导致TCP及时检测到故障并将其报告回应用程序

也许有什么东西可以提供线索:只有当10个或更多的客户 同时连接服务器(服务器侦听10个或更多端口)

如果您在Windows 7/8上编写此代码,可能会遇到连接限制问题。Microsoft的许可证允许20个并发连接,但措辞非常具体:

[开始->运行->winver,单击“Microsoft软件许可条款”]

3e。设备连接。您最多可以允许20台其他设备访问许可计算机上安装的软件,以便仅使用文件服务、打印服务、Internet信息服务以及Internet连接共享和电话服务

由于您所做的不是文件、打印、IIS、ICS或电话,因此在这些情况下,XP/Vista以前的连接限制可能仍然是10。在代码中暂时将并发连接的限制设置为9,然后查看它是否继续发生

也许有什么东西可以提供线索:只有当10个或更多的客户 同时连接服务器(服务器侦听10个或更多端口)

如果您在Windows 7/8上编写此代码,可能会遇到连接限制问题。Microsoft的许可证允许20个并发连接,但措辞非常具体:

[开始->运行->winver,单击“Microsoft软件许可条款”]

3e。设备连接。您最多可以允许20台其他设备访问许可计算机上安装的软件,以便仅使用文件服务、打印服务、Internet信息服务以及Internet连接共享和电话服务


由于您所做的不是文件、打印、IIS、ICS或电话,因此在这些情况下,XP/Vista以前的连接限制可能仍然是10。在代码中暂时将并发连接的限制设置为9,然后查看它是否继续发生。

我对MSDN注释的解释似乎是预期的行为。如果没有数据,Read方法将返回

考虑到这一点,我认为我应该尝试以指定的间隔发送数据,就像前面的一些建议一样,同时发送某种类型的“超时”。如果在指定的时间间隔内没有看到“ping”,则可能会导致keepalive失败。使用TCP时,您必须记住,不需要仅仅因为看不到数据就认为连接“断开”。您可以完全拔下网络电缆,直到您发送一些数据之前,连接仍然被认为是良好的。发送数据后,您将看到以下两种行为之一。要么您永远看不到响应(侦听器关闭了?),要么您将得到“ack reset”(侦听器不再在该特定套接字上侦听)

备注: 此方法将数据读入缓冲区参数,并返回成功读取的字节数如果没有可读取的数据,则读取方法返回0。读取操作读取尽可能多的可用数据,最多读取大小参数指定的字节数。如果远程主机关闭了连接,则所有连接都可用
class Program
{
    private static Task _tcpServerTask;
    private const int ServerPort = 1000;

    static void Main(string[] args)
    {
        StartTcpServer();
        KeepAlive();

        Console.ReadKey();
    }

    private static void StartTcpServer()
    {
        _tcpServerTask = new Task(() =>
        {
            var tcpListener = new TcpListener(IPAddress.Any, ServerPort);
            tcpListener.Start();

            var tcpClient = tcpListener.AcceptTcpClient();
            Console.WriteLine("Server got client ...");

            using (var stream = tcpClient.GetStream())
            {
                const string message = "Stay alive!!!";

                var arrayMessage = Encoding.UTF8.GetBytes(message);
                stream.Write(arrayMessage, 0, arrayMessage.Length);   
            }

            tcpListener.Stop();
        });

        _tcpServerTask.Start();
    }

    private static void KeepAlive()
    {
        var tcpClient = new TcpClient();
        tcpClient.Connect("127.0.0.1", ServerPort);
        using (var stream = tcpClient.GetStream())
        {
            var buffer = new byte[16];
            while (stream.Read(buffer, 0, buffer.Length) != 0)
                Console.WriteLine("Client received: {0} ", Encoding.UTF8.GetString(buffer));
        }
    }
}