2011-12-04 11 views
3

TCPソケットを使用してクライアントサーバーアプリケーションを作成しています。このサーバーはVisual Studio 2010(.NET 4.0)を使用してC#で作成されています。サーバーは複数のクライアント接続を同時に許可するので、私はAsyncを使用しています。スタイル。サーバーはデータベース(MySQL)に接続する必要があり、サーバープログラムが実行されている間はデータベースと対話する必要があります。この理由から私はインターフェイスがフリーズするのを防ぎ、ビジュアルインターフェイスからデータベースにアクセスできるように無限のリスニングループ(クライアントを受け入れる)を実行するためにBackgroundWorkerを使用しています。C#サーバーがフォーカスを失ったときにクライアントが接続した場合のサーバーの終了/クラッシュ

サーバープログラムが重視されない限り、すべてうまくいきます。フォーカスを失う例:サーバープログラムを実行しているPCがスクリーンセーバーを起動し、タスクバーの時計をクリックして時間を表示し、別のウィンドウ(Windowsエクスプローラ、電卓など)を開きます。サーバープログラムがフォーカスを失ってクライアントが接続しようとすると、サーバーは完全に閉じます。 Visual Studioからサーバーを実行している場合、エラーまたは例外はスローされません。リリースされたバージョンのサーバーを実行している場合、Microsoft Windowsは「応答しないプログラミング...」ダイアログを表示します。ここで

は私のコードが構成されている方法です:メインクラスで

変数:メインフォームで

const int portNo = 12345; 
static System.Net.IPAddress localAdd = System.Net.IPAddress.Parse("192.168.1.67"); 
static TcpListener tcpListenerReadWrite = new TcpListener(localAdd, portNo); 

ボタンは、サーバーを起動します:

private void button1_Click(object sender, EventArgs e) 
{ 
    tcpListenerReadWrite.Start(); 
    backgroundWorker1.RunWorkerAsync(); 
} 

バックグラウンドワーカーDoWork機能:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    while (true) 
    { 
     ChatClient clientRead = new ChatClient(tcpListenerReadWrite.AcceptTcpClient()); 
    } 
} 
サーバクラスの

は、コンストラクタは以下の通りである:

public void ReceiveMessage(IAsyncResult asyncResult) 
{ 
    //read received message from client 
} 

つ最終ノート:(1)クライアントがサーバーに接続メッセージがサーバによって受信される

public ChatClient(TcpClient client) //constructor 
{ 
    _client = client; 
    _clientIP = client.Client.RemoteEndPoint.ToString(); 

    //start reading data from the client in a separate thread 
    data = new byte[_client.ReceiveBufferSize]; 
    _client.GetStream().BeginRead(data, 0, Convert.ToInt32(_client.ReceiveBufferSize), ReceiveMessage, client); 
} 

最初に行うことはHelloメッセージのようなサーバーにメッセージを送信することです(2)サーバーをビジュアルインターフェイスに書き込む前にConsoleモードでテストしていましたが、この問題は存在しませんでした。起こりました。もちろん、コンソールモードでは私はBackgroundWorkerを使用しませんでした。

サーバーがクラッシュする理由を教えてください。

+1

私はその動作を再現できません...そのバハビールで最小の作業サンプルを投稿できますか? – DarkSquirrel42

+0

申し訳ありませんが、私はあなたを取得していない、詳細なコードを投稿する必要がありますか、状況のより良い説明が必要ですか? :) – antf

+0

コードサンプル... 1)コードサンプルはエラーを再現する必要があります2)コードサンプルは最小限に抑えてください(これと何の関係もないコードなし) – DarkSquirrel42

答えて

1

私のサーバーがクラッシュしていることがわかりました(クライアントプログラミングに集中していたので、しばらく時間がかかりました。今日はサーバープログラミングに戻りました)。 @ Moo-Juiceが示唆しているように、それはUIへのアクセスに関連する問題です。

  1. サーバが接続するクライアントを待機無限ループに入る
  2. 開始します:実際には、ここでクラッシュを引き起こしていたシナリオです。この無限ループはbackgroundWorkerです。
  3. クライアントがサーバーに接続します。
  4. クライアントが接続しているtextBoxにメッセージを出力します。 //ここに問題があります
  5. ポイント(4)を確立するにはbackgroundWorker.ReportProgressメソッドを使用しています。

は、問題を確認するには、サーバーは、フォーカスがプログラムにない場合は(スクリーン・セーバーは、例えば実行されていない)が、ない焦点はプログラム上にある場合はクラッシュとロギングが動作しているのみをクラッシュします。伐採を中止したときには、問題は解決しました。だから私は問題の原因を知っているが、私はなぜそれがクラッシュを引き起こしているのかわからない。 ReportProgressは、進捗状況をユーザーインターフェイスに報告するために使用するように設計されています。とにかく、私はこれを解決しようとします、特にどこから行くべきか分かります。ケースでは、私はここにログをやっていた方法を見て興味を持っている私が使用した機能は次のとおりです。私を引き起こすので、凝ったが、十分な

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    textBox1.Text += (string)e.UserState; 
    textBox1.Text += Environment.NewLine; 
} 

ナッシング:

private void PrintString(string stringToPrint) 
{ 
    var myForm = Form1.ActiveForm as Form1; 
    myForm.backgroundWorker1.ReportProgress(1, stringToPrint); 
} 

そして、ここではReportProgress機能です頭痛:)すべてのあなたの助けをありがとう。

+0

もう一度手に入りました:)私の関数 'PrintString'の問題は、' form1'を通して別のファイルにある 'backgroundWorker'に到達したことです。まあ、私たちが知っているように、別のスレッドのコンポーネントに触れることは許されておらず、UIスレッドからの 'form1'は、クラッシュを引き起こしました。解決策は、新しいクライアントに接続する際に、 'backgroundWorker'をクライアント作成(' ChatClient')のコンストラクタに渡し、これをグローバルな 'backgroundWorker'変数に保存し、' PrintString'でもう必要ないことです作業員に到達するために 'form1'を得るために、私は単にグローバルなものを使います。 – antf

2

TcpListenerがメインUIスレッドで作成され、バックグラウンドスレッドでは作成されていないことはありますか?あなたはこれがコンソールアプリケーションでは起こらないとあなたは言った。私はあなたが今いくつかのUI要素を持っているので、それは明確なカットではないと思う。

私の提案は、あなたのネットワーキングのALLをUIスレッドの外に移動し、「メイン」クラスではないことです。それを完全に独立させてください。

+0

答えをありがとう。私はすべてのネットワーキングを取り扱うクラスを持っています。メインクラスからすべてのネットワーク関連のものをこのクラスに移動しました。ここで、それらを新しいコンストラクタに挿入しました。今BackgroundWorkerでは、私は新しいコンストラクタを呼び出すNetworkClassからオブジェクトを作成しますが、問題はまだそこにあります。それはあなたが「UIスレッドの外にある」という意味ですか、それとも間違っていますか? – antf

+0

@antf、私の質問は...データ・メンバーがどこにいるのか(例:どんなクラスにあるのか)ではなく、どのスレッドでインスタンス化され使用されているのか。あなたが投稿した例から、それは私にはあまり明確ではありません。なぜこの動作が発生しているのかわかりませんが、UIスレッドとバックグラウンドスレッドのミックスアップが関係していると確信しています。さもなければ、あなたのコンソールアプリケーションもやってしまうでしょう。 :) –

関連する問題