2016-04-13 7 views
4

Ich habe Server und Client-Konsole-Anwendungen, die gut kommunizieren sowie eine Zeichenfolge senden. Hier ist der Code ...Wie man Datei über Socket in c sendet #

Server

public static void Main() 
    { 
     try 
     { 
      IPAddress ipAd = IPAddress.Parse("127.0.0.1"); 

      /* Initializes the Listener */ 
      TcpListener myList = new TcpListener(ipAd, 1234); 

      /* Start Listeneting at the specified port */ 
      myList.Start(); 

      Console.WriteLine("The server is running at port 8001..."); 
      Console.WriteLine("The local End point is :" + myList.LocalEndpoint); 
      Console.WriteLine("Waiting for a connection....."); 

      Socket s = myList.AcceptSocket(); 
      Console.WriteLine("Connection accepted from " + s.RemoteEndPoint); 

      byte[] b = new byte[100]; 
      int k = s.Receive(b); 
      Console.WriteLine("Recieved..."); 
      for (int i = 0; i < k; i++) 
       Console.Write(Convert.ToChar(b[i])); 

      ASCIIEncoding asen = new ASCIIEncoding(); 
      s.Send(asen.GetBytes("The string was recieved by the server.")); 
      Console.WriteLine("\nSent Acknowledgement"); 
      /* clean up */ 
      s.Close(); 
      myList.Stop(); 

     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error..... " + e.StackTrace); 
     } 
    } 

Kunde

public static void Main() 
    { 
     try 
     { 
      TcpClient tcpclnt = new TcpClient(); 
      Console.WriteLine("Connecting..."); 

      tcpclnt.Connect("127.0.0.1", 1234); 

      Console.WriteLine("Connected"); 
      Console.Write("Enter the string to be transmitted: "); 

      String str = Console.ReadLine(); 
      Stream stm = tcpclnt.GetStream(); 

      ASCIIEncoding asen = new ASCIIEncoding(); 
      byte[] ba = asen.GetBytes(str); 
      Console.WriteLine("Transmitting..."); 

      stm.Write(ba, 0, ba.Length); 

      byte[] bb = new byte[100]; 
      int k = stm.Read(bb, 0, 100); 

      for (int i = 0; i < k; i++) 
       Console.Write(Convert.ToChar(bb[i])); 

      tcpclnt.Close(); 
     } 

     catch (Exception e) 
     { 
      Console.WriteLine("Error... " + e.StackTrace); 
     } 
    } 

Nun, ich brauche den Code-Algorithmus hinzuzufügen, die eine Datei über die gleichen Apps senden. Der Schlüssel zur Implementierung ist die Verwendung von Socket.Send im Client. Ich bin mir nicht sicher über die Serialisierung und Deserialisierung der Datei.

Jeder Tipp, Beratung, Vorschlag ist mehr als willkommen. Vielen Dank.

+1

Hinweis: [möglicherweise im Zusammenhang + einige Erklärungen] (http://stackoverflow.com/questions/34586733/sending-a-value-from-server-to-client-with-sockets/34669446 # 34669446) – Ian

+0

Sie meinen nur für den Kunden? Ich bin jetzt nicht mit meinem PC. Nur Zugriff über Mobile. Sicher, wenn Sie möchten, würde ich es wahrscheinlich morgen posten. Ich werde es wahrscheinlich ein wenig mit asynchronen Senden auch aktualisieren (anstelle der Synchronisierung) – Ian

Antwort

2

Wie gewünscht, können Sie den folgenden in der Client-Seite tun - wie von this post vorgeschlagen, mit der Ausnahme, dass Sie die Synchronisierung Send Teil in async Send wie dies ändern möchten berücksichtigen:

clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async 

Und Ihre Rückruf kann wie folgt aussehen:

private static void endSendCallback(IAsyncResult ar) { 
    try { 
     SocketError errorCode; 
     int result = clientSocket.EndSend(ar, out errorCode); 
     Console.WriteLine(errorCode == SocketError.Success ? 
      "Successful! The size of the message sent was :" + result.ToString() : 
      "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one 
     ); 
    } catch (Exception e) { //exception 
     Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); 
     //do something like retry or just report that the sending fails 
     //But since this is an exception, it probably best NOT to retry 
    } 
} 

Was, wie der vollständige Client-Seite Code nach der obigen Änderung:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Threading.Tasks; 

