0

サーバーから複数のクライアントに書き込もうとすると、空の文字列が書き続けられます。私は自分のコードと、サーバーが実行中のすべてのクライアントに書き込むことができる間にクライアントがサーバーに書き込むことができる複数のクライアント サーバー アプリを共有しています。クライアントがサーバーに書き込みを行っても問題ありません。しかし、サーバーはそうではありません:(

サーバーコード:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Collections;

namespace ServerGui
{
    public partial class Form1 : Form
    {
        TcpListener tcpListen;
        Thread listenThread;
        String read = "";
        ArrayList collect = new ArrayList();
        int counter = 0;
        ArrayList NS = new ArrayList();
        TcpClient general = null;
        readonly ManualResetEvent mre = new ManualResetEvent(false);

        public Form1()
        {
            InitializeComponent();
        }

        private void connectServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tcpListen = new TcpListener(IPAddress.Any, 3000);
            listenThread = new Thread(new ThreadStart(ListenForClients));
            listenThread.Start();
            connectServerToolStripMenuItem.Enabled = false;
        }

        public void ListenForClients()
        {
            tcpListen.Start();

            while (true)
            {

                TcpClient client = tcpListen.AcceptTcpClient();
                collect.Insert(counter, client);
                general = (TcpClient)collect[counter];
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate { textBox1.AppendText(client.Client.LocalEndPoint.ToString() + "  Connected.");
                    textBox1.AppendText(Environment.NewLine); }));
                }
                else
                {
                    textBox1.AppendText(client.Client.LocalEndPoint.ToString() + "  Connected.");
                    textBox1.AppendText(Environment.NewLine);
                }
                Thread clientThread = new Thread(new ParameterizedThreadStart(Reader));
                clientThread.Start(collect[counter]);
                Thread clientThread1 = new Thread(new ParameterizedThreadStart(Writer));
                clientThread1.Start(collect[counter]);
                counter++;
            }
        }
        public void Reader(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream clientStream = tcpClient.GetStream();
            StreamReader sr = new StreamReader(clientStream);
            while (true)
            {
                try
                {
                    read = sr.ReadLine();
                }
                catch
                {
                    if (textBox1.InvokeRequired)
                    {
                        textBox1.Invoke(new MethodInvoker(delegate
                        {
                              textBox1.AppendText(tcpClient.Client.LocalEndPoint.ToString() +
 " disconnected.");
                            textBox1.AppendText(Environment.NewLine);
                        }));
                    }
                    else
                    {
                        textBox1.AppendText(tcpClient.Client.LocalEndPoint.ToString() + " disconnected.");
                        textBox1.AppendText(Environment.NewLine);
                    }
                    return;
                }
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate
                    {
                        textBox1.AppendText("<" +         tcpClient.Client.LocalEndPoint.ToString() + "> saying: " + read);
                        textBox1.AppendText(Environment.NewLine);
                    }));
                }
                else 
                {
                    textBox1.AppendText("<" + tcpClient.Client.LocalEndPoint.ToString() + "> saying: " + read);
                    textBox1.AppendText(Environment.NewLine);
                }
            }

            tcpClient.Close();
        }

        public void Writer(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream ns = tcpClient.GetStream();
            mre.WaitOne();
            while (true)
            {
                StreamWriter sw = new StreamWriter(ns);

                    string str = textBox2.Text;
                    sw.WriteLine(str);
                    sw.Flush();

                if (textBox2.InvokeRequired)
                {
                    textBox2.Invoke(new MethodInvoker(delegate 
                        {
                            textBox2.Clear();
                        }));
                }
                else
                textBox2.Clear();
                }
            tcpClient.Close();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            mre.Set();
            textBox1.AppendText(textBox2.Text);
            textBox1.AppendText(Environment.NewLine);
            textBox2.Clear();
        }

        private void CheckKeys(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                mre.Set();
                textBox1.AppendText(textBox2.Text);
                textBox1.AppendText(Environment.NewLine);
                textBox2.Clear();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

クライアントコード:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace ClientGcui
{
    public partial class Form1 : Form
    {
        NetworkStream general = null;
        public Form1()
        {
            InitializeComponent();

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void connectToServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            String str = "";
            TcpClient client = new TcpClient();
            IPEndPoint server = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
            client.Connect(server);
            textBox1.AppendText("Connected to server");
            textBox1.AppendText(Environment.NewLine);
            NetworkStream clientStream = client.GetStream();
            general = clientStream;
            StreamReader sr = new StreamReader(clientStream);
            StreamWriter sw = new StreamWriter(clientStream);
            Thread reader = new Thread(new ParameterizedThreadStart(readserver));
            reader.Start(sr);
        }
        public void readserver(object client)
        {
            StreamReader sr = (StreamReader)client;
            string read = "";
            while (true)
            {
                try
                {
                    read = sr.ReadLine();
                }
                catch
                {
                    if (textBox1.InvokeRequired)
                    {
                        textBox1.Invoke(new MethodInvoker(delegate
                        {
                            textBox1.AppendText("Disconnected from Server.");
                            textBox1.AppendText(Environment.NewLine);
                        }));
                    }
                    else
                    {
                        textBox1.AppendText("Disconnected from Server.");
                        textBox1.AppendText(Environment.NewLine);
                    }
                }
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new MethodInvoker(delegate
                    {
                        textBox1.AppendText(sr.ReadLine());
                        textBox1.AppendText(Environment.NewLine);
                    }));
                }
                else
                {
                    textBox1.AppendText(sr.ReadLine());
                    textBox1.AppendText(Environment.NewLine);
                }
                }
            sr.Close();
            }


        private void button1_Click(object sender, EventArgs e)
        {
            StreamWriter sw = new StreamWriter(general);
            sw.WriteLine(textBox2.Text);
            sw.Flush();
            textBox1.AppendText(textBox2.Text);
            textBox1.AppendText(Environment.NewLine);
            textBox2.Clear();
        }

        private void CheckKeys(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                StreamWriter sw = new StreamWriter(general);
                sw.WriteLine(textBox2.Text);
                sw.Flush();
                textBox1.AppendText(textBox2.Text);
                textBox1.AppendText(Environment.NewLine);
                textBox2.Clear();
            }
        }
    }
}
4

