2009-04-01 11 views
0

私は小さな頭を痛めて解決策を見つけることができませんでした。 ここで問題となるのは、begin-receiveを一度呼び出すことができるということですが、その後はメソッドを何度も何度も呼び出すことができる適切なテクニックを見つけることができません。 結局、接続が行われているにもかかわらず、メッセージは一度だけ受信でき、それ以降は受信できません。非常に緊急なので、助けてください。私はここにコード全体を載せています。すべてのソケットプログラミング

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

namespace WindowsApplication1 
{ 
public partial class lanmessenger : Form 
{ 

    Socket client; 
    Socket newSock, server, hostSock, remote; 


    byte[] receiveBuffer = new byte[1024]; 
    byte[] sendBuffer = new byte[1024]; 

    String dataEntered; 

    StringBuilder textbox1, receivedData, sb; 

    IPEndPoint serverIP, clientIP; 

    [DllImport("user32.dll")] 
    static extern bool HideCaret(IntPtr hWnd); 

    Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    IPAddress localaddress = IPAddress.Parse("127.0.0.1"); 


    public void Receive() 
    { 
     if (remote.Connected) 
      remote.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), remote); 
     else 
      return; 
    } 


    void OnReceivingData(IAsyncResult ar) 
    { 

     remote = (Socket)ar.AsyncState; 

     int recv = remote.EndReceive(ar); 

     receivedData = new StringBuilder(Encoding.ASCII.GetString(receiveBuffer, 0, recv)); 
     //MessageBox.Show(receivedData.ToString(), "received", MessageBoxButtons.OK); 

     sb = new StringBuilder(this.textBox1.Text); 
     sb.AppendLine(receivedData.ToString()); 

     if (textBox1.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate { this.textBox1.Text = sb.ToString(); }); 

     } 
     //Receive();  


     return; 
    } 



    private void Accepted(IAsyncResult ar) 
    { 
     server = (Socket)ar.AsyncState; 
     client = server.EndAccept(ar); 
     /*if (client.Connected) 
      MessageBox.Show("client connected");*/ 

     try 
     { 
      client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), client); 
     } 
     catch (ArgumentException) 
     { 
      MessageBox.Show("arguments incorrect in begin-receive call", "Error", MessageBoxButtons.OK); 
     } 
     catch (SocketException) 
     { 
      MessageBox.Show("error in accessing socket while receiving", "Error", MessageBoxButtons.OK); 
     } 
     catch (ObjectDisposedException) 
     { 
      MessageBox.Show("socket closed while receiving", "Error", MessageBoxButtons.OK); 
     } 
     catch (Exception) 
     { 
      MessageBox.Show("error while receiving", "Error", MessageBoxButtons.OK); 
     } 

    } 

    public void FirstEndPoint() 
    { 
     newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     clientIP = new IPEndPoint(localaddress, 5555); 

     newSock.Bind(clientIP); 
     newSock.Listen(100); 

     try 
     { 
      newSock.BeginAccept(new AsyncCallback(Accepted), newSock); 
     } 
     catch (ArgumentException) 
     { 
      MessageBox.Show("Error in arguments while using begin-accept", "Error", MessageBoxButtons.OK); 
     } 
     catch (ObjectDisposedException) 
     { 
      MessageBox.Show("socket closed while using begin-accept", "Error", MessageBoxButtons.OK); 
     } 
     catch (SocketException) 
     { 
      MessageBox.Show("Error accessing socket while using begin-accept", "Error", MessageBoxButtons.OK); 
     } 
     catch (InvalidOperationException) 
     { 
      MessageBox.Show("Invalid operation while using begin-accept", "Error", MessageBoxButtons.OK); 
     } 
     catch (Exception) 
     { 
      MessageBox.Show("Exception occurred while using begin-accept", "Error", MessageBoxButtons.OK); 
     } 
    } 

    public void CreateThread() 
    { 
     Thread FirstThread = new Thread(new ThreadStart(FirstEndPoint)); 
     FirstThread.Start(); 
    } 

    public lanmessenger() 
    { 
     InitializeComponent(); 
     CreateThread(); 

    } 

    void OnSendingData(IAsyncResult ar) 
    { 
     Socket socket = (Socket)ar.AsyncState; 
     int AmtOfData = socket.EndSend(ar); 
     //MessageBox.Show(AmtOfData.ToString()); 

     return; 
    } 

    public void SendingData(Socket sock, String data) 
    { 
     textbox1.AppendLine(this.textBox2.Text); 

     if (textBox1.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate { this.textBox1.Text = textbox1.ToString(); }); 
     } 


     if (textBox2.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate { this.textBox2.Text = "\0"; }); 
     } 


     sendBuffer = Encoding.ASCII.GetBytes(data); 


     try 
     { 
      sock.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(OnSendingData), sock); 
     } 
     catch (ArgumentException) 
     { 
      MessageBox.Show("arguments incorrect in begin-send call", "Error", MessageBoxButtons.OK); 
     } 
     catch (SocketException ex) 
     { 
      String str1 = "error in accessing socket while sending" + ex.ErrorCode.ToString(); 
      MessageBox.Show(str1, "Error", MessageBoxButtons.OK); 
     } 
     catch (ObjectDisposedException) 
     { 
      MessageBox.Show("socket closed while sending", "Error", MessageBoxButtons.OK); 
     } 
     catch (Exception) 
     { 
      MessageBox.Show("error while sending", "Error", MessageBoxButtons.OK); 
     } 
    } 

    private void OnClientConnect(IAsyncResult ar) 
    { 
     Socket sock = (Socket)ar.AsyncState; 

     try 
     { 
      sock.EndConnect(ar); 
      if (sock.Connected) 
       MessageBox.Show("connected"); 

     } 
     catch (SocketException ex) 
     { 
      MessageBox.Show("Error in accessing socket while using end-connect" + ex.ErrorCode.ToString(), "Error", MessageBoxButtons.OK); 
      return; 

     } 

     if ((sock.Connected) && (dataEntered != "")) 
     { 
      SendingData(sock, dataEntered); 
     } 

    } 



    private void button1_Click(object sender, EventArgs e) 
    { 

     HideCaret(this.textBox1.Handle); 

     textbox1 = new StringBuilder(this.textBox1.Text); 
     dataEntered = this.textBox2.Text; 
     hostSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     serverIP = new IPEndPoint(localaddress, 5555); 


     try 
     { 
      hostSock.BeginConnect(serverIP, new AsyncCallback(OnClientConnect), hostSock); 
     } 
     catch (ArgumentException) 
     { 
      MessageBox.Show("Error in arguments while using begin-connect", "Error", MessageBoxButtons.OK); 
      return; 
     } 
     catch (SocketException) 
     { 
      MessageBox.Show("Error in accessing socket while using begin-connect", "Error", MessageBoxButtons.OK); 
      return; 
     } 
     catch (ObjectDisposedException) 
     { 
      MessageBox.Show("socket closed while using begin-connect", "Error", MessageBoxButtons.OK); 
      return; 
     } 
     catch (InvalidOperationException) 
     { 
      MessageBox.Show("Invalid operation while using begin-connect", "Error", MessageBoxButtons.OK); 
      return; 
     } 

     catch (Exception) 
     { 
      MessageBox.Show("Exception while using begin-connect", "Error", MessageBoxButtons.OK); 
      return; 
     } 

    } 

} 

}

