2012-04-15 104 views
0

我遇到了一个问题,那就是当我尝试从我的服务器写入到我的多个客户端时,它不断写入空字符串。我分享我的代码和它的多客户端服务器应用程序,客户端可以写入服务器,而服务器可以写入所有正在运行的客户端。客户写入服务器安静罚款。但服务器是不是:(Tcp客户端服务器窗体应用程序问题

Server代码:

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(); 
      } 
     } 
    } 
} 

回答

2

什么用 'textBox1的', 'TextBox2中', 'Button1的' 在那里似乎不到风度在这段代码中成为一个特定于应用程序的组件名 - 你知道,这些东西使得经验丰富的开发人员可以快速地浏览帖子,并且很容易理解。为什么在发布之前你没有将组件名称编辑成有意义的内容?你的英语不好,(我可以理解) ,你的问题很清楚。

无论如何,你的作者并没有调用()ing textbox2 read,然后第一个清除textBox2的作者赢得了比赛,然后塞满了所有其他的作家,然后他们什么都不读。

..和在CheckKeys你发出的信号的MRE,然后在一个结算运行TextBox2中比赛,获奖作家甚至得到一个机会读它。

我不能看到你重置MRE它,反正是错误的同步对象使用。

你不能吝啬多线程代码。你必须正确地做。

您的作家线程有一些可能的通信。

1)使用锁保护,引用计数的对象,直到所有的作家都用它做从TextBox2中坚持自己的传出文本。这意味着你知道有多少作家 - 目前你还没有追踪的东西。与此相关的问题是编写者不得退出,而不会退出refCount被初始化为包含的所有'hold'实例的refCount。我怀疑你会得到这个权利。

2)使用对象来保存到您从TextBox2中传出的文本。另外,将这个实例提交给超时队列,该超时队列保存在一个引用上,比如10分钟,届时所有编写者肯定会使用它。这是一个合理的方法。

3)使用对象从TextBox2中坚持自己的传出文本每个作家和生产者 - 消费者队列每个作家提交不同的复制。这意味着你需要一个写作者向量,随着客户端连接和断开,必须保持最新。

4)有,我认为写其他三个时的第四个办法,但我现在已经忘了。

我会与(2) - 最不可能的东西不工作。

哦 - 忘了,发信号通知所有的客户端线程。如果您使用MRE,您将在哪里重置?你怎么知道所有的客户什么时候阅读过东西,并且又要等待?你不能,我怀疑这就是为什么你的代码中没有resetEvent - 你不知道该把它放在哪里。

因此,考虑到你有一个GC语言,给每个作者自己的BlockingCollection并将每个文本对象的引用排列到所有作者可能是最简单和最安全的。同样,我们又回到了一个(线程安全的)作家集合,这些作者集合中有新的条目放在连接上并在断开连接时被删除。即使使用线程安全的集合,您也必须期望并捕获奇怪的异常,因为主线程尝试发出文本对象ref。对刚刚断开连接的作家来说,还没有完全摆脱收藏的束缚。

此外,每个作家的线程有点矫枉过正。最大。客户端,您最好使用threadPool进行写入。您只需要一个'SeverClientSocket'类,它将拥有自己的读取线程,要添加到主线程的queueUpForWrite()方法以及要调用的线程池线程的writeQueue()方法。

+0

好朋友,在阅读完整答案之前,我得告诉你这是我在stackoverflow.com上的第二个问题。我不知道规则,我不知道如何正确格式化代码。我试图尽快摆脱问题,所以我没有任何修改就复制了整个代码。我对此表示歉意。感谢您阅读我的问题并回答问题。希望我能在这里得到我的解决方案。如果我问你你的Facebook,你似乎是一位专家吗? – 2012-04-15 12:08:24

相关问题