namespace TcpClientConsoleApplication { 
    class Program { 
     const int PORT_NO = 2201; 
     const string SERVER_IP = "127.0.0.1"; 
     static Socket clientSocket; //put here 
     static void Main(string[] args) { 
      //Similarly, start defining your client socket as soon as you start. 
      clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
      loopConnect(3, 3); //for failure handling 
      string result = ""; 
      do { 
       result = Console.ReadLine(); //you need to change this part 
       if (result.ToLower().Trim() != "exit") { 
        byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string 
        //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes 
        clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async 
        //clientSocket.Send(bytes); use this for sync send 
       } 
      } while (result.ToLower().Trim() != "exit"); 
     } 

     private static void endSendCallback(IAsyncResult ar) { 
      try { 
       SocketError errorCode; 
       int result = clientSocket.EndSend(ar, out errorCode); 
       Console.WriteLine(errorCode == SocketError.Success ? 
        "Successful! The size of the message sent was :" + result.ToString() : 
        "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one 
       ); 
      } catch (Exception e) { //exception 
       Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); 
       //do something like retry or just report that the sending fails 
       //But since this is an exception, it probably best NOT to retry 
      } 
     } 

     static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) { 
      int attempts = 0; 
      while (!clientSocket.Connected && attempts < noOfRetry) { 
       try { 
        ++attempts; 
        IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnectCallback, null); 
        result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds)); 
        System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000); 
       } catch (Exception e) { 
        Console.WriteLine("Error: " + e.ToString()); 
       } 
      } 
      if (!clientSocket.Connected) { 
       Console.WriteLine("Connection attempt is unsuccessful!"); 
       return; 
      } 
     } 

     private const int BUFFER_SIZE = 4096; 
     private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message 
     private static void endConnectCallback(IAsyncResult ar) { 
      try { 
       clientSocket.EndConnect(ar); 
       if (clientSocket.Connected) { 
        clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket); 
       } else { 
        Console.WriteLine("End of connection attempt, fail to connect..."); 
       } 
      } catch (Exception e) { 
       Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString()); 
      } 
     } 

     const int MAX_RECEIVE_ATTEMPT = 10; 
     static int receiveAttempt = 0; 
     private static void receiveCallback(IAsyncResult result) { 
      System.Net.Sockets.Socket socket = null; 
      try { 
       socket = (System.Net.Sockets.Socket)result.AsyncState; 
       if (socket.Connected) { 
        int received = socket.EndReceive(result); 
        if (received > 0) { 
         receiveAttempt = 0; 
         byte[] data = new byte[received]; 
         Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to https://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest 
         //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET! 
         //Notice that your data is not string! It is actually byte[] 
         //For now I will just print it out 
         Console.WriteLine("Server: " + Encoding.UTF8.GetString(data)); 
         socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); 
        } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again 
         ++receiveAttempt; 
         socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); 
        } else { //completely fails! 
         Console.WriteLine("receiveCallback is failed!"); 
         receiveAttempt = 0; 
         clientSocket.Close(); 
        } 
       } 
      } catch (Exception e) { // this exception will happen when "this" is be disposed... 
       Console.WriteLine("receiveCallback is failed! " + e.ToString()); 
      } 
     } 
    } 
} 

Die vollständige Erklärung, wie die obigen Teile des Codes Arbeit (beachten Sie, dass Punkt 7 wird geändert und Punkt 8 wird für async Send hinzugefügt):

