我正在创建一个“中间人”风格的应用程序,它将网络延迟应用于传输,而不是恶意使用我应该声明。
但是我在数据结构(LinkedList<string> buffer = new LinkedList<string>();
)上遇到了正确的输出机制。
会发生什么:
从clientA将数据读入结构。
if (buffer.First != null && buffer.Last != null)
{
buffer.AddAfter(buffer.Last, ServerRead.ReadLine().ToString());
}
else
buffer.AddFirst(ServerRead.ReadLine().ToString());
使用个人或整体计时器来跟踪何时向ClientB发布数据。 (调整延迟的可调节计时器)
清理免费数据结构节点
if (buffer.First != null)
{
clientWrite.WriteLine(buffer.First.Value.ToString());
clientWrite.Flush();
buffer.RemoveFirst();
}
但是我一直在尝试使用System.Windows.Forms.Timer
创建一个全局计时器来触发一个处理向clientB输出数据的线程。但是我发现这个技术太慢了,即使设置myTimer.Interval = 1;
这会产生并发问题,当清理列表并添加它时,临时解决方案是通过锁定资源但我觉得这是增加数据输出的缓慢性能。
问题: 我需要一些关于解决方案的想法,该解决方案可以将数据存储到数据结构中并对存储的数据应用计时器(如蛋计时器效果),当计时器用完时,它将被发送到其他客户端。
问候,众议院。
答案 0 :(得分:3)
链接列表将起作用,锁定它(如果正确完成)不太可能导致性能不佳。使用ConcurrentQueue可能会好得多。它是线程安全的,因此您不必进行任何明确的阻止。
我建议使用System.Threading.Timer
而不是Windows窗体计时器。但请注意,您仍将被限制在大约15毫秒的分辨率。也就是说,即使定时器间隔为1,您的有效延迟时间也将介于15到25毫秒之间,而不是1毫秒。这就是定时器的实现方式。
此外,由于您希望在指定的时间段内延迟每个项目(我认为这是不变的),您需要一些“当前时间”的概念。我不建议使用DateTime.Now
或其任何变体,因为时间可能会改变。相反,我使用Stopwatch
来获取特定于应用程序的时间。
此外,您还需要一些方法来跟踪项目的发布时间。用于保存项目的类及其发送时间。类似的东西:
class BufferItem
{
public string Data { get; private set; }
public TimeSpan ReleaseTime { get; private set; }
public BufferItem(string d, TimeSpan ts)
{
data = d;
ReleaseTime = ts;
}
}
好。让我们把它们放在一起。
// the application clock
Stopwatch AppTime = Stopwatch.StartNew();
// Amount of time to delay an item
TimeSpan DelayTime = TimeSpan.FromSeconds(1.0);
ConcurrentQueue<BufferItem> ItemQueue = new ConcurrentQueue<BufferItem>();
// Timer will check items for release every 15 ms.
System.ThreadingTimer ReleaseTimer = new System.Threading.Timer(CheckRelease, null, 15, 15);
收到物品:
// When an item is received:
// Compute release time and add item to buffer.
var item = new BufferItem(data, AppTime.Elapsed + DelayTime);
ItemQueue.Add(item);
计时器过程。
void CheckRelease(object state)
{
BufferItem item;
while (ItemQueue.TryPeek(out item) && item.ReleaseTime >= AppTime)
{
if (ItemQueue.TryDequeue(out item))
{
// send the item
}
}
}
这应该表现良好,你不应该有任何并发问题。
如果您不喜欢15毫秒计时器,即使没有任何项目,也可以让计时器一次性完成并让CheckRelease
方法重新初始化它出纸后的下一个发布时间。当然,您还必须在第一次或者队列中没有任何项目时使接收代码初始化。您需要一个锁来同步访问以更新计时器。