Service 传入TCP连接的云服务挂起

Service 传入TCP连接的云服务挂起,service,tcp,Service,Tcp,我正在开发一个云服务工作者角色,用于从许多仪器收集数据。这些仪器大约每分钟随机报告一次数据。服务本身不是性能关键型的,不需要是异步的。当连接尝试失败时,仪器可以在一小时内重新发送数据 我已经为我的云服务尝试了几种实现,包括: 但他们迟早都会挂断我的云服务器,有时会在一小时内挂断。 我怀疑我的代码有问题。我在我的代码中有很多日志记录,但我没有收到任何错误。服务只是停止接收传入的连接 在Azure门户中,服务似乎运行良好。没有错误日志,没有可疑的cpu使用情况等 如果我重新启动服务,它将再次正常运行

我正在开发一个云服务工作者角色,用于从许多仪器收集数据。这些仪器大约每分钟随机报告一次数据。服务本身不是性能关键型的,不需要是异步的。当连接尝试失败时,仪器可以在一小时内重新发送数据

我已经为我的云服务尝试了几种实现,包括:

但他们迟早都会挂断我的云服务器,有时会在一小时内挂断。 我怀疑我的代码有问题。我在我的代码中有很多日志记录,但我没有收到任何错误。服务只是停止接收传入的连接

在Azure门户中,服务似乎运行良好。没有错误日志,没有可疑的cpu使用情况等

如果我重新启动服务,它将再次正常运行,直到下次挂起

如果有人能帮我,我将不胜感激

public class WorkerRole : RoleEntryPoint
{
    private LoggingService _loggingService;

    public override void Run()
    {
        _loggingService = new LoggingService();

        StartListeningForIncommingTCPConnections();
    }

    private void StartListeningForIncommingTCPConnections()
    {
        TcpListener listener = null;

        try
        {
            listener = new TcpListener(RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WatchMeEndpoint"].IPEndpoint);

            listener.Start();

            while (true)
            {
                _loggingService.Log(SeverityLevel.Info, "Waiting for connection...");

                var client = listener.AcceptTcpClient();

                var remoteEndPoint = client.Client != null ? client.Client.RemoteEndPoint.ToString() : "Unknown";

                _loggingService.Log(SeverityLevel.Info, String.Format("Connected to {0}", remoteEndPoint));

                var netStream = client.GetStream();
                var data = String.Empty;

                using (var reader = new StreamReader(netStream, Encoding.ASCII))
                {
                    data = reader.ReadToEnd();
                }

                _loggingService.Log(SeverityLevel.Info, "Received data: " + data);

                ProcessData(data); //data is processed and stored in database (all resources are released when done)

                client.Close();

                _loggingService.Log(SeverityLevel.Info, String.Format("Connection closed for {0}", remoteEndPoint));
            }
        }
        catch (Exception exception)
        {
            _loggingService.Log(SeverityLevel.Error, exception.Message);
        }
        finally
        {
            if (listener != null)
                listener.Stop();
        }
    }

    private void ProcessData(String data)
    {
        try
        {
            var processor = new Processor();
            var lines = data.Split('\n');

            foreach (var line in lines)
                processor.ProcessLine(line);

            processor.ProcessMessage();
        }
        catch (Exception ex)
        {
            _loggingService.Log(SeverityLevel.Error, ex.Message);

            throw new Exception(ex.InnerException.Message);
        }
    }
}
我刚才做了一个奇怪的观察:

我最近查看了日志,在过去30分钟内没有任何仪器连接,这表明服务已关闭

我通过自己编写的TCP客户端连接到该服务,并上传了一些测试数据

这很有效

当我再次检查日志时,我的测试数据已存储

奇怪的是,其他4台仪器几乎同时连接并成功发送数据

为什么在我连接测试客户机之前,他们不能自己连接

另外,.csdef中的此设置对InputEndpoint IdleTimeOutingMinutes有什么作用

===============================================

编辑:

从几天前开始,我的云服务一直在成功运行

不幸的是,今天早上最后一个日志条目来自以下行:

_loggingService.Log(SeverityLevel.Info, String.Format("Connected to {0}", remoteEndPoint));
在此之后,无法进行其他连接。即使是从我自己的测试TCP客户端也没有得到任何错误,但是没有存储任何数据,也没有新的日志

这使我认为以下代码导致服务挂起:

var netStream = client.GetStream();
var data = String.Empty;

using (var reader = new StreamReader(netStream, Encoding.ASCII))
{
    data = reader.ReadToEnd();
}
我读过StremReader的ReadToEnd可以挂起来的地方。这可能吗

我现在将这段代码更改为:

int i;
var bytes = new Byte[256];
var data = new StringBuilder();
const int dataLimit = 10;
var dataCount = 0;

while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
{
    data.Append(Encoding.ASCII.GetString(bytes, 0, i));

    if (dataCount >= dataLimit)
    {
        _loggingService.Log(SeverityLevel.Error, "Reached data limit");
        break;
    }

    dataCount++;
}
另一种解释可能是数据库中挂着什么东西。我使用SqlConnection和SqlCommand类读取和写入数据库。我总是在最后阻塞后关闭连接

SqlConnection和SqlCommand应该有默认超时,对吗

===============================================

编辑:

在进一步调试之后,我发现当服务没有响应时,它挂起在这行代码上:

while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
经过一番挖掘,我发现NetStream类及其读取方法实际上可能会挂起。尽管微软宣称并非如此

我现在已将代码更改为:

Thread thread = null;

var task = Task.Factory.StartNew(() =>
{
   thread = Thread.CurrentThread;

   while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
   {
      // Translate data bytes to a ASCII string.
      data.Append(Encoding.ASCII.GetString(bytes, 0, i));
   }

   streamReadSucceeded = true;
});

task.Wait(5000);

if (streamReadSucceeded)
{
   //Process data
}
else
{
   thread.Abort();
}                

希望这能阻止绞刑

我想说,部分问题是您正在侦听客户端连接的线程上处理数据。如果另一个客户端启动了某种类型的长时间运行操作,这将阻止新客户端连接。我建议您将处理延迟到工作线程,从而释放侦听器线程以接受新连接

您可能遇到的另一个问题是,如果您的服务抛出错误,那么该服务也将停止接受连接

private static void ListenForClients()
{
    tcpListener.Start();

    while (true)
    {
        TcpClient client = tcpListener.AcceptTcpClient();
        Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
        clientThread.Start(client);
    }
}

private static void HandleClientComm(object obj)
{
    try
    {
        using(TcpClient tcpClient = (TcpClient)obj)
        {
            Console.WriteLine("Got Client...");
            using (NetworkStream clientStream = tcpClient.GetStream())
            using (StreamWriter writer = new StreamWriter(clientStream))
            using(StreamReader reader = new StreamReader(clientStream))
            {        
                //do stuff

            }
        }
    }
    catch(Exception ex)
    {

    }   
}

我试过穿线。不幸的是,它本身并没有解决挂起问题,尽管它可能会帮助服务变得无响应。有关详细信息,请参阅最新编辑。