Auftraggeber:

  1. Ebenso setzen die Socket Klasse im Klassenkontext und nicht im Methodenkontext und initialisiere sie, sobald du dein Programm startest

    const int PORT_NO = 2201; 
    const string SERVER_IP = "127.0.0.1"; 
    static Socket clientSocket; //put here 
    static void Main(string[] args) { 
        //Similarly, start defining your client socket as soon as you start. 
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    
        //your other main routines 
    } 
    
  2. Dann starten Sie die Verbindung durch ASyncBeginConnect. Ich würde normalerweise weiter gehen, indem ich LoopConnect nur für die Fehlerbehandlung wie folgt.

    static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) { 
        int attempts = 0; 
        while (!clientSocket.Connected && attempts < noOfRetry) { 
         try { 
          ++attempts; 
          IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnect, null); 
          result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds)); 
          System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000); 
         } catch (Exception e) { 
          Console.WriteLine("Error: " + e.ToString()); 
         } 
        } 
        if (!clientSocket.Connected) { 
         Console.WriteLine("Connection attempt is unsuccessful!"); 
         return; 
        } 
    } 
    
  3. ähnliches Konzept zu dem, was Sie mit dem Server tun BeginAccept Sie benötigen endConnectCallback für die ASyncBeginConnect zu definieren, die Sie verwenden. Aber hier, im Gegensatz zu Server, die BeginAccept erneut aufrufen müssen, müssen Sie keine neuen BeginConnect tun, da Sie nur einmal verbunden werden müssen.

  4. Möglicherweise möchten Sie buffer usw. Dann erklären, nachdem Sie eine Verbindung herstellen, nicht zu vergessen die nächste ASyncBeginReceive das Nachrichtenabrufteil (ähnlich mit dem Server)

    private const int BUFFER_SIZE = 4096; 
    private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message 
    private static void endConnectCallback(IAsyncResult ar) { 
        try { 
         clientSocket.EndConnect(ar); 
         if (clientSocket.Connected) { 
          clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket); 
         } else { 
          Console.WriteLine("End of connection attempt, fail to connect..."); 
         } 
        } catch (Exception e) { 
         Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString()); 
        } 
    } 
    
  5. natürlich zu handhaben, Sie müssen Sie Ihre receiveCallback definieren, genau wie Sie für den Server getan haben. Und ja, es ist, wie Sie vermutet haben, fast identisch mit dem, was Sie für den Server getan haben!

  6. Sie können mit Ihren Daten alles machen, was Sie wollen. Beachten Sie, dass die Daten, die Sie erhalten, tatsächlich in byte[], nicht string sind. Du kannst also alles damit machen. Aber zum Beispiel Willen, werde ich einfach string zur Anzeige verwenden.

    const int MAX_RECEIVE_ATTEMPT = 10; 
    static int receiveAttempt = 0; 
    private static void receiveCallback(IAsyncResult result) { 
        System.Net.Sockets.Socket socket = null; 
        try { 
         socket = (System.Net.Sockets.Socket)result.AsyncState; 
         if (socket.Connected) { 
          int received = socket.EndReceive(result); 
          if (received > 0) { 
           receiveAttempt = 0; 
           byte[] data = new byte[received]; 
           Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //copy the data from your buffer 
           //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET! 
           //Notice that your data is not string! It is actually byte[] 
           //For now I will just print it out 
           Console.WriteLine("Server: " + Encoding.UTF8.GetString(data)); 
           socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); 
          } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again 
           ++receiveAttempt; 
           socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); 
          } else { //completely fails! 
           Console.WriteLine("receiveCallback is failed!"); 
           receiveAttempt = 0; 
           clientSocket.Close(); 
          } 
         } 
        } catch (Exception e) { // this exception will happen when "this" is be disposed... 
         Console.WriteLine("receiveCallback is failed! " + e.ToString()); 
        } 
    } 
    
  7. Und nächste (vor dem allerletzten) - Ja, wieder, wie Sie vielleicht schon erraten haben, müssen Sie nur etwas auf dem Haupt-Routine tun - Angenommen, Sie es zu BeginSend Daten verwenden möchten. Weil Sie Console verwenden, aber Sie wollen, dass es Dinge wie byte[] sendet, müssen Sie die Konvertierung durchführen (siehe die Erklärung in Server 9 der linked post).

    static void Main(string[] args) { 
        //Similarly, start defining your client socket as soon as you start. 
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
        loopConnect(3, 3); //for failure handling 
        string result = ""; 
        do { 
         result = Console.ReadLine(); //you need to change this part 
         if (result.ToLower().Trim() != "exit") { 
          byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string 
          //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes 
          clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async 
          //clientSocket.Send(bytes); use this for sync send 
         } 
        } while (result.ToLower().Trim() != "exit"); 
    } 
    
  8. Und schließlich ganz am allerletzten, müssen Sie nur die async EndSend Callback-Funktion zu erklären und Sie sind fertig!

    private static void endSendCallback(IAsyncResult ar) { 
        try { 
         SocketError errorCode; 
         int result = clientSocket.EndSend(ar, out errorCode); 
         Console.WriteLine(errorCode == SocketError.Success ? 
          "Successful! The size of the message sent was :" + result.ToString() : 
          "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one 
         ); 
        } catch (Exception e) { //exception 
         Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); 
         //do something like retry or just report that the sending fails 
         //But since this is an exception, it probably best NOT to retry 
        } 
    } 
    
1

Sie müssen nur die Datei in ein Byte-Array lesen und dann über den Draht Sie, dass die Byte-Array senden

var bytes = File.ReadAllBytes(path); 
stm.Write(ba, 0, ba.Length);