2016-06-04 7 views
0

Я изо всех сил пытался исправить свою ошибку. Мой клиент/сервер, похоже, отлично работает на одном компьютере. Когда код выполняется на другом ПК, по какой-то причине только часть байтов достигает сервера. Кажется, я не могу получить байты, чтобы понять, насколько я стараюсь. Кажется, точка отсечки составляет 367 байт, и она больше не хочет передавать. Если кто-то знает, что я делаю неправильно, решение будет высоко оценено.C# - Сокеты, не принимающие все байты

Заранее благодарен!

Сервер:

using System; 
using System.Data.SQLite; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Text; 
using System.Threading; 

namespace DMAssist 
{ 

    // 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(); 
     // Current URL string 
    } 

    public class asyncserver 
    { 

     public asyncserver() 
     { 
     } 

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

     public static string GetLocalIPAddress() 
     { 
      var host = Dns.GetHostEntry(Dns.GetHostName()); 
      foreach (var ip in host.AddressList) 
      { 
       if (ip.AddressFamily == AddressFamily.InterNetwork) 
       { 
        return ip.ToString(); 
       } 
      } 
      throw new Exception("Local IP Address Not Found!"); 
     } 

     public 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, 25599); 

      // 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 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 byte[] ObjectToByteArray(object obj) 
     { 
      if (obj == null) 
       return null; 

      BinaryFormatter bf = new BinaryFormatter(); 
      MemoryStream ms = new MemoryStream(); 
      bf.Serialize(ms, obj); 
      return ms.ToArray(); 
     } 

     private Object ByteArrayToObject(byte[] arrBytes) 
     { 
      MemoryStream memStream = new MemoryStream(); 
      BinaryFormatter binForm = new BinaryFormatter(); 
      memStream.Write(arrBytes, 0, arrBytes.Length); 
      memStream.Seek(0, SeekOrigin.Begin); 
      Object obj = (Object)binForm.Deserialize(memStream); 
      return obj; 
     } 


     public void ReadCallback(IAsyncResult ar) 
     { 
      String content = String.Empty; 
      String connectedAddress = String.Empty; 
      // Retrieve the state object and the handler socket 
      // from the asynchronous state object. 
      StateObject state = (StateObject)ar.AsyncState; 
      Socket handler = state.workSocket; 
      IPEndPoint remoteIpEndPoint = handler.RemoteEndPoint as IPEndPoint; 
      connectedAddress = remoteIpEndPoint.Address.ToString(); 

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

      if (bytesRead > 0) 
      { 

       Console.WriteLine("Bytes read: " + bytesRead); 

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

       object rawbytes = ByteArrayToObject(state.buffer); 
       netObject recvobject = (netObject)rawbytes; 

       Send(handler, (object)recvobject); 
      } 
    } 

     private void Send(Socket handler, object data) 
     { 
      // Convert the string data to byte data using ASCII encoding. 
      byte[] byteData = ObjectToByteArray(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()); 
      } 
     } 
    } 
} 

Клиент:

using System; 
    using System.Net; 
    using System.Net.Sockets; 
    using System.Threading; 
    using System.Text; 
    using System.Windows.Forms; 
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.IO; 
    using System.Collections; 

    namespace DMAssist 
    { 
     public class asyncsclient { 

      public asyncsclient() 
      { 
      } 

      public byte[] ObjectToByteArray(object obj) 
      { 
       if (obj == null) 
        return null; 

       BinaryFormatter bf = new BinaryFormatter(); 
       MemoryStream ms = new MemoryStream(); 
       bf.Serialize(ms, obj); 
       return ms.ToArray(); 
      } 

      private Object ByteArrayToObject(byte[] arrBytes) 
      { 
       MemoryStream memStream = new MemoryStream(); 
       BinaryFormatter binForm = new BinaryFormatter(); 
       memStream.Write(arrBytes, 0, arrBytes.Length); 
       memStream.Seek(0, SeekOrigin.Begin); 
       Object obj = (Object)binForm.Deserialize(memStream); 
       return obj; 
      } 

      static byte[] GetBytes(string str) 
      { 
       byte[] bytes = new byte[str.Length * sizeof(char)]; 
       System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); 
       return bytes; 
      } 

      static string GetString(byte[] bytes) 
      { 
       char[] chars = new char[bytes.Length/sizeof(char)]; 
       System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length); 
       return new string(chars); 
      } 

      public object sendObject(object outgoingObject, bool expectRecieve) 
      { 
       try 
       { 

        Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
        IPAddress ip = IPAddress.Parse("x.x.x.x"); 
        IPEndPoint remoteEP = new IPEndPoint(ip, 25599); 
        soc.Connect(remoteEP); 

        byte[] byData = ObjectToByteArray(outgoingObject); 

        //Console.WriteLine("Array length:" + byData.Length); 

        soc.Send(byData); 


        if (expectRecieve) 
        { 
         byte[] buffer = new byte[1024]; 
         int iRx = soc.Receive(buffer); 

         object rawbytes = ByteArrayToObject(buffer); 
         netObject recvobject = (netObject)rawbytes; 

         Console.WriteLine("Writing stopped"); 
         soc.Close(); 
         soc.Dispose(); 

         return recvobject; 
        } 
        else 
        { 
         soc.Close(); 
         soc.Dispose(); 

         return ""; 
        } 
       } 
       catch (Exception) 
       { 
        MessageBox.Show("Server unreachable. Make sure server is broadcasting on port 25599 successfully.", "DMAssist Error 0xC1"); 
       } 
       return null; 
      } 
     } 
    } 

