我一直在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倍?
或者我这样做错了吗?
答案 0 :(得分:1)
假设每个客户端需要一个单独的线程,并且在给定时间只有一个线程可能与服务器通信(没有重叠),lock
方法中的TcpHandler
就足够了:
// 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);
}
}
}
答案 1 :(得分:0)
我不太清楚为什么你这样做但我在Windows服务中使用了System.Timers(实际上是一组计时器),并且错开了开始(间隔)。
在Elapse事件中,您可以使用锁(myobject){},以便它们不重叠?
吉娜
答案 2 :(得分:0)
我认为您正在使用sleep来管理连接时间..为什么不设置“最大连接延迟”,然后使用BeginConnect
和Timer
来管理连接。
例如
//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();
}