2

我一直在用 C# 编写一个命令行程序,它使用多个连接到同一服务器的 tcp 客户端。每个客户端都驻留在自己的线程中。目前,我正在尝试制定一种有效的方法,在假设 4 个线程之间有效地传播 5 个请求。

我的代码目前如下所示,但我仍然会遇到相互重叠的请求。有谁知道如何有效地防止这些重叠?

// Max connections is 4, interval is 200
// Loop once to give tcp clients chance to connect
var tcpClients = new TcpClient[_maxConnections];

for(int i = 0; i < _maxConnections; i++)
{
    tcpClients[i] = new TcpClient();
    tcpClients[i].Connect(host, port);
}

// Loop again to setup tasks
for(int i = 0; i < _maxConnections; i++)
{
   Task.Factory.StartNew(TcpHandler, tcpClients[i]);

   // Sleep so every task starts separate from each other.
   Thread.Sleep(_interval);
}

然后 TcpHandler 代码如下所示:

public static void TcpHandler(Object o)
{
    // active is already declared
    while(_active)
    {
        var tcpClient = (TcpClient) o;

        // .. do some send and receive...

        Console.WriteLine("Something here..");

        Thread.Sleep(_interval * _maxConnections);
    }
}

所以你可以看到我正在睡觉以在每个正在执行的线程之间提供足够的空间,然后它们仍然重叠。

如何使这些线程并行运行而没有任何重叠,并限制在所有 4 个线程中每秒 5 次?

还是我对这一切都错了?

4

3 回答 3

1

假设每个客户端都需要一个单独的线程,并且在给定时间只有一个线程可能与服务器通信(没有重叠),方法lock中的aTcpHandler就足够了:

// Max connections is 4, interval is 200
// Loop once to give tcp clients chance to connect
var tcpClients = new TcpClient[_maxConnections];
// dedicated lock object
static readonly object lockObject = new object();

然后在你的 TcpHandler 方法中

public static void TcpHandler(Object o)
{
    // active is already declared
    while(_active)
    {
        //DO NON-SOCKET RELATED STUFF HERE
        // ... code ...
        //
        //DO SOCKET RELATED STUFF HERE
        lock(lockObject)
        {
            var tcpClient = (TcpClient) o;

            // .. do some send and receive...

            Console.WriteLine("Something here..");

            Thread.Sleep(_interval * _maxConnections);
        }
    }
}
于 2013-05-01T23:19:28.830 回答
0

我认为您正在使用 sleep 来管理连接时间。为什么不设置“最大连接延迟”,然后使用BeginConnect和 aTimer来处理连接。

例如。

//setup a timer variable
TCPClient connectionOpening;

_connecting = true;
_connected = false;

connectionOpening = tcpClient;
timer.change(5000, Infinite)
tcpClient.BeginConnect(ClientConnectCallback, tcpClient)

void ClientConnectCallback(iasyncresult ar)
{ 
    _timer.change(infinite, infinite);
    TCPClient tcp = (TCPClient)ar.AsyncState;
    try
    {
        //if we have timed out because our time will abort the connect
        tcp.EndConnect(ar);
        _connected = true;
        _connecting = false;
        //we are now connected... do the rest you want to do.
        //get the stream and BeginRead etc.

    }
    catch (Exception ex) // use the proper exceptions IOException , socketException etc
    {
        if (!_connecting)
        {
            //We terminated the connection because our timer ticked.
        }
        else
        {
            //some other problem that we weren't expecting
        }
    }

void TimerTick(object state)
{
    _connecting = false;
    _connected = false;
    connectionOpening.Close();
}
于 2013-05-02T00:45:15.697 回答
0

我不太清楚你为什么要这样做,但我在 Windows 服务中使用了 System.Timers (实际上是一个定时器数组)并且错开了开始(间隔)。

在 Elapse 事件中,也许您可​​以使用 lock(myobject) { } 这样它们就不会重叠?

吉娜

于 2013-05-01T22:45:09.580 回答