2014-01-23 4 views
0

У меня возникла следующая проблема: я создал простой компонент HTTP-сервера. Сервер должен управляться с помощью кнопок в графическом интерфейсе. Я могу запустить сервер без проблем, но если я хочу остановить сервер, вся программа будет убита. Я думаю, что это ошибка прерывания потока, но я не знаю, как я могу решить эту проблему.Exit Thread и TcpListener в C#

Вот мой код:

public class HttpServer { 
    private int port; 

    public HttpServer(int port) { 
    this.port = port; 
    } 

    public void Listen() { 
    TcpListener listener = new TcpListener(IPAddress.Any, port); 
    listener.Start(); 

    try { 
     while (true) { 
     TcpClient client = listener.AcceptTcpClient(); 
     HttpProcessor processor = new HttpProcessor(client); 
     Thread thread = new Thread(new ThreadStart(processor.Process)); 
     thread.Start(); 
     Thread.Sleep(1); 
     } 
    } 
    catch { } 

    listener.Stop(); 
    } 
} 

public class HttpProcessor { 
    private TcpClient client; 
    private StreamReader reader; 
    private StreamWriter writer; 

    public HttpProcessor(TcpClient client) { 
    this.client = client; 
    this.reader = null; 
    this.writer = null; 
    } 

    public void Process() { 
    reader = new StreamReader(client.GetStream()); 
    writer = new StreamWriter(client.GetStream()); 

    ParseRequest(); 
    // some method calls to process the request and generate the response 
    SendResponse(); 

    client.Close(); 
    } 
} 

public partial class MainForm : Form { 
    private HttpServer server; 
    private Thread servthread; 

    private void Form_Load(object sender, EventArgs e) { 
    server = new HttpServer(8080); 
    } 

    private void Button1_Click(object sender, EventArgs e) { 
    servthread = new Thread(new ThreadStart(server.Listen)); 
    servthread.Start(); 
    Thread.Sleep(1); 
    } 

    private void Button2_Click(object sender, EventArgs e) { 
    servthread.Abort(); 
    } 
} 
+0

Возможно, вам стоит попытаться закрыть и другие объекты правильно, и вы можете подумать, действительно ли вам нужны два потока. – Rafa

+1

Do * not ever * use 'Thread.Abort()'! –

ответ

0

Чтобы сделать все "любопытное" работу "своего рода" правильно:

  1. в HttpServer движение listener переменной из локального вар члену класса
  2. в HttpServer ввести метод:

    public void Stop() { listener.Stop(); }

  3. Измените метод Button2_Click на:

    private void Button2_Click(object sender, EventArgs e) { server.Stop(); servthread.Join(); }

PS: Я полагаю, что это одна из ваших первых проектов, поэтому вместо того, чтобы писать длинный пост о том, как сделать свой материал правильно, я предложил изменения, которые позволят вам продолжить свой проект. Ошибки и проблемы архитектуры могут прийти или не придет) Счастливое обучение.

1

Do не используетсяThread.Abort(), когда-либо! Используйте другие средства связи с нитью, которую он должен остановить, например, WaitHandle или даже флаг private volatile bool stopThread;!

Если вы чувствуете необходимость вызова любых других методов на Thread чем Start и Join вы, вероятно, делаете что-то неправильно, и вы должны думать о вашем дизайне ;-)

Смотреть это: How to: Create and Terminate Threads (C# Programming Guide)


На ваш комментарий о AcceptTcpClient является блокирующим звонком: Да, это так. Однако, как и другие отметили, что и вы можете легко изменить свой класс, чтобы избежать этой проблемы:

public class HttpServer { 
    private int port; 
    private TcpListener listener; // Make the listener an instance member 

    public HttpServer(int port) { 
    this.port = port; 
    this.listener = new TcpListener(IPAddress.Any, port); // Instantiate here 
    } 

    public void Listen() { 
    listener.Start(); 

    try { 
     while (true) { 
     TcpClient client = listener.AcceptTcpClient(); 
     HttpProcessor processor = new HttpProcessor(client); 
     Thread thread = new Thread(new ThreadStart(processor.Process)); 
     thread.Start(); 
     Thread.Sleep(1); 
     } 
    } 
    catch { } 

    listener.Stop(); 
    } 

    public void StopListening() 
    { 
    listener.Server.Close(); 
    } 
} 

Тогда вместо servthread.Abort(); вы бы назвали server.StopListening();.

Вы может нужно обернуть listener.Stop() линию в try/catch, а также, но вы должны попробовать.

+0

'AcceptTcpClient' блокирует вызов, поэтому даже если вы используете' stopThread' 'bool' во время разрыва. Он будет прерываться при приеме одного соединения после того, как значение bool будет установлено на false. Пожалуйста, поправьте меня, если я ошибаюсь. – Sameer

+0

Я улучшил свой ответ. Кстати, ваш дизайн довольно странный, на самом деле. Обычно класс 'HttpServer' создавал бы сам поток, а не какой-то внешний класс создавал бы поток в методе. –

Смежные вопросы