2013-12-17 52 views
1

我正试图捕获特定端口上的所有传入事件。它工作正常,但我认为,我的Socket被阻塞5秒,而stream.Read()正在执行。 stream.Read()忙时,如果有包裹进入,会发生什么情况?我怎么能避免可能的数据丢失?C#在没有busyTimes的情况下在tcp网络中侦听?

public static void Main(string[] args) 
    { 

     System.Console.WriteLine("Testprogramm Connection\n"); 
     //ThreadListener tl = new ThreadListener(); 
     DateTime startTime3 = DateTime.Now; 
     DateTime startTime4 = DateTime.Now; 

     TimeSpan duration3; 
     TimeSpan duration4; 

     while (true) 
     { 
      DataPackage dp = Connection.readEvent(4002, 3000); 

      DateTime EndZeit = DateTime.Now; 
      if (dp.Ip.Equals("192.168.101.3")) 
      { 
       duration3 = EndZeit - startTime3; 
       System.Console.WriteLine("Duration to last receive: " + duration3); 
       startTime3 = DateTime.Now; 
      } 
      if (dp.Ip.Equals("192.168.101.4")) 
      { 
       duration4 = EndZeit - startTime4; 
       System.Console.WriteLine("Duration to last receive: " + duration4); 
       startTime4 = DateTime.Now; 
      } 
      System.Console.WriteLine(); 
     } 
    } 

    ...Connection.cs 
    public static DataPackage readEvent(int port, int size) 
    { 
     DataPackage dp = new DataPackage(); 
     byte[] bytes = new byte[size]; 
     String ip_client = ""; 
     IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[1]; 
     try 
     { 
      System.Console.Write("Wait...:"); 
      listener = new TcpListener(ipAddress, port); 
      listener.Start(); 
      tcpClient = listener.AcceptTcpClient(); 
      tcpClient.NoDelay = true; 
      tcpClient.Client.NoDelay = true; 

      ip_client = tcpClient.Client.RemoteEndPoint.ToString(); 

      stream = tcpClient.GetStream(); 
      DateTime startTime = DateTime.Now; 
      stream.Read(bytes, 0, bytes.Length); 
      DateTime endTime = DateTime.Now; 

      stream.Close(); 
      tcpClient.Close(); 
      listener.Stop(); 
      dp.Data = bytes; 
      dp.setIP(ip_client); 

      System.Console.Write("...received from " + ip_client + " busy:"); 
      TimeSpan duration = endTime - startTime; 
      System.Console.WriteLine(duration.Seconds + "s"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      closeAllConnections(); 
      return null; 
     } 
     return dp; 
    } 

enter image description here

回答

1

我并不感到惊讶,你看到事件间的延迟。在您的readEvent方法中,您正在创建套接字,然后侦听传入连接,然后执行read(),然后关闭所有套接字。需要一点时间来设置您的套接字。如果您创建连接类的套接字成员,执行初始化(创建,侦听和连接),然后在readEvent方法中检索消息,那么这是更好的方法。更奇特的做法可能是排队所有的事件,以便您的连接的客户端可以去拿起它们,但这涉及到一些异步编程。

 public class Connection : IDisposable { 
    private readonly Queue<DataPackage> messages = new Queue<DataPackage>(); 

    public object syncLock = new Object(); 
    public List<DataPackage> GetCurrentMessages() { 
     Monitor.Enter(syncLock); 
     var result = new List<DataPackage>(); 
     try { 
      foreach (var item in messages) { 
       result.Add(item); 
      } 
      messages.Clear(); 
     } finally { 
      Monitor.Exit(syncLock); 
     } 
     return result; 
    } 

    private TcpListener listener; 
    private TcpClient tcpClient; 
    private int bufferSize; 
    private bool running; 
    public void Init(int port, int size) { 
     // not real thread safe here 
     if (running) return; 
     running = true; 
     bufferSize = size; 
     IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[1]; 
     listener = new TcpListener(ipAddress, port); 
     listener.Start(); 
     listener.BeginAcceptSocket(ar => { 
      tcpClient = listener.AcceptTcpClient(); 
      tcpClient.NoDelay = true; 
      listener.EndAcceptTcpClient(ar); 
      var t = new Thread(readEvent); 
      t.Start(); 
     }, null); 
    } 

    private bool shouldRead = true; 
    private void readEvent() { 

     while (shouldRead) { 
      byte[] bytes = new byte[bufferSize]; 

      try { 
       Console.Write("Wait...:"); 

       var ip_client = tcpClient.Client.RemoteEndPoint.ToString(); 

       var stream = tcpClient.GetStream(); 
       DateTime startTime = DateTime.Now; 
       stream.Read(bytes, 0, bytes.Length); 
       DateTime endTime = DateTime.Now; 
       var package = new DataPackage(); // add your stuff in here 

       Monitor.Enter(syncLock); 
       try { 
        messages.Enqueue(package); 
       } finally { 
        Monitor.Exit(syncLock); 
       } 

       System.Console.Write("...received from " + ip_client + " busy:"); 
       TimeSpan duration = endTime - startTime; 
       System.Console.WriteLine(duration.Seconds + "s"); 
      } catch (Exception e) { 
       Console.WriteLine(e.Message); 
      } 
     } 

    } 

    public class DataPackage {} 

    #region IDisposable Members 
    private bool disposed; 
    void Dispose(bool disposing) { 
     if (!disposed) { 
      if (disposing) { 
       shouldRead = false; 
       tcpClient.Close(); 
       listener.Stop(); 
      } 
      //Clean up unmanaged resources 
     } 
     disposed = true; 
    } 
    public void Dispose() { 
     Dispose(true); 
    } 
    #endregion 
} 
+0

你能举个例子吗? –

+0

我曾尝试尽可能提前启动。但没有注意到一些改进。我曾考虑过线程,但我认为使用套接字多次或连接到同一端口的多个套接字可能会有问题... –

+1

我添加了一个可能遵循的示例。我在VS中很快就把它掀起来了,所以它应该可以编译,但它没有完全测试。你应该从中得到想法。 –

0

你的TCP监听器可能正在等待缓冲区填满。

  • 减小缓冲区大小;
  • PUSH bit集发送数据包;或
  • 您的客户正在等待建立一个重要的数据包大小。

要设置缓冲区大小,请使用TcpClient.ReceiveBufferSize属性。

为了避免拖延而等待缓冲区填满时,TcpClient.NoDelay属性设置为true

+0

我无法编辑客户端发送程序,我也需要这个缓冲区大小,以获得整个包。 TcpClient.NoDelay没有改变任何东西 –

+0

你可以增加你的载荷;除非有特定的原因,否则不需要将缓冲区设置为与您计划的有效负载一样大。例如,假设您的最终有效负载为1MB。使缓冲区大小为64KB。你会阅读()20次;将每个收到的部分有效载荷添加到本地缓冲区 – OnoSendai

+0

现在,我获得10秒的忙时间而不是5秒 –

1

我估计没有任何数据丢失。在你的大小写块线程中使用Read方法,直到第一笔数据量到来(甚至1字节)。理论上,如果客户会保持“沉默”,您可以等待无限的时间。如果你想限制的等待时间,使用tcpClient.ReceiveTimeout,像这样:

tcpClient.ReceiveTimeout = 3000; 

于是,就有了一切完全正确的代码,问题是客户保持沉默5秒。

PS:你为什么不使用IPAddress.Any?在某些情况下,此Dns.GetHostEntry(Dns.GetHostName())可能需要很长时间。

var listener = new TcpListener(IPAddress.Any, port); 
+0

感谢您的提示。 –

相关问题