Frage

Ich versuche, einige ziemlich allgemeine Netzwerk-Code zu schreiben. Ich habe verschiedene Arten von Paketen, die jeweils durch eine andere Struktur dargestellt. Die Funktion, wo alle meine auftritt sieht aus wie das Senden:

- (void)sendUpdatePacket:(MyPacketType)packet{ 
    for(NSNetService *service in _services) 
        for(NSData *address in [service addresses]) 
            sendto(_socket, &packet, sizeof(packet), 0, [address bytes], [address length]); 
}

Ich möchte wirklich, dass diese Funktion nutzen können ANY von Paket Art senden, nicht nur MyPacketType Pakete.

Ich dachte, vielleicht, wenn die Funktion def war:

- (void)sendUpdatePacket:(void*)packetRef

konnte ich in anykind der Zeiger auf Paket übergeben. Aber ohne den Typen des Pakets zu wissen, ich kann nicht die Zeigerdereferenzierung.

Wie schreibe ich eine Funktion, jede Art von primitiver / Struktur als Argument akzeptieren?

War es hilfreich?

Lösung 2

Der Schlüssel ist, dass Sie, dass alles in einem Computer realisieren muss, ist nur ein Array von Bytes (oder, Wörter oder Doppelwörter).

Zenmeister SENF an seinem Schreibtisch sitzt auf seinem Monitor starrt auf einem komplexen Muster von scheinbar zufälligen Zeichen starren. Ein STUDENT annähert.

Student: Meister? Darf ich unterbrechen?

Zen-Meister Senf. Sie haben eine eigene Anfrage, meinen Sohn, antworten

S: Was

ZMM. Ihre Frage zu unterbrechen Sie mich mit der Frage: hast du mich unterbrochen

S: Oh, sorry. Ich habe eine Frage zu Strukturen unterschiedlicher Größe von Ort zu Ort zu bewegen.

ZMM: Wenn das es wahr ist, dann sollten Sie einen Master konsultieren, der auf solche Dinge auszeichnet. Ich schlage vor, Sie zahlen einen Besuch Meister DotPuft, der in bewegten große Metallstrukturen großes Wissen hat, wie Radare Tracking, von Ort zu Ort. Master DotPuft kann auch dazu führen, die kleinsten Elemente einer federleichte DMS mit der Kraft einer Taube des Atems zu bewegen. Biegen Sie rechts ab, dann biegen Sie links ab, wenn Sie die Tür der hallo-Bucht erreichen. Es wohnt Meister DotPuft.

. S: Nein, ich meine Bewegen von großen Strukturen in unterschiedlichen Größen von Ort zu Ort in dem Speicher eines Computers

ZMM: Ich kann Sie in diesem Bestreben unterstützen, wenn Sie es wünschen. Beschreiben Sie Ihr Problem.

S: Insbesondere ich eine C-Funktion habe, dass ich verschiedene Arten von Strukturen annehmen möge (sie werden verschiedene Arten von Paketen vertreten). Also meine struct Pakete zu meiner Funktion als void * übergeben werden. Aber ohne den Typen zu kennen, kann ich werfe sie nicht, oder wirklich tut viel von allem. Ich weiß, das ein lösbares Problem, weil sento () von socket.h tut genau das:

    ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr,socklen_t dest_len);

wo sendto wie genannt würde:

    sendto(socketAddress, &myPacket, sizeof(myPacket), Other args....);

ZMM: Haben Sie beschreiben Ihr Problem zu Zen-Meister MANTAR! ?

S: Ja, sagte er, „Es ist nur ein Zeiger Alles in C ein Zeiger ist..“ Als ich ihn fragte, zu erklären, sagte er, „Bok, Bok, aus meinem Büro die Hölle kommen.“

ZMM: Wahrlich, du mit dem Master gesprochen haben. Hat dieser Ihnen nicht helfen?

S: äh, äh, nein. Dann fragte ich Zen-Meister Max.

ZMM: Wise ist er. Was war sein Rat nützlich für Sie?

S: Nein. Als ich ihn fragte sendto (), er wirbelte nur seine Fäuste in der Luft. Es ist nur ein Byte-Array. "

ZMM:. In der Tat, Zen-Meister Max hat tau

S: Ja, er hat tau, aber wie kann ich mit Funktionsargumenten vom Typ void * behandeln

