2016-09-18 2 views
0

C# system.net, розеткиNetworkStream.Write данные, похоже, не прибудет на получение сокета

У меня проблема, когда я не могу понять, что я могу делать неправильно.

История, я отправляю данные байта [] приложения из сокета TcpClient в другой сокет TcpClient. Все это отлично работает, пока я не добавлю пользовательский псевдоинтерфейс перед отправкой данных приложения, после чего сбой и отправка, которые изначально работали, терпят неудачу.

Я говорю, что это не так, но на самом деле происходит только то, что только 3 байта все установлено в 0 в считываемом сокете.

Метод Authenticate выполняет следующие действия. Сервер отправляет 1 байт данных (0-85), клиент получает его, обрабатывает его как int, умножает его на 3 и отправляет байт обратно на сервер. Сервер проверяет значение и отправляет другой байт обратно на 1.

Все это, кажется, работает нормально, но вместе данные, отправленные клиентом после аутентификации, по-видимому, не принимаются, всего 3 байта установлены на 0.

Я хочу, чтобы сокет оставался открытым на протяжении всей жизни программы, поэтому я не могу распоряжаться потоком, так как это также будет утилизировать сокет.

Вот полный код для клиента и сервера, в надежде, что кто-то может увидеть мою ошибку или проблему, которую я пропустил.

Код намеренно без проверки ошибок для краткости, и является очень простым, чтобы просто показать проблему.

Обратите внимание, что если оба метода аутентификации просто возвращают true, тогда код работает точно так, как я ожидал бы этого.

Сервер.

class Program 
    { 
     static Random rnd = new Random(Guid.NewGuid().GetHashCode()); 
     static void Main(string[] args) 
     { 
      Process p = Process.Start(@"C:\Users\Teddy\Documents\visual studio 2015\code\Readissue\TheClient\bin\Debug\TheClient.exe"); 

      Console.Title = "Server"; 

      TcpListener lis = new TcpListener(
       new IPEndPoint(
        IPAddress.Any, 4000 
        )); 

      lis.Start(); 

      TcpClient cli = lis.AcceptTcpClient(); 
      NetworkStream ns = cli.GetStream(); 

      if (Authenticate(cli, ns)) 
      { 
       Console.WriteLine("Good!"); 
       // This condition is met 
      } 
      else 
      { 
       Console.WriteLine("Bad!"); 
       Console.ReadLine(); 
       return; 
      } 

      // Wait until Carrier class of client 
      // Sends data 
      while (!ns.DataAvailable) 
      { 
       Thread.Sleep(100); 
      } 
      Console.WriteLine("DataAvailable"); 

      byte[] buffer = new byte[2048]; 
      //bytesread is always the value of 3. 
      int bytesread = ns.Read(buffer, 0, buffer.Length); 
      string sdata = Encoding.ASCII.GetString(buffer).Substring(0, bytesread); 
      Console.WriteLine(sdata); 
      Console.ReadLine(); 

      p.Kill(); 
      p.Close(); 

     } 

     private static bool Authenticate(TcpClient cli, NetworkStream ns) 
     { 
      //return true; 
      byte[] rcv = new byte[1]; 
      int isnd = rnd.Next(0, 85); 
      byte[] snd = new byte[1] { (byte)isnd }; 

      //Sends a random number 
      //and waits for response 
      ns.Write(snd, 0, snd.Length); 
      while (!ns.DataAvailable) 
      { 
       Thread.Sleep(10); 
      } 

      // Expects response to be 
      // random number x 3 
      int br = ns.Read(rcv, 0, rcv.Length); 
      int ircv = rcv[0]; 

      int iok; 
      if (ircv == (isnd * 3)) 
      { 
       // Confirm random number x 3 
       iok = 1; 
       byte[] bok = new byte[1] { (byte)iok }; 
       ns.Write(bok, 0, snd.Length); 
       return true; 
      } 
      else 
      { 
       iok = 0; 
       byte[] bok = new byte[1] { (byte)iok }; 
       ns.Write(bok, 0, snd.Length); 
       return false; 
      } 
     } 

     class Carrier 
     { 
      public double PointX { get; set; } 
      public double PointY { get; set; } 
      public string Comment { get; set; } 

      public Carrier(byte[] bytes) 
      { 
       string[] tmpStrings = Encoding.ASCII.GetString(bytes) 
        .Split('|'); 

       PointX = Convert.ToDouble(tmpStrings[0]); 
       PointY = Convert.ToDouble(tmpStrings[1]); 
       Comment = tmpStrings[2]; 
      } 
     } 
    } 

