本帖最后由 tqwboy 于 2009-08-08 21:22:37 编辑

解决方案 »

  1.   

    bool isContinue=true;把线程里面的while(true)换成while(IsContinue)再把Dispose()里面的代码剪切到while结束之后需要停止线程是,调用某个方法如stop,里面设置isContinue=false
      

  2.   

               while (true)
                {
                    try
                    {
                        MessageBox.Show("监听开始!");
                        client = listener.AcceptSocket();
                    }
    ---------------------------------
    我的做法是:
    1.为这个类增加一个bool成员,Listening。
    2.上面的while循环改成:while(Listening)
    3.循环内部:
      if(listener.Pending)
         //Accept
      else
         Thread.Sleep(300);
    4.要终止的话,Listening=false;当然,这样做的缺点就是CPU消耗时间会有一定的增加。
      

  3.   


    谢谢你的帮助,问题解决了。
    我看了一下Abort() 的介绍,貌似用这个方法就一定会产生异常信息的,但是这个方法既然存在就一定有它的道理,请问这个方法该在什么时候用呢?使用的时候该做什么处理?该注意些什么?
      

  4.   

    刚刚没有仔细看,实际问题还没有解决。在调试的时候,关闭程序没有发现“程序“[4920] Server.vshost.exe: 托管”已退出,返回值为 0 (0x0)。”这句话,在终止调试后才出现这句,程序这个时候才真正的退出。
      

  5.   

    你可以让线程都去轮询一个全局boolean值判断是否推出,然后在Form的FormClosing中设置这个值,并且检测线程的状态等待线程都退出。
      

  6.   

    如过不用在线程以外控制线程的运行.
    就用ThreadPool吧.比Thread方便10000倍!
    ThreadPool.QueueWorkItem(YourMethod);
      

  7.   


    我已经这样做了,这是新的代码:    public partial class Form1 : Form
        {
            Thread createServer = null;
            ServerThread listener = null;        public Form1()
            {
                InitializeComponent();
            }        //启动服务端监听线程
            private void button1_Click(object sender, EventArgs e)
            {
                createServer = new Thread(new ThreadStart(WaitForConnect));
                  createServer.Start();
            }        private void WaitForConnect()
            {
                listener = new ServerThread();
                listener.StartListening();
            }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                try
                {
                    if (listener != null)
                        listener.Dispose();
                    if (createServer != null)
                        createServer.Abort();                MessageBox.Show("清理完毕1");
                }
                catch
                {} 
            }
        }
        class ServerThread
        {
            int port = 9000; //监听端口号
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");        TcpListener listener = null;
            Socket client = null;        bool listening = true;        public void StartListening()
            {
                listener = new TcpListener(localAddr,port);
                listener.Start();            while (listening)
                {
                    try
                    {                    MessageBox.Show("监听开始!");
                        client = listener.AcceptSocket();                }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.ToString());
                    }            }
                try
                {
                    if (client != null)
                    {
                        client.Close();
                        client = null;
                    }
                    listener.Stop();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
            }        public void Dispose()
            {
                listening = false;
            }
        }
    结果还是不行。当我强制关闭窗口的时候,调试信息为:
    线程 0xc70 已退出,返回值为 0 (0x0)。
    线程 '<无名称>' (0x1748) 已退出,返回值为 0 (0x0)。
    “Server.vshost.exe”(托管): 已加载“D:\编程工具\C#程序\网格\NetGrid\Server\bin\Debug\Server.exe”,符号已加载。
    “Server.vshost.exe”(托管): 已加载“C:\WINDOWS\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll”,未加载符号。
    “Server.vshost.exe”(托管): 已加载“C:\WINDOWS\assembly\GAC_MSIL\mscorlib.resources\2.0.0.0_zh-CHS_b77a5c561934e089\mscorlib.resources.dll”,未加载符号。
    线程 '<无名称>' (0xffc) 已退出,返回值为 0 (0x0)。
    线程 0x12b4 已退出,返回值为 0 (0x0)。当我关闭调试后,就多了句:程序“[3516] Server.vshost.exe: 托管”已退出,返回值为 0 (0x0)。这时程序才真正退出,程序进程才在进程管理器里消失。问题一个个来,郁闷死……
      

  8.   

    感谢大家帮忙,我终于与找到了解决办法,把线程改成后台线程(createServer.IsBackground = true;)就解决这个问题了。但是我不太了解前台线程和后台线程之间的区别,请那位能跟我解释一下吗?网上找的很多资料我都看不太明白。
      

  9.   

    楼主莫想自己解决.肯定会遗留bug.
    Java中有守护线程,C#中有线程池.
    他们都会在程序主线程main结束时自动退出.
    这才是正到
      

  10.   


    请问 
     if(listener.Pending())
        //Accept
     else
        Thread.Sleep(300);
    这段貌似有点错误吧,我认为应该是这样:
     if(!listener.Pending())
        //Accept
     else
        Thread.Sleep(300);
    当没有监听挂起的时候才去监听
      

  11.   

    哈哈,终于找到答案了,一直觉得C#里怎么没有守护线程,原来是后台线程.....
    学习ing
      

  12.   

    看来你不知道Pending()的真正作用,其实换句话说,就是未处理的连接请求的时候,这个方法返回true,否则返回false,这个时候,Accept方法永远不会挂起,即使它是一个阻塞方法。
      

  13.   


    我改了一下我的代码:          if (listener.Pending())
              {
                    MessageBox.Show("监听开始!");
                    client = listener.AcceptSocket();
              }
              else
              {
                    MessageBox.Show("没有挂起!");
                    listening = false;
              }
    我试了一下,当我改成您这样的写法的时候,点击监听摁钮时,发现执行的是MessageBox.Show("没有挂起!")这一段。因为我没有写客户端来测试,所以我现在这样猜想:当执行了listener.Start()后,因为没有客户端连接近来,所以listener.Pending()为false;当有客户端连接进来的时候,listener.Pending()就为true,这时就执行client = listener.AcceptSocket()来接受客户端的连接请求。不知道我理解对了吗?
      

  14.   

    对。
    所以我那个在Pending为false的时候一直执行Thread.Sleep,让出CPU时间。
    当然,执行方法本身要浪费点时间。
      

  15.   

    当时我用这个方法也是不得已,因为在线程阻塞的情况下,执行Abort方法会产生异常,甚至不能完全退出。
      

  16.   

    这是新的更改情况://服务端监听类
            public void StartListening()
            {
                listener = new TcpListener(localAddr, port);
                listener.Start();
                listening = true;            while (listening)
                {
                    try
                    {
                        if (listener.Pending())
                        {
                            MessageBox.Show("监听开始!");
                            client = listener.AcceptSocket();
                        }
                        else
                            Thread.Sleep(300);
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.ToString());
                    }            }            try
                {
                    if (client != null)
                    {
                        client.Close();
                        client = null;
                    }
                    listener.Stop();
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
            }        public void Dispose() //终止循坏监听
            {
                listening = false;
            }//主窗口
           
            //强制退出
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                try
                {
                    if (listener != null)
                        listener.Dispose();                if (createServer != null)
                    {
                        createServer.Abort();
                        MessageBox.Show("终止了createServer");
                    }
                    MessageBox.Show("清理完毕1");
                }
                catch (ThreadAbortException ex)
                {
                    MessageBox.Show(ex.ToString());
                } 
            }这时有个新问题发生。当执行了监听的时候,因为没有客户连接进来,所以在服务端监听类里不断执行着Thread.Sleep(300),这时我强制退出,触发了服务端监听类里的Dispose()方法,使得循环退出。紧接着执行主窗口createServer.Abort()方法来终止线程。这时又弹出异常信息,显示要强制中断服务端监听类里的Thread.Sleep(300)线程。我不是已经退出循环了吗,干嘛Thread.Sleep(300)这个线程不一起终止呢?我取消createServer.Abort()这句后就能正常退出,因为前面我已经把服务端监听类开辟为一个后台线程了。但是现在取消createServer.Abort()这句虽然能退出程序,但是我担心会留下什么后遗症。这个有什么解决办法吗?
      

  17.   

    如果监听线程正在Sleep(300),那么Dispose的后果不会马上出现,循环要稍后一点时间才会终止。
    你可以在Dispose之后插入一个Thread.Sleep(300);这个时候,即使你不使用Abort,线程也会自然终止。
      

  18.   

    好在有循环,没循环就不能用变量标志来控制结束了。另外,如果循环线程里有阻塞方法的话用标志来控制也不太好,可能出现等很长时间的问题。 我就用 Abort(),再加个 Jion(时间),catch 里直接 return
      

  19.   

    可以用一个 bool的类型的变量去做个判断  然后执行listener.Dispose();
      
      

  20.   

    abort用于暴力终止线程,一般使用try语块来包着形如:try {th.Abort();}catch(){}
      

  21.   

    使用信号量就行啦。
     private static EventWaitHandle ewh_exception = new EventWaitHandle(false, EventResetMode.ManualReset); while (true)
                {
                    try
                    {
    if(ewh_exception.waitOne(0,false))
    {
    ewh_exception.reset();
    break;
    }
                        if (listener.Pending())
                        {
                            MessageBox.Show("监听开始!");
                            client = listener.AcceptSocket();
                        }
                        else
                            Thread.Sleep(300);
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.ToString());
                    }            }
    如果你想结束,先ewh_exception。set();跳出循环之后,你在把socket释放。
      

  22.   

    使用 信号量是个 传统可靠的方法建议你去看 《UNix网络编程》经典哦里面讲了很多你程序里的很多异常,不全是线程造成的你的线程处理不正常,也造成了些网络错误产生的异常
      

  23.   

    C#做socket? 学习下 呵呵~
      

  24.   

    你把线程设置为后台线程,isbackground = true ,看看
      

  25.   

    其实把线程的属性设置成这样的可以了。isbackground = true。