ZMM: Um zu erfahren, müssen Sie zuerst verlernen müssen. Der Schlüssel ist, dass Sie, dass alles in einem Computer realisieren muss, ist nur ein Array von Bytes (oder, Wörter oder Doppelwörter). Sobald Sie einen Zeiger auf den Anfang eines Puffers, und die Länge des Puffers haben, können Sie es geschickt überall ohne Notwendigkeit, die Art der Daten in dem Puffer platziert kennen.

S: OK.

ZMM: eine Reihe von Menschen lesbaren Text in Betracht. „Sie planen einen Turm, der die Wolken durchdringen wird? Lay zunächst die Grundlage der Demut.“ Es ist 82 Byte lang. Oder vielleicht 164, wenn das Übel Unicode verwendet. Schützen Sie sich gegen die Lügen von Unicode! Ich kann diesen Text sendto () einreichen durch einen Zeiger auf den Anfang des Puffers, die die Zeichenfolge enthält, und die Länge des Puffers, etwa so:

char characterBuffer[300];      // 300 bytes
strcpy(characterBuffer, "You plan a tower that will pierce the clouds? Lay first the foundation of humility.");
// note that sizeof(characterBuffer) evaluates to 300 bytes.
sendto(socketAddress, &characterBuffer, sizeof(characterBuffer));

ZMM: Hinweis gut, dass die Anzahl von Bytes des Zeichenpuffers wird vom Compiler automatisch berechnet. Die Anzahl der Bytes besetzt durch jeden Variablentyp ist von einem Typ namens „size_t“. Es ist wahrscheinlich, entspricht dem Typ „long“ oder „unsinged int“, aber es ist Compiler abhängig.

S: Nun, was ist, wenn ich will, eine Struktur senden

ZMM. Lassen Sie uns eine Struktur senden, dann

struct
{
     int integerField;          // 4 bytes
     char characterField[300];  // 300 bytes
     float floatField;          // 4 bytes
} myStruct;

myStruct.integerField = 8765309;
strcpy(myStruct.characterField, "Jenny, I got your number.");
myStruct.floatField = 876.5309;

