Announcement

Collapse
No announcement yet.

Binärdaten über Socket versenden

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Binärdaten über Socket versenden

    Hallo!
    Ich möchte folgenden Delphi - Code in C# umsetzen:

    <PRE>
    Var
    EA_Set : packed Record
    Send_Sequence,
    Rec_Sequence,
    Struct_Type,
    l : Word;
    Set_Bits : Word;
    Value : Word;
    End;

    Var
    pEA_Set: Pointer;

    begin
    pEA_Set := @EA_Set;
    If FActive Then Begin {Server is online}
    with EA_Set Do Begin
    Set_Bits := $FFFF;
    Value := Data;
    End;
    FClient.Send (pEA_Set,EA_Set.l);
    PEA_Set := @EA_Read_Cmd;
    Client.Send (pEA_Set,EA_Read_Cmd.l);
    End;
    </PRE>

    Der Record wird damit rein binär Byte für Byte über die Client (Socket) Verbindung geschickt.
    In C# geht so etwas nicht, deshalb habe ich folgendes versucht - funkt aber nicht:

    <PRE>
    [Serializable]
    struct EA_Set
    {
    public ushort
    Send_Sequence,
    Rec_Sequence,
    Struct_Type,
    l,
    Set_Bits,
    Value;
    }

    private void button1_Click(object sender, System.EventArgs e)
    {
    EA_Set EA;
    EA.Send_Sequence = 0;
    EA.Rec_Sequence = 0;
    EA.Struct_Type = 0;
    EA.Set_Bits = 0xFFFF;
    EA.Value = 0x55;
    EA.l = 12;

    byte [] buf = new byte [200000];

    MemoryStream bw = new MemoryStream (buf,0,2000,true,true);

    BinaryFormatter frm = new BinaryFormatter ();

    frm.Serialize(bw,EA);

    tcpClient1.Socket.WriteBytes (buf,true);
    }
    }
    </PRE>

    Thx for help!!

    Manfred

  • #2
    Hallo nochmal!
    Sorry, das Byte - Array buf ist nur 12 Byte gross und der Stream ebenfalls. Dann ergibt sich allerdings zusätzlich das Problem, dass das Array beim Serialisieren als zu klein und nicht erweiterbar angemeckert wird (= Programmabbruch). Erst wenn man die Werte sehr gross wählt (wie oben) dann läuft das Programm durch aber beim Server kommt nur Müll an

    Comment


    • #3
      Hallo,

      Von was ist tcpClient1 denn eine Instanz?

      Ein anderer Ansatz wäre:

      NetworkStream writer = GetStream();

      System.Text.ASCIIEncoding encord = new System.Text.ASCIIEncoding();

      byte [] writeBuffer = encord.GetBytes(data);

      if(writer != null) {

      for (i=0; i<writeBuffer.Length; i++){

      writer.WriteByte(writeBuffer[i]);

      Thread.Sleep(1);

      }

      Dies ist ein Ausschnitt aus einer von TcpClient abgeleiteten Klasse, so dass GetStream eine Methode von TcpClient ist. data ist ein string. NetworkStream kann den Puffer auch in einem Rutsch schreiben (mit Methode Write), das Pausieren nach jedem Byte ist nur bei mir eine spezielle Anforderung der Hardware der Gegenseite

      Comment


      • #4
        Hallo,
        und erst einmal danke für die Antwort.
        tcpclient ist aus der INDY - Bibliothek, aber das ist für das Problem eigentlich egal.<BR>
        Das Problem besteht darin, dass ich 6 Word -Variablen in einen SocketStream verpacken muss.
        Dabei muss jeweils erst das Low-Byte und dann das High - Byte der Variablen auf die Reise gehen.<BR>
        Außer den Bimärdaten darf ansonsten nichts verschickt werden, sonst versteht das Empfangsgerät die Daten nicht.<BR>
        In Dephi und ähnlich in C-Builder läßt sich das ganz einfach wie oben beschrieben erledigen.
        Ich könnte nun natärlich die Word - Daten "zu Fuß" in ein Byte - Array schreiben. Habe ich schon gemacht und funktioniert auch.<BR>
        Aber das kann es doch nicht sein oder??<BR&gt

        Comment


        • #5
          Hallo,

          ich frage mich nur, ob der BinaryFormatter das leisten kann. Im SDK steht unter dem Thema "Binäre Serialisierung":

          Die Serialisierung kann als Prozess der Speicherung des Zustands eines Objekts in einem Speichermedium definiert werden. Während dieses Prozesses werden die öffentlichen und die privaten Felder des Objekts und der Klassenname sowie die Assembly, die die Klasse enthält, in einen Bytestream umgewandelt, der dann in einen Datenstream geschrieben wird. Wenn das Objekt anschließend deserialisiert wird, wird ein identischer Klon des ursprünglichen Objekts erstellt.

          Hieraus würde ich folgern, dass das Datenformat nach der Serialisierung BlackBox ist und erst nach der Deserialisierung mit BinaryFormatter auf der Empfängerseite wieder deine Struktur restauriert wird. Das würde auch den Fehler zu kleines Array erklären. Wenn diese Überlegung richtig ist, ist es also kein Wunder, wenn dein Server nur Bahnhof versteht

          Comment


          • #6
            Hallo!<BR>
            Ich glaube auch, dass Du recht hast.<BR>
            Ich habe die Daten mal in einen Filestrean geschrieben und mir mit einem Hex-Editor die Datei angesehen.<BR>
            Vor den eigentlichen Binärdaten stehen da noch eine Menge anderer Informationen. Man kann z.B. die .NET Version erkennen.<BR>
            Ich habe das Problem mittlerweile für mich durch "Klein-klein" Programmierung gelöst.<BR> Bei Interesse stelle ich es hier ein. (Sind nur ca. 20 Zeilen).<BR>Für eine Sprache mit dem Anspruch von C# finde ich es allerdings etwas ärmlich wenn man zu solchen "Steinzeitmethoden" greifen muss.

            Gruss und nochmals vielen Dank

            Manfred Flum

            Comment


            • #7
              Hallo,

              ja, stell mal rein. Ich sammle immer interessante Codeschnipsel

              Comment


              • #8
                Also:<BR>
                Here it is:<BR>
                <PRE>
                namespace EA_Server
                {
                class EA_Set
                {

                enum EA_Names
                {
                Send_Sequence,
                Rec_Sequence,
                Struct_Type,
                l,
                Set_Bits,
                Value
                };

                public ushort [] EA_Values = new ushort [6];

                public byte [] EA_Data = new byte [12];

                byte lo (ushort Value)
                {
                return (Convert.ToByte (Value & 0x00FF));
                }

                byte hi (ushort Value)
                {
                return (Convert.ToByte ((Value >> 8) & 0x00FF));
                }

                public void EA_Convert ()
                {
                int j = 0;
                for (int i=0;i<6;i++)
                {
                EA_Data [j++] = lo (EA_Values [i]);
                EA_Data [j++] = hi (EA_Values [i]);
                }
                }

                public EA_Set ()
                {
                EA_Values [(int)EA_Names.Send_Sequence] = 0;
                EA_Values [(int)EA_Names.Rec_Sequence] = 0;
                EA_Values [(int)EA_Names.Struct_Type] = 0x09;
                EA_Values [(int)EA_Names.l] = 12;
                EA_Values [(int)EA_Names.Set_Bits] = 0;
                EA_Values [(int)EA_Names.Value] = 0;
                }
                }
                }

                :
                :

                private void button1_Click(object sender, System.EventArgs e)
                {
                EA_Set EA = new EA_Set();
                EA.EA_Values [4] = 0xFFFF;
                ushort Data = Convert.ToUInt16 (textBox1.Text);
                EA.EA_Values [5] = Data;
                EA.EA_Convert();
                tcpClient1.Socket.WriteBytes (EA.EA_Data,true);
                }
                }
                </PRE>

                Gruss

                Manfred Flum

                Comment


                • #9
                  Hallo!
                  Mich würde aber trotzdem interessieren, ob das nicht auch mit eingebauten Befehlen geht

                  Comment


                  • #10
                    servus,

                    die "eingebaute" variante heisst .Net Remoting.
                    da musst du dich dann nicht mal mehr um den ganze socket-kram
                    kuemmern

                    Comment


                    • #11
                      Hallo!
                      Danke, da fange ich mal an zu lesen...
                      Oder gibt es ggf. ein Beispiel??
                      ;-

                      Comment


                      • #12
                        Ich schon wieder!
                        Mein Problem ist nicht so sehr der "Socket-Kram" als vielmehr, dass das Struct kein Struct mehr ist, sondern ein Objekt.
                        Mein Zielsystem erwartet aber die reinen Daten in Intel - Order.
                        Ich muss also das Struct entkernen um an die Binärdaten heranzukommen.
                        Ich habe im übrigen noch in einer anderen Anwendung das Problem, dass ich eine Union benötige.

                        Gruss
                        Manfre

                        Comment


                        • #13
                          hallo manfred,

                          du versuchst die daten(struct) an einen nicht dotnet process zu schicken?

                          vielleicht hilft dir: www.zeroc.com

                          das ist eine oo middleware - aehnlich zu corba - unterstuetzt viele
                          spreachen und platformen.

                          falls das ein overkill fuer deine applikation ist,
                          dann kannst du ja dein eigenes marshalling schreiben.

                          viel gluec

                          Comment


                          • #14
                            Hallo!
                            Mein Zielgerät ist ein kleiner Microcontroller für Steuerungszwecke.
                            Der erwartet die Daten genau in der Form wie ich es beschrieben habe. <br>
                            1. Byte = low - Byte des 1. Word,<br>
                            2. Byte = high - Byte des 2. Word,<br>
                            etc.<br>

                            Bisher war das ganz einfach:<br>
                            Pointer auf den Record oder das Struct (für die C-Fraktion), mit SizeOf (Record) die Länge ermitteln und das Ganze abschicken.

                            Ein weiteres Problem:<br>

                            Var<br>
                            Daten: Record<br>
                            Data1 : Single;<br>
                            Data2 : Array [1..4] of Byte Absolute Data1;<br>
                            End;<br>

                            Wozu das Ganze?<br>
                            Ich speichere einen Float - Wert im IEEE - Single - Format.<br>
                            Dieser ist 4 Byte lang. Data2 liegt speichertechnisch genau auf Data1.<br>
                            Wenn ich nun Data2 über eine Schnittstelle (V24, TCP-IP,etc) versende, empfängt das Zielsystem Data1 ohne Rundungsfehler o.ä. und mit minimalem Datenvolumen.<br>
                            Auch so etwas benötigt man im Zusammenspiel mit Microcontrollern.<br>
                            Und auch hier ist mir außer einer Bastellösung noch nichts aufgefallen, wie man das mit C# erledigen kann.<br>

                            Gruss Manfred<br>

                            P.S.: Trotzdem vielen Dank für die vielen Versuche mir zu helfen

                            Comment


                            • #15
                              servus,

                              schau dir doch mal die class System.ComponentModel.ByteConverter an.
                              damit muesstest du eigentlich alle typen in ein Byte[]
                              convertieren koennen.

                              viel glueck

                              to

                              Comment

                              Working...
                              X