我正在编写一个同时运行两个IRC连接的C#程序。 连接是线程化的,每个线程都是这样开始的:
MainThread = new Thread(new ThreadStart(StartMainProcessor));
MainThread.IsBackground = false;
MainThread.Start();
private void StartMainProcessor() {
MainProcessor.Bot.Connect();
//while (true) { }
}
Bot.Connect()看起来像这样(有点删节的版本):
public void Connect() {
try {
Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
}
catch (CouldNotConnectException e) {
Reconnect(true);
return;
}
try {
Client.Listen();
}
catch (Exception e) {
Reconnect(false);
return;
}
}
这可以正常工作,直到机器人断开连接(最终总会发生,这是IRC的本质)。 断开连接时,调用Reconnect(),启动计时器。当该计时器到期时,僵尸程序意味着再次调用Connect()。计时器的原因是IRC服务器有时会拒绝立即重新连接。
但是,一旦Connect()方法结束,线程结束,程序(控制台应用程序)退出。 (Client.Listen()正在阻止)
我之前通过在StartMainProcessor()中添加while(true){}来解决这个问题......但这会占用100%的CPU,我真的更喜欢不同的解决方案。
感谢您的帮助。 :)
答案 0 :(得分:2)
听起来你需要一个信号构造。例如,您可以使用类似AutoResetEvent的内容来阻止调用Reconnect的线程,即调用Reconnect,启动计时器然后阻止线程。然后在计时器过期事件处理程序中设置自动重置事件,以允许线程继续(解除阻塞)并调用Connect。
我不喜欢旋转处理器 - 当你添加无限循环或sleeps in loops时浪费了大量的CPU资源。
答案 1 :(得分:1)
为什么不在Thread.Sleep
内Bot.Reconnect
?这将使你的线程保持活跃状态,并在准备再次呼叫Bot.Connect
时将其唤醒。
答案 2 :(得分:0)
你可能想尝试类似的东西
private bool canExitThread;
private void StartMainProcessor()
{
while (canExitThread)
{
//do the magic here
System.Threading.Thread.Sleep(1); //make sure you allow thread to do the job, otherwise you will get 100 cpu usage
//do the connecting, disconnecting, listening
}
}
您还可以检查客户端是否已连接?如果是这样,那么你应该在主循环内检查它,如果它已断开连接 - 请调用connect方法。
希望能让你了解如何做到这一点。
另请查看下面的文章,这可能会更多地解释一下。 http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx
答案 3 :(得分:0)
这样的事情
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Server
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting server..");
foreach (var connection in new[] {new Connection(TimeSpan.FromSeconds(1)), new Connection(TimeSpan.FromSeconds(1))})
ThreadPool.QueueUserWorkItem(connection.Connect);
Console.WriteLine("Server running. Press Enter to quit.");
Console.ReadLine();
}
}
public class Connection //might be good to implement IDisposable and disconnect on Dipose()
{
private readonly TimeSpan _reConnectionPause;
public Connection(TimeSpan reConnectionPause)
{
_reConnectionPause = reConnectionPause;
}
//You probably need a Disconnect too
public void Connect(object state)
{
try
{
//for testing assume connection success Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
Debug.WriteLine("Open Connection");
}
catch (Exception)
{
//You might want a retry limit here
Connect(state);
}
try
{
//Client.Listen();
//Simulate sesison lifetime
Thread.Sleep(1000);
throw new Exception();
}
catch (Exception)
{
Debug.WriteLine("Session end");
Thread.Sleep(_reConnectionPause);
Connect(state);
}
}
}
}
答案 4 :(得分:0)
我认为你有Main
方法,所以我们为什么不从那里开始:
private static readonly MAX_NUM_BOTS = 2;
static void Main(string[] args)
{
List<Thread> ircBotThreads = new List<Thread>();
for(int numBots = 0; numBots < MAX_NUM_BOTS; numButs++)
{
Thread t = new Thread(()=>{StartMainProcessor();});
t.IsBackground = false;
t.Start();
ircBotThreads.Add(t);
}
// Block until all of your threads are done
foreach(Thread t in ircBotThreads)
{
t.Join();
}
Console.WriteLine("Goodbye!");
}
private static void StartMainProcessor()
{
MainProcessor.Bot.Connect();
}
然后你可以这样做:
// 30 second time out (or whatever you want)
private static readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(30.0);
// specify the maximum number of connection attempts
private static readonly int MAX_RECONNECTS = 10;
public void Connect()
{
bool shouldListen = false;
// This is your connect and re-connect loop
for(int i = 0; i < MAX_RECONNECTS; i++)
{
try
{
Client.Connect(IRCHelper.SERVER, IRCHelper.PORT);
shouldListen = true;
}
catch (CouldNotConnectException e)
{
// It's OK to sleep here, because you know exactly
// how long you need to wait before you try and
// reconnect
Thread.Sleep((long)TIMEOUT.TotalMilliseconds);
shouldListen = false;
}
}
while(shouldListen)
{
try
{
Client.Listen();
}
catch (Exception e)
{
// Handle the exception
}
}
}
这是一个非常粗略的草案,但概念是你一直试图重新连接,直到你失败。一旦你连接,然后你听(我认为你在IRC中听一些东西)并处理数据,直到你决定你不再需要做这项工作。