2016-06-04 3 views
0

나는 실수를 고치기 위해 고심하고 있습니다. 동일한 컴퓨터에서 내 클라이언트/서버가 제대로 작동하는 것 같습니다. 코드가 다른 PC에서 실행될 때 어떤 이유로 바이트 중 일부만 서버에 도달합니다. 얼마나 많은 노력을했는지에 관해서는 바이트를 처리 할 수없는 것 같습니다. 컷오프 포인트가 367 바이트 인 것처럼 보이고 더 이상 전송하지 않으려합니다. 누구든지 내가 뭘 잘못하고 있는지 알고 있다면 해결책을 많이 얻게 될 것이다.소켓이 모든 바이트를 수신하지 못함

미리 감사드립니다.

서버 :

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 소켓 사이에 큰 차이가 있습니다 :

MSDN 제대로이 작업을 수행하는 방법에 대한 예제가 있습니다. 이 프로토콜이 패킷 지향적이기 때문에 UDP로 더 잘 작동 할 것입니다. 즉, 서버가 특정 수의 바이트를 전송하면 클라이언트가 동일한 특정 바이트 수를 수신하거나 전혀 수신하지 못할 수도 있습니다.

TCP의 경우 스트리밍 프로토콜이기 때문에 바이트는 서버가 적합하다고 보는대로 순차적으로 전송된다는 의미이기 때문에 TCP와 다릅니다. 보통 그것은 mtu를 채우기 위해 노력할 것이고 당신이받을 때 당신은 자신을 덧붙여야만하는 다수의 덩어리로 데이터를받을 것입니다. TCP는 또한 연결 지향적이며 신뢰할 수 있습니다. 바이트는 클라이언트에서 서버로 또는 그 반대로 수신되고, ack가 정해진 시간 내에 수신되지 않으면 재전송됩니다. 이것은 심지어 패킷이 TCP 레벨에서 순서가 맞지 않게 수신 될 수 있음을 의미합니다. TCP가 함께 맞습니다. 응용 프로그램 수준에서 모든 것을 순서대로받습니다.

지금까지 얻은 조언은 정확합니다. 계속 전화를 받아야합니다. 그리고 이제는 더 이상받을 것이 없을 때까지. 그리고 더 이상받을 것이 없다는 것을 어떻게 아나요? 보통 길이가 0 인 수신에서 TCP 메시지를 수신하여 감지됩니다. 이는 피어가 소켓의 끝을 닫았으며 더 이상 보내지 않을 것임을 의미합니다. 이것은 차례로 소켓의 끝을 닫을 수 있음을 의미합니다.

+0

이것을 UDP로 변환하려면 무엇이 필요합니까? 나는 네트워킹 경험이별로 없습니다. –

+0

소켓을 다르게 사용합니다. 예를 들어 udp에는 연결 개념이 없으므로 승인 할 필요가 없습니다. UDP를 사용하기 전에 초보자라면 실제로 나쁜 생각이 아닙니다. 그러나 좀 더 주위에 Google을 사용하면 개념을 더 잘 이해할 수 있습니다. UdpClient는 .NET에서 시작됩니다. –

+0

좋아, 고마워! 물건을 알아 냈어. –

0

이것은 의도적으로 설계된 동작입니다. 그리고 개발자가 소켓과 관련하여 만드는 매우 흔한 실수입니다.

데이터를 올바르게 수신하려면 필요한 바이트 수가 나타날 때까지 루프에서 데이터를 계속 수신해야합니다. 필요한 바이트 수를 얻을 때까지 수신 버퍼에 계속 추가하십시오.

일부 소켓 구현에는 "wait for all"플래그 (예 : MSG_WAITALL)의 개념이 있지만 송신 후 연결이 닫히면 부분 데이터가 반환됩니다.

코드를 방어 적으로 사용합니다. 발신자가 한 번에 1 바이트 만 전송하는 것처럼 코딩하십시오. 당신은 좋은 모습이 될 것입니다.

+0

나는 총 바이트 수를 늘리는 루프를 만들려고했지만 어떤 이유로 루프를 실행할 때마다 스레드가 시간 초과됩니다. –

1

코드에서 언급했듯이 더 많은 데이터가있을 수 있으므로 지금까지받은 데이터를 저장합니다. 그러나 나머지 코드는 코드를 가지고 있지 않습니다.

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

+0

예제 자체가 잘 작동하므로 어쩌면 수정 한 것일까 요? – Jotarun

+0

컴퓨터에서 원래 코드가 작동합니까?그렇다면 무엇이 잘못되었는지 파악할 수 있도록 수정 된 버전을 제공해주십시오 .. – Jotarun

+0

메인 서버를 현재 서버 및 클라이언트 코드로 업데이트했습니다. –

관련 문제