2014-01-29 5 views
2

Я пытаюсь узнать, как создать асинхронный tcp-сервер в C#, и у меня есть небольшая проблема с моим кодом.Попытка создать асинхронный tcp-сервер

I tried to modify this code

и вот что я сделал:

public class ClientContext 
{ 
    public TcpClient client { get; set; } 
    public NetworkStream stream { get; set; } 
    public byte[] buffer { get; set; } 
    public string message { get; set; } 
    // public MemoryStream message = new MemoryStream(); 

    public ClientContext() 
    { 
     buffer = new byte[14]; 
     message = ""; 
    } 
} 

public class TCPServer 
{ 

    public TCPServer() 
    { 
     // Setup the server side 
     TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Parse("127.0.0.1"), 14000)); 
     listener.Start(); 
     // Server side ok, wait for client to connect 
     listener.BeginAcceptTcpClient (OnClientAccepted, listener); 

     Console.WriteLine ("Press enter to exit..."); 
     Console.ReadLine(); 
     listener.Stop(); 
    } 

    private void OnClientAccepted (IAsyncResult ar) 
    { 
     // A client connected 
     TcpListener listener = (TcpListener)ar.AsyncState; 

     if (listener == null) 
      return; 

     try { 
      // Create a new client context to store connection infos about dat client 
      ClientContext context = new ClientContext(); 
      context.client = listener.EndAcceptTcpClient (ar); 
      context.stream = context.client.GetStream(); 
      // The client is now ready, read what it has to say 
      context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 
     } finally { 
      listener.BeginAcceptTcpClient (OnClientAccepted, listener); 
     } 
    } 

    private void OnClientRead (IAsyncResult ar) 
    { 
     // The client wants to say something 
     ClientContext context = (ClientContext)ar.AsyncState; 
     context.message = ""; 

     if (context == null) 
      return; 

     try { 
      // Read what it says 
      if(context.stream.CanRead) { 

       do { 

        context.stream.Read (context.buffer, 0, context.buffer.Length); 
        context.message += Encoding.ASCII.GetString (context.buffer); 
        //length -= context.message.Length; 

       } while (context.stream.DataAvailable); // && length < readBuffer.Length 

       OnMessageReceived(context); 
      } 

     } catch (Exception) { 
      context.client.Close(); 
      context.stream.Close(); 
      context = null; 
     } finally { 
      // If we are still connected to the client, read what it has to say... 
      if (context != null) 
       context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 
     } 

    } 

    private void OnMessageReceived (ClientContext context) 
    { 
     // Display what the client said 
     Console.WriteLine ("Message reçue : " + context.message); 
    } 
} 

Проблема в том, у меня есть клиент, который отправляет 50 "привет мир !!" сообщение на сервер, а сервер печатает только 25/26 «привет мир!». в консоли. Я смотрю на сокет, используя SocketSniff, и я увидел, что серверный сокет получил 50 «привет мир!», Поэтому я должен был что-то провалить с моим кодом, но что?

У вас есть идеи?

ответ

1
context.stream.Read (context.buffer, 0, context.buffer.Length); 
context.message += Encoding.ASCII.GetString (context.buffer); 

Здесь вы не проверяете доход от Stream.Read. Read мог бы поместить в буфер один байт, но затем вы декодируете весь буфер, который содержит оставшиеся байты из предыдущих вызовов чтения. Это должно быть:

int bytesRead = context.stream.Read (context.buffer, 0, context.buffer.Length); 
context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead); 

Но проблема у вас другая. Вы делаете опасное сочетание синхронизации и асинхронности с ... неустойчивыми результатами. Вы не должны отправлять синхронизацию. Читайте внутри обратного вызова BeginRead! Вместо этого вы должны вызвать EndRead:

int bytesRead = context.stream.EndRead(ar); 
context.message += Encoding.ASCII.GetString (context.buffer, 0, bytesRead); 
OnMessageReceived(context); 
context.stream.BeginRead (context.buffer, 0, context.buffer.Length, OnClientRead, context); 

Там нет необходимости проверять DataAvailable ни CanRead.

+0

Прежде всего, спасибо за быстрый ответ. Я изменил свой код на основе того, что вы сказали, и он исправил его. Большое спасибо. – Devnunux

 Смежные вопросы

  • Нет связанных вопросов^_^