ответ

0

Там есть большая разница между UDP сокетами и TCP сокетов. Что вы пытаетесь работать с UDP лучше, потому что этот протокол более ориентирован на пакет. Это означает, что если сервер отправляет определенное количество байтов, клиент «может» получать одно и то же определенное количество байтов или вообще ничего не получать.

Для TCP это другое, потому что это протокол потоковой передачи, который означает, что байты просто отправляются последовательно, так или иначе сервер считает нужным. Обычно он пытается заполнить mtu, и когда вы получите, вы, скорее всего, получите данные в нескольких кусках, которые вы должны добавить. TCP также является ориентированным и надежным. Байты отбираются от клиента к серверу и наоборот и повторно передаются, если ack не получен в свое время. Это означает, что даже пакеты могут на уровне TCP быть получены не в порядке. TCP поместит их вместе. Вы на уровне приложения получите все в порядке.

Совет, который вы получили до сих пор, является правильным, вы должны продолжать звонить. И это пока нечего больше получать. И откуда вы знаете, что больше ничего не получать? Обычно это обнаруживается при получении TCP-сообщения в приеме с длиной 0. Это означает, что сверстник закрыл свой конец сокета и больше не будет отправлять. Это, в свою очередь, означает, что вы можете закрыть свой конец сокета.

+0

Что нужно сделать, чтобы преобразовать это в UDP? Я не очень опытен в сети. –

+0

Различные использования розетки. Вам не нужно принимать, например, потому что удп не имеет понятия о соединении. Если вы действительно начинаете смотреть в UDP, прежде чем использовать TCP, это действительно не плохая идея. Но google немного, чтобы вы поняли концепции лучше. В .NET начинается с UdpClient. –

+0

Хорошо, спасибо! выдумал. –

0

Это дизайн. И это очень распространенная ошибка разработчиков в отношении сокетов.

Чтобы получать данные правильно, вам необходимо продолжать получать данные в цикле, пока не получите необходимое количество байтов. Продолжайте добавлять в буфер приема, пока не получите необходимое количество байтов.

В некоторых реализациях сокетов есть понятие «ждать для всех» (например, MSG_WAITALL), но даже это приведет к возврату частичных данных, если удаленный доступ к нему завершился после отправки.

Код в обороне. Код, как будто отправитель отправляет только один байт за раз. Вы будете в хорошей форме.

+0

Я попытался сделать цикл, чтобы сохранить добавленные байты в общее количество, но по какой-то причине поток истекает всякий раз, когда я запускаю его с помощью цикла. –

1

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

MSDN есть пример о том, как сделать это правильно:

https://msdn.microsoft.com/en-us/library/bew39x2a.aspx?f=255&MSPPError=-2147217396

+0

Сам пример отлично работает для меня, так что, возможно, вы внесли некоторые изменения? – Jotarun

+0

Так работает ли исходный код на вашем компьютере?Если да, укажите свою измененную версию, чтобы мы могли понять, что пошло не так. – Jotarun

+0

Я обновил свой основной пост с моим текущим кодом сервера и клиента. –