2017-02-10 9 views
1

私は非同期ソケットを使用する方法を学んできましたが、私の質問は信じられないほど簡単だと確信していますが、解決策を見つけるのは本当に苦労しています。私はAsynchronous ServerAsynchronous ClientのMSDNで提供されているコードから始めます。私はコードがどのように動作するか、次の1つの大きな疑問を除いて、クライアントがプログラムの主な機能に戻す文字列をどうやって得るのでしょうか? ReadCallback()関数で文字列が完全にどこに形成されているかを確認します。AsyncCallbackからのデータ取得方法

質問はどのようにして文字列コンテンツの内容をMain()に戻すのですか?私はどこに行きたいかを明確にするためにいくつかのコメントを書きました。ご協力いただきありがとうございます。

非同期サーバー:

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Threading; 

// State object for reading client data asynchronously 
public class StateObject { 
    // Client socket. 
    public Socket workSocket = null; 
    // Size of receive buffer. 
    public const int BufferSize = 1024; 
    // Receive buffer. 
    public byte[] buffer = new byte[BufferSize]; 
// Received data string. 
    public StringBuilder sb = new StringBuilder();  
} 

public class AsynchronousSocketListener { 
    // Thread signal. 
    public static ManualResetEvent allDone = new ManualResetEvent(false); 

    public AsynchronousSocketListener() { 
    } 

    public static void StartListening() { 
     // Data buffer for incoming data. 
     byte[] bytes = new Byte[1024]; 

     // Establish the local endpoint for the socket. 
     // The DNS name of the computer 
     // running the listener is "host.contoso.com". 
     IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[0]; 
     IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

     // Create a TCP/IP socket. 
     Socket listener = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, ProtocolType.Tcp); 

     // Bind the socket to the local endpoint and listen for incoming connections. 
     try { 
      listener.Bind(localEndPoint); 
      listener.Listen(100); 

      while (true) { 
       // Set the event to nonsignaled state. 
       allDone.Reset(); 

       // Start an asynchronous socket to listen for connections. 
       Console.WriteLine("Waiting for a connection..."); 
       listener.BeginAccept( 
        new AsyncCallback(AcceptCallback), 
        listener); 

       // Wait until a connection is made before continuing. 
       allDone.WaitOne(); 
      } 

     } catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 

     Console.WriteLine("\nPress ENTER to continue..."); 
     Console.Read(); 

    } 

    public static void AcceptCallback(IAsyncResult ar) { 
     // Signal the main thread to continue. 
     allDone.Set(); 

     // Get the socket that handles the client request. 
     Socket listener = (Socket) ar.AsyncState; 
     Socket handler = listener.EndAccept(ar); 

     // Create the state object. 
     StateObject state = new StateObject(); 
     state.workSocket = handler; 
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
      new AsyncCallback(ReadCallback), state); 
    } 

    public static void ReadCallback(IAsyncResult ar) { 
     String content = String.Empty; 

     // Retrieve the state object and the handler socket 
     // from the asynchronous state object. 
     StateObject state = (StateObject) ar.AsyncState; 
     Socket handler = state.workSocket; 

     // Read data from the client socket. 
     int bytesRead = handler.EndReceive(ar); 

     if (bytesRead > 0) { 
      // There might be more data, so store the data received so far. 
      state.sb.Append(Encoding.ASCII.GetString( 
       state.buffer,0,bytesRead)); 

      // Check for end-of-file tag. If it is not there, read 
      // more data. 
      content = state.sb.ToString(); 
      if (content.IndexOf("<EOF>") > -1) { 
       // All the data has been read from the 
       // client. Display it on the console. 
       Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
        content.Length, content); 
       // Echo the data back to the client. 
       // AT THIS POINT content SHOULD HAVE THE STRING SENT 
       Send(handler, content); 
      } else { 
       // Not all data received. Get more. 
       handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReadCallback), state); 
      } 
     } 
    } 

    private static void Send(Socket handler, String data) { 
     // Convert the string data to byte data using ASCII encoding. 
     byte[] byteData = Encoding.ASCII.GetBytes(data); 

     // Begin sending the data to the remote device. 
     handler.BeginSend(byteData, 0, byteData.Length, 0, 
      new AsyncCallback(SendCallback), handler); 
    } 

    private static void SendCallback(IAsyncResult ar) { 
     try { 
      // Retrieve the socket from the state object. 
      Socket handler = (Socket) ar.AsyncState; 

      // Complete sending the data to the remote device. 
      int bytesSent = handler.EndSend(ar); 
      Console.WriteLine("Sent {0} bytes to client.", bytesSent); 

      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 

     } catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 
    } 

    public static int Main(String[] args) { 
     StartListening(); 
     // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string. 
     return 0; 
    } 
} 
+1

ソースとデスティネーションは、Unicode文字セットのUTF-16エンコーディングのテキスト用の 'String'データ型を使用するため、転送にUnicodeエンコーディングの1つを使用することを検討してください。 UTF-8( 'Encoding.UTF8')はストリームとファイルに共通です。メモリ内のテキストの場合、UTF-16( 'Encoding.Unicode')は一般的です(.NET、Java、JavaScriptなど)。それ以外の場合、UnicodeからASCIIへの変換は潜在的に損失です。非Unicodeエンコーディングの場合、エンコーダーを['EncoderExceptionFallback'](https://msdn.microsoft.com/en-us/library/system.text.encoderexceptionfallback(v = vs.110))と一緒に使うことができます。 .aspx)。 –

答えて

2

あなたの例では、かなり右に続きます。入力を待つだけです。 return文の前にConsole.ReadLine();を置く:

public static int Main(String[] args) 
{ 
    StartListening(); 
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string. 

    Console.ReadLine(); 
    return 0; 
} 

あなたが入力を印刷したい場合。あなたがコンテンツを持っており、それに何かをしたい場合は

if (bytesRead > 0) { 

    // There might be more data, so store the data received so far. 
    state.sb.Append(Encoding.ASCII.GetString( 
     state.buffer,0,bytesRead)); 

    // Check for end-of-file tag. If it is not there, read 
    // more data. 
    content = state.sb.ToString(); 

    // print the stuff to the console 
    Console.WriteLine(content); 

あなたは、静的クラス変数として宣言することができますし、それをアクセスすることができます:あなたはReadCallback方法bytesin受信をデコードした後だけConsole.WriteLine()を使用主な方法:あなたがReadCallbackから宣言を削除する必要があります。もちろん、

public class AsynchronousSocketListener 
{ 
    public static string content = ""; 


public static int Main(String[] args) 
{ 
    StartListening(); 
    // I want to make string here that has the result from ReadCallback so I can then perform other logic on the string. 

    Console.ReadLine(); 

    // wait until the message has arrive and press enter to jump to this line 
    Console.WriteLine("Now I can do what ever I want with the incoming message: " + content); 
    // just to be able to read it one more time before the program ends ;) 
    Console.ReadLine(); 
    return 0; 
} 

これは非同期であるため、メッセージが到着するのを待たなければならないことに注意する必要があります。しかし、あなたがそこにそれを印刷するなら、それをコンソールで見ることができます。残りはあなた次第です

+0

私はちょっとこれを撃つつもりですが、アイデアに感謝します。 – BigDevJames

+0

ようこそ。問題が発生した場合は、コメントを削除してください。 WinFormsプロジェクトでこの非同期なものを初めて試しました。受信したメッセージがメインを通過せずすぐに終了するので、受信したメッセージを待つ方が簡単です。チャットプログラムを書くことをお勧めします。 –

関連する問題