答えて

2

まず、あなたはいくつかのより適切なタグであなたの質問にタグ付けすることもできます。また、これは、非同期TCPクライアントメッセージングのMSDNドキュメントから取得されているため、ここでドキュメントを再度参照してください。

(ローカルのVSヘルプURLで: MSDN Asynchronous Client Socket Example)始まる新しい非同期操作があなたのコールバックメソッドに失敗した受信なぜ

あなたは言及しなかった - あなたはどのようなエラーが表示されますか?

メッセージが正常に受信され、非同期コールバックで処理された場合は、そこから受信を再度呼び出すことができます(コメントアウトしています)。あなたの状態オブジェクト(あなたのケースではリモート)を再利用するならば、バッファとその中に残っている他のオブジェクトをクリアする必要があることに留意してください。

Receiveメソッドでは、状態オブジェクトを初期化し、新しい非同期受信操作のために再び準備する必要があります。

また、私が以前使用していた受信コールバック。その中には、私が取り組んでいるアプリケーションに固有のもの(これが由来するベースクラスのメッセージをエンキューするなど)がかなり速く汚れていますが、役立つかもしれません。

private void ReceiveCallback(IAsyncResult ar) 
    { 
     int bytesRead = 0; 

     try 
     { 
      // receive finished 
      if (ar.IsCompleted) 
      { 
       TcpIpState stateObject = (TcpIpState)ar.AsyncState; 
       bytesRead = stateObject.TcpIpSocket.EndReceive(ar, out seSocketError); 
       if (bytesRead > 0) 
       { 
        foreach (ArraySegment<byte> asBuffer in stateObject.Buffer) 
        { 

          stateObject.SBuilder.Append(
           Encoding.ASCII.GetChars(
           asBuffer.Array, 
           0, 
           asBuffer.Count)); 

        } 
        // Let the owner object know of the received message 
        base.EnqueueMessage(new TcpIpMessage(stateObject.SBuilder.ToString())); 

        // Start a new receive operation 
        stateObject.SBuilder = new StringBuilder(); 
        stateObject.Buffer.Clear(); 
        stateObject.Buffer.Add(new ArraySegment<byte>(new byte[_bufferSize])); 
        stateObject.TcpIpSocket.BeginReceive(
         stateObject.Buffer, 
         SocketFlags.None, 
         new AsyncCallback(ReceiveCallback), 
         stateObject); 
       } 
       else 
       { 
        OnDisconnected(this, new Exception("Bytes returned are 0")); 
        Disconnect(); 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      // Something has gone wrong on a low level portion 
      OnDisconnected(this, e); 
      Disconnect(); 
     } 
    } 
+0

その他のもの:http://msdn.microsoft.com/en-us/library/bew39x2a.aspx – Acron

1

.NETで読んで非同期ソケットを行うための標準的な方法は、受信コールバックの終わりにBeginReceiveを繰り返し呼び出すことです。 Receiveがコメントアウトされている必要があります。そのコールを打ち明けて、すべて正常に動作するはずです。私はあなたのコードの最も詳細な検査をしていないので、何かを見逃しているかもしれませんが、これは間違いなく最初に試すものです。おそらく、あなたがその方法を実装している正確な問題を詳述すれば、もう少しお手伝いできるでしょう。

明らかにそういう点で、.NETでTCP通信を行っている場合は、TcpClientクラスを使用することを強くお勧めします。これにより、下位レベルのソケットの処理が簡単になり、一般的にはTCP通信がプログラマにとってもっとフレンドリーになります!非同期読書「ループ」は、もちろん同じです。また、さまざまな目的でTcpClientクラスを適切に使用する方法については、多くの他のサイト(SOを含む)のMSDNおよびチュートリアル/コードスニペットに関する多くのドキュメントがあります(TcpClientオブジェクトをマルチスレッドまたは再利用したい場合は少し面倒です) 。

+0

TcpClientクラスに同意します。人生をもっと簡単にします(Clientプロパティを使用して低レベルのソケットにアクセスすることもできます) –