// sizeof(myStruct) evaluates to 4 + 300 + 4 = 308 bytes
sendto(socketAddress, &myStruct, sizeof(myStruct);

S: Ja, die bei Übertragung Dinge über TCP / IP-Sockets groß ist. Aber was ist die schlechte Empfangsfunktion? Wie kann es sagen, wenn ich ein Zeichen-Array oder eine Struktur schicke?

ZMM: Eine Möglichkeit ist, die verschiedenen Arten von Daten auflisten, die gesendet werden können, eind dann die Art der Daten senden zusammen mit den Daten. Zen-Meister bezeichnet dies als „Metadaten“, das heißt „Daten über die Daten“ zu sagen ist. Ihre Empfangsfunktion muß die Metadaten untersuchen, um zu bestimmen, welche Art von Daten (struct, float, Zeichen-Array) ist, gesendet wird, und dann diese Informationen verwenden, um die Daten zurück in ihren ursprünglichen Typen umgewandelt. Betrachten wir zuerst die Sendefunktion:

enum
{
    INTEGER_IN_THE_PACKET =0 ,
    STRING_IN_THE_PACKET =1,  
    STRUCT_IN_THE_PACKET=2
} typeBeingSent;

struct
{
     typeBeingSent dataType;
     char data[4096];
} Packet_struct;

Packet_struct myPacket;

myPacket.dataType = STRING_IN_THE_PACKET;
strcpy(myPacket.data, "Nothing great is ever achieved without much enduring.");
sendto(socketAddress, myPacket, sizeof(Packet_struct);

myPacket.dataType = STRUCT_IN_THE_PACKET;
memcpy(myPacket.data, (void*)&myStruct, sizeof(myStruct);
sendto(socketAddress, myPacket, sizeof(Packet_struct);

. S: In Ordnung

ZMM: Nun, uns nur mit der Aufnahmefunktion zu Fuß entlang. Es muss die Art der Daten abfragen, die gesendet wurde, und das Kopieren der Daten in eine Variable dieses Typs deklariert. Verzeihen Sie mir, aber ich vergesse genau für die recvfrom() Funktion.

   char[300] receivedString;
   struct myStruct receivedStruct;  

   recvfrom(socketDescriptor, myPacket, sizeof(myPacket);

   switch(myPacket.dataType)
   {
       case STRING_IN_THE_PACKET:
            // note the cast of the void* data into type "character pointer"
            &receivedString[0] = (char*)&myPacket.data; 
            printf("The string in the packet was \"%s\".\n", receivedString); 
            break;

       case STRUCT_IN_THE_PACKET:
            // note the case of the void* into type "pointer to myStruct"
            memcpy(receivedStruct, (struct myStruct *)&myPacket.data, sizeof(receivedStruct));
            break;
    }

ZMM: Haben Sie erreicht Erleuchtung? Zuerst fragt man die Compiler für die Größe der Daten (auch bekannt als die Anzahl von Bytes) zu sendto() vorgelegt werden. Sie senden die Art der ursprünglichen Daten als auch mitgeschickt wird. Der Empfänger fragt dann nach der Art der ursprünglichen Daten und nutzt sie die richtige Besetzung von „Zeigern auf Lücke“ nennen (ein allgemeiner Zeiger), über die Art der ursprünglichen Daten (int, char [], eine Struktur, etc.)

. S: Nun, ich werde es versuchen

ZMM:. Gehen Sie in Frieden

Andere Tipps

Was Sie versuchen zu erreichen Polymorphismus , die ein OO-Konzept ist.

Während also diese ganz einfach in C zu implementieren wäre ++ (oder ein andere OO-Sprachen), es ist ein bisschen mehr in C herausfordernd.

Eine Möglichkeit, um bekommen könntest, ist es eine allgemeine „Paket“ Struktur, wie diese zu erstellen:

typedef struct {
    void* messageHandler;
    int   messageLength;
    int*  messageData;
} packet;

Wenn das messageHandler Mitglied eine Funktion Zeiger auf eine Callback-Routine ist, die den Nachrichtentyp verarbeiten können, und die messageLength und messageData Mitglieder sind ziemlich selbsterklärend.

Die Idee ist, dass die Methode, die Ihnen die packetStruct passieren die verwenden würde Tell, Don‘ stellen sie t Prinzip den spezifischen Message-Handler Zeiger auf von messageHandler aufzurufen, vorbei in den messageLength und messageData ohne sie zu interpretieren.

Die Funktion dispatch (auf dem durch messageHandler) würde Nachricht spezifisch sein und wird den messageData auf die entsprechende sinnvolle Art, und dann wird die sinnvollen Felder der Lage sein können zu werfen daraus extrahierten und verarbeitet werden, etc.

Natürlich ist das alles viel einfacher und eleganter in C ++ mit Vererbung, virtuellen Methoden und dergleichen.


Edit:

Als Reaktion auf den Kommentar:

  

Ich bin ein wenig unklar, wie „in der Lage Besetzung   die an den entsprechenden message   sinnvolle Art, und dann die   sinnvolle Felder extrahiert werden   von ihm und verarbeitet werden, usw.“wäre   erreicht.

Sie würden einen Handler für eine bestimmte Nachrichtentyp, implementieren und das messageHandler Mitglied gesetzt ein Funktionszeiger auf diesen Handler zu sein. Zum Beispiel:

void messageAlphaHandler(int messageLength, int* messageData)
{
    MessageAlpha* myMessage = (MessageAlpha*)messageData;

    // Can now use MessageAlpha members...
    int messageField = myMessage->field1;
    // etc...
}

Sie würden messageAlphaHandler() in einer solchen Art und Weise definieren jede Klasse zu ermöglichen, leicht einen Funktionszeiger, um es zu bekommen. Sie können dies tun, beim Start der Anwendung, so dass die Nachrichtenhandler von Anfang an registriert werden.

Beachten Sie, dass für dieses System zu arbeiten, werden alle Nachrichten-Handler die gleiche Funktion Unterschrift teilen müssten (d Rückgabetyp und Parameter).

  

oder was das betrifft, wie message   würde in erster Linie erstellt werden   von meinem struct.

Wie Sie bekommen Sie Datenpaket? Sind Sie es manuell zu erstellen, ist es aus einer Steckdose zu lesen? So oder so, müssen Sie es irgendwo als eine Kette von Bytes kodieren. Das int* Glied (messageData) ist lediglich ein Zeiger auf den Anfang der codierten Daten. Das messageLength Mitglied ist die Länge dieser codierten Daten.

In Ihrem Nachrichtenhandler Rückruf, mögen Sie nicht wollen wahrscheinlich nicht fortsetzen, die Daten als unformatierte binären / Hex-Daten zu manipulieren, sondern interpretieren die Informationen in einer sinnvollen Art und Weise nach der Nachrichtentyp.

Casting es auf eine Struktur im Wesentlichen bildet die unformatierten binären Informationen über zu einem sinnvollen Satz von Attributen zu dem Protokoll der Nachricht passend Sie verarbeiten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top