2012-02-17 80 views
1

消息之前要通过对我的一个应用程序,我用一段简单的代码,一个TCP连接发送数据:缓冲区被覆盖,可以读取

public void Send(byte[] message) 
{ 
    if (socket != null) 
    { 
     if (stream != null) 
     { 
      stream.Write(message, 0, message.Length); 
      if (receiveThread == null) 
      { 
       StartReceiver(); 
      } 
     } 
    } 
} 

插座是TcpClient类的一个实例,并且该流是关联的流实例。 StartReceiver()启动一个线程,正如该方法所暗示的那样,它接收发送给应用程序的数据。

要接收的数据,我使用:

private void ReceiveLoop() 
{ 
    DataReceivedStruct drs; 
    try 
    { 
     for (; ;) 
     { 
      if (stream != null) 
      { 
       drs = new DataReceivedStruct(); 
       drs.stream = stream; 
       drs.waitHandle = are; 
       stream.BeginRead(readBuffer, 0, readBuffer.Length, DataReceived, drs); 
       Console.WriteLine("Waiting to be allowed to continue"); 
       are.WaitOne(); 
       Console.WriteLine("Allowed, continuing loop"); 
      } 
      else 
      { 
       Thread.Sleep(5); 
      } 
     } 
    } 
    catch (SocketException e) 
    { 
     DispatchRaiseException(e); 
    } 
    catch (Exception e) 
    { 
     DispatchRaiseException(e); 
    } 
} 

再次,所用的流是TcpClient类对象的上述流实例。 readBuffer对象是byte[1024]。给BeginRead回调看起来是这样的:

private void DataReceived(IAsyncResult result) 
{ 
    DataReceivedStruct drs = (DataReceivedStruct)result.AsyncState; 
    NetworkStream used = drs.stream; 
    AutoResetEvent handle = drs.waitHandle; 
    used.EndRead(result); 
    DispatchRaiseReceived(readBuffer); 
    Console.WriteLine("Signalling allowance of continue for loop"); 
    handle.Set(); 
} 

它结束的流读取动作和传中readBuffer数据集。

这在原则上起作用。我可以发送和接收来自应用程序的数据。应用程序的接收端只有一个问题。向应用程序发送消息时,调用BeginRead函数,之后回调触发并结束与EndRead的读取操作,并传递数据以供进一步处理。这适用于一次一条消息。但在第一条消息触发BeginRead后直接发送另一条消息时,它会变得更有趣。接下来会发生的第一条消息的EndRead还没有发生,所以第一条消息的数据被第二条消息覆盖,导致数据不正确。

我应该停止使用BeginRead/EndRead,只是使用阻止Read操作来接收数据?还是有可能锁定流与BeginRead/EndRead,所以第二个消息不会收到,直到第一个消息处理?

+1

而不是使用共享缓冲区('readBuffer'),在'DataReceivedStruct'中声明它 – 2012-02-17 10:34:20

+0

无关紧要,因为流仍会覆盖第二条消息。 – ThaMe90 2012-02-17 10:40:02

+0

不,既然你把它传递给'BeginRead' – 2012-02-17 10:47:41

回答

1

国际海事组织,这里的问题是思考一个循环,因此需要一个继续旗帜。这不会扩展,因为它需要每个连接都有一个线程。

什么你应该做的是:

  • 得到一些数据要发送
  • 开始接收异步(我用ReceiveAsync,但应该的BeginRead工作太)
  • 并退出! (无环)

在回调:

  • 过程的片段(或缓冲它)
  • 开始接收如果必要
  • 和出口!

如果您很乐意替换几个不同的缓冲区(我使用一个小的微池),您可以交换“进程”,以便您可以继续与处理并行读取。但是,你绝对需要读取不同的缓冲区,以防止覆盖数据。这通常只需要异常高读取方案。

如果有帮助,我正在图书馆编写简单的TCP客户机/服务器方案,而不必担心所有蹩脚的实现细节,我打算释放作为开源一次稳定的;包括广泛的对象池/重用,完全异步使用(使用绑定到完成端口的3.5 API)等。

+0

我知道这是一种与环做事的懒办法,但我的目标不是去深由于时间限制而成为整个问题。听取你的图书馆很有意思,但显然,这并不是一个可以看到的选项。无论如何,感谢有趣的选择。 – ThaMe90 2012-02-17 10:36:54

+0

另一方面,我实际上是这样设计的,因为我的应用程序可以有多个到其他实例的TCP连接,因此每个连接需要一个线程。如果它是UDP,我可以看到你的建议工作。 – ThaMe90 2012-02-17 10:38:52

+0

@ ThaMe90不知道为什么需要一个线程。例如,我目前正在进行的工作;已经使用25k入站连接进行了测试,每个客户端与一个组中的多个服务器(服务器间的负载平衡客户端)通信,每个服务器服务于多个TCP绑定;我明确旋转的线程数:零。 – 2012-02-17 10:40:49