2012-04-15 2 views
0

문제가 생겼습니다. 내 서버에서 여러 클라이언트로 쓰기를 시도 할 때 빈 문자열을 쓰는 것을 계속합니다. 서버가 모든 실행중인 클라이언트에 쓸 수있는 동안 내 코드와 클라이언트가 서버에 쓸 수있는 다중 클라이언트 서버 응용 프로그램을 공유하고 있습니다. 클라이언트가 서버에 조용하게 정상적으로 기록합니다. 하지만 서버가 아닌 :(Tcp 클라이언트 서버 양식 응용 프로그램 문제

서버 코드 :

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

클라이언트 코드 :.

'을 textBox1', 'TextBox2를', '단추 1'로 무엇
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

가 dosn't 보인다 이 코드에서 하나의 응용 프로그램 별 구성 요소 이름이 될 수 있습니다. 경험 많은 개발자는 게시물을 빠르게보고 이해하기 쉽습니다. 왜 여기에 게시하기 전에 구성 요소 이름을 의미있는 이름으로 편집하지 않았습니까? 당신의 영어가 나쁘다. , 당신의 질문은 충분히 명확합니다.

어쨌든, 당신의 작가는 textbox2를 읽은 다음에 첫 번째 작가가 textBox2를 없애기 위해 Invoke()를하지 않고, 다른 모든 작가들에게 아무것도주지 않고 읽습니다.

. 그리고 CheckKeys에서 레이스 우승 작가가 읽기 전에 텍스트 상자 2를 지우고 실행 중입니다.

어쨌든 잘못된 싱크로 개체를 사용할 수있는 mre 재설정 위치를 볼 수 없습니다.

다중 스레드 코드를 고려할 수 없습니다. 당신은 그것을 정확하게해야합니다.

작가 스레드와 통신 할 수있는 몇 가지 방법이 있습니다.

1) 잠금으로 보호 된 참조 카운트 된 개체를 사용하여 모든 작성자가 완료 할 때까지 textbox2에서 보내는 텍스트를 유지합니다. 이것은 당신이 얼마나 많은 작가가 있는지를 안다는 것을 의미합니다. 이 문제는 작성자가 refCount가 포함되도록 초기화 된 모든 '보류'인스턴스의 refCount를 디코딩하지 않고 종료해서는 안됩니다. 나는 네가이 권리를 얻는 지 의심 스럽다.

2) 개체를 사용하여 textbox2의 보내는 텍스트를 고정시킵니다. 또한이 인스턴스를 10 분의 참조를 보유하는 시간 초과 대기열에 제출하십시오. 그러면 모든 작성자가이 인스턴스를 확실히 사용합니다. 이것은 합리적인 접근법입니다.

3) 개체를 사용하여 각 작성자의 textbox2에서 나가는 텍스트를 고정하고 생산자 - 소비자 대기열의 다른 복사본을 각 작성자에게 제출합니다. 즉, 클라이언트 연결 및 연결 끊김에 따라 최신 상태를 유지해야하는 작성자 벡터가 필요합니다.

4) 다른 세 가지를 쓸 때 생각한 네 번째 방법이 있지만 지금은 잊어 버렸습니다.

나는 (2) - 최소한 작동하지 않을 가능성이 있습니다.

오, 깜박하고 모든 클라이언트 스레드를 알립니다. MRE를 사용하는 경우 어디에서 재설정 하시겠습니까? 모든 고객이 물건을 읽고 다시 기다릴 때를 어떻게 알 수 있습니까? 당신은 할 수 없습니다, 그리고 이것이 당신이 당신의 코드에 resetEvent를 가지고 있지 않은 이유라고 생각합니다. 당신은 어디에 넣어야할지 모릅니다.

GC 언어가 있다고 가정하면 각 작성자에게 자체 BlockingCollection을 제공하고 각 텍스트 개체에 대한 참조를 모든 작성자에게 대기시키는 것이 가장 쉽고 안전 할 수 있습니다. 다시 말하지만, 우리는 새로운 항목을 연결하고 연결 해제시 제거한 작성기 모음 (스레드로부터 안전함)으로 돌아갑니다. 스레드로부터 안전한 컬렉션을 사용하더라도 주 스레드가 텍스트 개체 ref를 발행하려고하기 때문에 이상한 예외를 예상하고 파악해야합니다. 아직 연결이 끊긴 작가에게 아직 컬렉션에서 자신을 제거하지 못했습니다.

또한 작가 당 스레드는 과도한 공격입니다. 최대 클라이언트의 경우 쓰레드를 쓰려면 threadPool을 사용하는 것이 좋습니다. 하나의 'SeverClientSocket'클래스에는 독자적인 읽기 스레드, 주 스레드가 추가 할 수있는 queueUpForWrite() 메서드 및 풀 스레드가 호출 할 writeQueue() 메서드가 있어야합니다.

+0

글쎄, 당신의 완전한 대답을 읽기 전에, 나는 stackoverflow.com에 내 두 번째 질문입니다 말해야 해. 규칙을 모르겠다. 코드를 올바르게 포맷하는 법을 모르겠다. 가능한 한 빨리 문제를 없애려고 했으므로 수정하지 않고 전체 코드를 복사했습니다. 나는 이것을 사과한다. 내 문제를 읽고 답해 주셔서 감사합니다. 희망이 내 솔루션을 얻을 것이다. 내가 너에게 너의 페이스 북을 물으면 너는 전문가처럼 보인다. –

관련 문제