Client

class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.Title = "Client"; 

      IPEndPoint EP = new IPEndPoint(
        IPAddress.Parse("192.168.1.100"), 4000 
        ); 

      TcpClient cli = new TcpClient(); 
      cli.Connect(EP); 
      if (!cli.Connected) 
      { 
       Console.WriteLine("Not connected!"); 
       return; 
      } 
      Console.WriteLine("Connected!"); 
      NetworkStream ns = cli.GetStream(); 

      if (Authenticate(cli, ns)) 
      { 
       Console.WriteLine("Good!"); 
       // This condition is met 
      } 
      else 
      { 
       Console.WriteLine("Bad!"); 
       return; 
      } 

      // Send data to server 
      Carrier carrier = new Carrier(); 
      string stringtosend = carrier.ToString(); 
      byte[] bytestosend = Encoding.ASCII.GetBytes(stringtosend); 
      ns.Write(bytestosend, 0, bytestosend.Length); 

      Console.WriteLine("Data sent!"); 
      Console.ReadLine(); 

     } 

     private static void UseClient(TcpClient cli, NetworkStream ns) 
     { 
      Console.WriteLine(ns.CanRead); 
     } 

     private static bool Authenticate(TcpClient client, NetworkStream ns) 
     { 
      //return true; 
      byte[] rcv = new byte[1]; 
      while (!ns.DataAvailable) 
      { 
       Thread.Sleep(10); 
      } 

      int br = ns.Read(rcv, 0, rcv.Length); 
      int ircv = rcv[0]; 
      int result = ircv * 3; 
      byte[] snd = BitConverter.GetBytes(result); 
      ns.Write(snd, 0, snd.Length); 

      while (!ns.DataAvailable) 
      { 
       Thread.Sleep(10); 
      } 

      br = ns.Read(rcv, 0, rcv.Length); 

      int iok = rcv[0]; 
      if (iok == 1) 
      { 
       return true; 
      } 
      return false; 
     } 
    } 

    class Carrier 
    { 
     public double PointX { get; set; } 
     public double PointY { get; set; } 
     public string Comment { get; set; } 


     public Carrier() 
     { 
      PointX = 1.00; 
      PointY = 2.00; 
      Comment = "A longer comment string"; 
     } 

     public override string ToString() 
     { 
      return PointX.ToString() + "|" 
       + PointY.ToString() + "|" 
       + Comment; 
     } 
    } 
+0

Вы отправляете код только после того, как отправили одно сообщение. Вам нужен цикл, чтобы остановить завершение кода, который обычно называется BLOCK. Вы можете использовать WAITONE для блокировки. См. Асинхронные примеры msdn на следующей веб-странице: https://msdn.microsoft.com/en-us/library/w89fhyex(v=vs.110).aspx Примечание: пример msdn также завершается после нескольких сообщений. – jdweng

+0

Я был под впечатлением Console.ReadLine(); сохранил код в живых. – TEDSON

+0

Да Readline будет блокироваться, но вы используете синхронные методы, и у вас нет цикла для обработки более одного сообщения. – jdweng

ответ

0

Так как я подозревал, что проблема была в методе Authenticate на стороне клиента. Я отправил int вместо одного байта. Оскорбительная строка кода была.

byte[] snd = BitConverter.GetBytes(result); 

Какой должен быть.

byte[] snd = new byte[1] { (byte)result }; 

Благодарим jdweng за обнаружение ошибки.

PS, спасибо избирателям за ваш интерес, пожалуйста, примите мою искреннюю жалость.

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