webentwicklung-frage-antwort-db.com.de

Senden und Empfangen von std :: string über Socket

Ich habe eine ähnliche Frage zu SO gesehen, aber meine Frage wurde nicht beantwortet. Hier versuche ich, Zeichenfolge zu senden und zu empfangen:

Ich sende std :: string:

if( (bytecount=send(hsock, input_string.c_str(), input_string.length(),0))== -1)

Kann es dadurch richtig empfangen werden?

if ((bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)) == -1)

Ich erhalte eine Fehlermeldung:

fehler: Ungültige Konvertierung von "const void *" in "void *" [-fpermissive] `in der recv-Zeile!

9
Catty

Nein, das kann es nicht. c_str () gibt einen const char* zurück. Dies bedeutet, dass Sie den Inhalt des Zeigers nicht überschreiben können.

Wenn Sie die Daten empfangen möchten, müssen Sie einen Puffer erstellen, z. mit einem std::vector und erstelle damit einen std::string.

// create the buffer with space for the data
const unsigned int MAX_BUF_LENGTH = 4096;
std::vector<char> buffer(MAX_BUF_LENGTH);
std::string rcv;   
int bytesReceived = 0;
do {
    bytesReceived = recv(*csock, &buffer[0], buffer.length(), 0));
    // append string from buffer.
    if ( bytesReceived == -1 ) { 
        // error 
    } else {
        rcv.append( buffer.cbegin(), buffer.cend() );
    }
} while ( bytesReceived == MAX_BUF_LENGTH )
// At this point we have the available data (which may not be a complete
// application level message). 

Der obige Code empfängt jeweils 4096 Bytes. Wenn mehr als 4 KB gesendet werden, wird die Schleife fortgesetzt, und die Daten werden an recv angehängt, bis keine Daten mehr vorhanden sind.

Beachten Sie auch die Verwendung von &buffer[0] anstelle von buffer.data(). Indem Sie die Adresse des ersten Elements verwenden, können Sie auf den Nicht-Konstanten-Zeiger zugreifen und undefiniertes Verhalten vermeiden.

8
Steve

Am besten senden Sie die Länge der Zeichenfolgendaten zuerst in einem festen Format (z. B. einem uint32_t in Netzwerkbyte-Reihenfolge). Dann kann der Empfänger dies zuerst lesen und einen Puffer der entsprechenden Größe zuweisen, bevor er die serialisierte Nachricht empfängt, die anschließend gesendet wird.

Es wird angenommen, dass sd und csd bereits vorhandene Socket-Deskriptoren sind.

Sender.cpp

std::string dataToSend = "Hello World! This is a string of any length ...";

uint32_t dataLength = htonl(dataToSend.size()); // Ensure network byte order 
                                                // when sending the data length

send(sd,&dataLength ,sizeof(uint32_t) ,MSG_CONFIRM); // Send the data length
send(sd,dataToSend.c_str(),dataToSend.size(),MSG_CONFIRM); // Send the string 
                                                           // data 

Receiver.cpp

uint32_t dataLength;
recv(csd,&rcvDataLength,sizeof(uint32_t),0); // Receive the message length
dataLength = ntohl(dataLength ); // Ensure Host system byte order

std::vector<uint8_t> rcvBuf;    // Allocate a receive buffer
rcvBuf.resize(dataLength,0x00); // with the necessary size

recv(csd,&(rcvBuf[0]),dataLength,0); // Receive the string data

std::string receivedString;                        // assign buffered data to a 
receivedString.assign(&(rcvBuf[0]),rcvBuf.size()); // string

Vorteil ist. Sie müssen nicht mit mehreren gepufferten Lesevorgängen herumspielen und in die empfangene Zeichenfolge kopieren. Außerdem wissen Sie auf der Empfängerseite, wann die gesendeten Daten endlich vollständig sind.

Der Nachteil ist, dass Sie eine Art 'Protokoll' einführen, wenn Sie die Länge zuerst senden.

7

Nein, std::string::c_str() gibt const char* zurück, dh es ist schreibgeschützt. Sie können einen lokalen Puffer zuweisen und ein Zeichenfolgenobjekt aus einem lokalen Puffer erstellen, nachdem recv erfolgreich zurückgegeben wurde.

Sie müssen die Funktion recv anweisen, eine bestimmte Datenlänge zu lesen. Sie möchten beispielsweise jedes Mal 512 Bytes lesen:

#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];

recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);
5
billz

error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive] on recv line!

Als Sie sich in diese spezielle Frage eingewählt haben, haben Sie Folgendes geschrieben ( sans the if statement):

bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)

rcv.c_str() ruft einen const char* Zeiger ab. Der const char* wurde zum const void* gezwungen. Die einzige Möglichkeit, einen Nicht-Konstanten-Zeiger zu erhalten und undefiniertes Verhalten zu vermeiden, besteht darin, die Adresse des ersten Elements in einem std::string oder std::vector zu übernehmen:

bytecount = recv(*csock, &rcv[0], rcv.length(), 0)

Das Erhalten des nicht-const-Zeigers ist nur für STL-Container gültig, die zusammenhängenden Speicher bereitstellen. Der Trick würde für eine map, multimap oder andere assoziative Container nicht funktionieren.

@ πάντα-ῥεῥ ist die einzige Antwort, die darauf eingegangen ist, aber er hat den Punkt nicht betont.

0
jww