1 に答える 1

2

'textBox1'、'textbox2'、'button1'とは何ですか。このコードには、アプリケーション固有のコンポーネント名は1つもないようです。これは、経験豊富な開発者が投稿をすばやく確認できるようにするためのものです。ここに投稿する前に、コンポーネント名を意味のあるものに編集していないのはなぜですか?あなたの英語が悪いわけではありません(私はそれを理解することができました)、あなたの質問は十分に明確です。

とにかく、あなたのライターはtextbox2の読み取りをInvoke()しておらず、textBox2をクリアした最初のライターがレースに勝ち、他のすべてのライターを詰め込みます。

..そしてCheckKeysで、あなたはmreに信号を送り、レースに勝ったライターがそれを読む機会を得る前に、textbox2をクリアして実行しています。

とにかく、使用するシンクロオブジェクトが間違っているmreをどこでリセットしたかわかりません。

マルチスレッドコードを軽視することはできません。あなたはそれを正しくしなければなりません。

ライタースレッドとの通信にはいくつかの可能性があります。

1)ロックで保護された参照カウントオブジェクトを使用して、すべてのライターがそれを完了するまで、textbox2からの送信テキストを保持します。これは、ライターが何人いるかを知っていることを意味します。現在、追跡していないものです。これに伴う問題は、ライターが、refCountがインクルードするように初期化されたすべての「hold」インスタンスのrefCountを決定せずに終了してはならないことです。私はあなたがこれを正しく理解するだろうとは思わない。

2)オブジェクトを使用して、textbox2からの送信テキストを保持します。また、このインスタンスをタイムアウトキューに送信します。このキューは、参照をたとえば10分間保持します。このキューまでに、すべてのライターが確実にそれを使用します。これは合理的なアプローチです。

3)オブジェクトを使用して、各ライターのtextbox2からの送信テキストを保持し、生産者/消費者キューの異なるコピーを各ライターに送信します。これは、クライアントが接続および切断するときに最新の状態に保つ必要があるライターのベクトルが必要であることを意味します。

4)他の3つを書くときに考えた4番目の方法がありましたが、今はそれを忘れています。

私は(2)で行きます-何かが機能しない可能性が最も低いです。

ああ-忘れて、すべてのクライアントスレッドに信号を送ります。MREを使用している場合、どこでリセットしますか?すべてのクライアントが内容を読み、再び待機しようとしていることをどのように知ることができますか?それはできません。これが、コードにresetEventがない理由だと思います。どこに配置すればよいかわかりません。

GC言語を使用している場合は、各ライターに独自のBlockingCollectionを指定し、各テキストオブジェクトへの参照をすべてのライターにキューに入れるのが最も簡単で安全な場合があります。ここでも、接続時に新しいエントリが挿入され、切断時に削除される(スレッドセーフな)ライターのコレクションに戻ります。スレッドセーフなコレクションを使用している場合でも、メインスレッドがテキストオブジェクトrefを発行しようとするため、奇妙な例外を予期してキャッチする必要があります。まだコレクションから自分自身を削除することに完全に取り掛かっていないために切断したばかりの作家に。

また、ライターごとのスレッドは少しやり過ぎです。最大の場合 クライアントの場合は、書き込みにthreadPoolを使用することをお勧めします。その場合、必要なのは1つの'SeverClientSocket'クラスで、独自の読み取りスレッド、追加するメインスレッド用のqueueUpForWrite()メソッド、および呼び出すプールスレッド用のwriteQueue()メソッドがあります。

于 2012-04-15T08:44:43.243 に答える