C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

スレッドの終了ができない

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■93397 / inTopicNo.1)  スレッドの終了ができない
  
□投稿者/ 名無し (1回)-(2019/12/09(Mon) 22:48:53)

分類:[C#] 

Server側とClientを接続して、Clientを切るとServerを再接続待機状態にする様に考えています。
clientをきるとserverのスレッド処理をAbortしたらエラーが出ます。
どうしたらいいか調べてもわからなかったのでご教授していただけると助かります。

namespace WinSockC
{
    public partial class FomSoch : Form
    {
        private Server m_server = null;

        public FomSoch()
        {
            InitializeComponent();
            this.m_server = new Server();
            this.m_server.ServerStart();
        }

        private void FomSoch_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.m_server.StopSock();
        }
    }
}


namespace WinSockC
{
	class Server
	{
		Encoding ecUni = Encoding.GetEncoding( "utf-16" );
		Encoding ecSjis = Encoding.GetEncoding( "shift-jis" );
		TcpClient server = null;
		TcpListener listener = null;
		Thread threadServer = null;

		private void StartSock() {
			ServerStart();
		}

		public bool ServerStart() {
			try {
				if( listener == null ) {
					IPAddress ipAdd = IPAddress.Parse( "127.0.0.1" );
					listener = new TcpListener( ipAdd, 2001 );
				}
				listener.Start();
				threadServer = new Thread( new ThreadStart( ServerListen ) );
				threadServer.IsBackground = true;
				threadServer.Start();
				return ( true );
			}
			catch( Exception ex ) {
				listener.Stop();
				return ( false );
			}
		}

		private void ServerListen() {
			server = listener.AcceptTcpClient();
			NetworkStream stream = server.GetStream();
			Byte[] bytes = new Byte[1000];
			while( true ) {
				try {
					int intCount = stream.Read( bytes, 0, bytes.Length );
					if( intCount != 0 ) {
						Byte[] getByte = new byte[intCount];
						for( int i = 0; i < intCount; i++ )
							getByte[i] = bytes[i];

						byte[] uniBytes;
						uniBytes = Encoding.Convert( ecSjis, ecUni, getByte );
						string strGetText = ecUni.GetString( uniBytes );
					}
					else {
						StopSock();
						return;
					}
				}
				catch( System.Threading.ThreadAbortException ) {
					return;
				}
				catch( Exception ex ) {
					return;
				}
			}
		}
        
		public void StopSock() {
			CloseServer();
		}

        private void CloseServer()
        {
            if (server != null && server.Connected)
            {
                server.Close();
            }

            if (threadServer != null)
            {
                threadServer.Abort();
            }
		}
	}
}

引用返信 編集キー/
■93398 / inTopicNo.2)  Re[1]: スレッドの終了ができない
□投稿者/ KOZ (66回)-(2019/12/10(Tue) 01:41:27)
2019/12/10(Tue) 02:03:01 編集(投稿者)
No93397 (名無し さん) に返信
> Server側とClientを接続して、Clientを切るとServerを再接続待機状態にする様に考えています。
> clientをきるとserverのスレッド処理をAbortしたらエラーが出ます。
> どうしたらいいか調べてもわからなかったのでご教授していただけると助かります。

ServerListen はループするようにして、スレッドを終了したいときは、listener.Stop します。
すると、AcceptTcpClient が SocketException で異常終了するのでスレッドを終了します。
通信中のクライアントがある場合は、同様に server.Dispose() して通信を中断します。

public void Start() {
    Stop();
    listener = new TcpListener(IPAddress.Any, 2001);
    listener.Start();
    threadServer = new Thread(ServerListen);
    threadServer.Start();
}

public void Stop() {
    if (listener != null) {
        listener.Stop();
        listener = null;
    }
    if (server != null) {
        server.Dispose();
        server = null;
    }
    if (threadServer != null) {
        if (threadServer.IsAlive) {
            threadServer.Join();
        }
        threadServer = null;
    }
}

private void ServerListen() {
    while (true) {
        try {
            server = listener.AcceptTcpClient();
            try {
                /*
                 * server を使って送受信処理
                 */
                server.Close();
            } finally {
                server.Dispose();
                server = null;
            }
        } catch (SocketException e) {
            if (e.SocketErrorCode == SocketError.Interrupted) {
                break;
            }
            throw;
        }
    }
}

引用返信 編集キー/
■93400 / inTopicNo.3)  Re[1]: スレッドの終了ができない
□投稿者/ Azulean (1113回)-(2019/12/10(Tue) 06:09:25)
本筋についてはコメントがついているので、余談として。

■No93397 (名無し さん) に返信
> clientをきるとserverのスレッド処理をAbortしたらエラーが出ます。
>             if (threadServer != null)
>             {
>                 threadServer.Abort();
>             }

「Abort でエラーが出る」のは質問者さんが Abort を呼んでいるからです。
何があったとしても、Thread.Abort を呼んではならないと考えておいてください。
Abort は相手先のスレッドがどんな状態でも強制的に終了させ、ThreadAbortException をスローすることになります。

引用返信 編集キー/
■93402 / inTopicNo.4)  Re[2]: スレッドの終了ができない
□投稿者/ KOZ (67回)-(2019/12/10(Tue) 10:38:17)
No93398 (KOZ) に返信

ちょっと訂正。

            server = listener.AcceptTcpClient();
            try {
                /*
                 * server を使って送受信処理
                 */
                server.Close();
            } finally {
                server.Dispose();
                server = null;
            }

ここは

            server = listener.AcceptTcpClient();
            var tmpServer = server;
            try {
                /*
                 * tmpServer を使って送受信処理
                 */
                tmpServer.Close();
            } finally {
                tmpServer.Dispose();
            }
            server = null;

こうしたほうがいいかも。

私がソケット通信するプログラムを作るときは Socket 使ってバイナリ通信するので
NetworkStream についてよく知らないのですが

「Winsock Programmer's FAQ」
http://www.kt.rim.or.jp/~ksk/wskfaq-ja/

に目を通して

2.8 - Winsock がずっとWSAEWOULDBLOCKばかり返すんですが、何が悪いんでしょう?
2.10 - TCP ソケットを正しく close するにはどうすれば良いのですか?

あたりはチェックしておくと良いです。
特に 2.10 を忘れるとデータが抜ける可能性があります。

引用返信 編集キー/
■93513 / inTopicNo.5)  Re[2]: スレッドの終了ができない
□投稿者/ 名無し (1回)-(2019/12/17(Tue) 04:56:06)
ありがとうございます。
無事出来ました。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