私はSO=で同様の質問を見ましたが、私の質問には答えません。ここで私は文字列を送信して受信しようとしています:
Std :: stringを送信しています:
if( (bytecount=send(hsock, input_string.c_str(), input_string.length(),0))== -1)
これで正しく受け取れますか?
if ((bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)) == -1)
エラーが発生します:
エラー:受信ラインで「const void *」から「void *」[-fpermissive]」への変換が無効です!
いいえ、できません。 c_str() は_const char*
_を返します。つまり、ポインタの内容を上書きすることはできません。
データを受け取りたい場合は、バッファを作成する必要があります。 _std::vector
_ を使用し、それを使用して_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.size(), 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).
_
上記のコードは一度に4096バイトを受け取ります。 4Kを超えるデータが送信された場合は、ループし続け、データがなくなるまでデータをrecv
に追加します。
また、buffer.data()
ではなく_&buffer[0]
_を使用していることに注意してください。最初の要素のアドレスを取ることは、非constポインターにアクセスし、未定義の動作を回避する方法です。
最善の方法は、最初に文字列データの長さを固定形式で送信することです(例:uint32_t
(ネットワークバイト順)。次に、受信者はこれを最初に読み取り、適切なサイズのバッファを割り当ててから、後で送信されるシリアル化されたメッセージを受信します。
sd
およびcsd
は、すでに存在するソケット記述子であると見なされます。
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
利点は。バッファリングされた複数の読み取りや、受信した文字列へのコピーをいじる必要はありません。さらに、送信されたデータが最終的に完成したときに受信側で知ることができます。
短所は、長さを最初に送信するときに「プロトコル」のようなものを導入することです。
いいえ、 std::string::c_str()
はconst char*
を返します。つまり、読み取り専用です。 recv
が正常に戻った後、ローカルバッファを割り当て、ローカルバッファから文字列オブジェクトを作成できます。
特定の長さのデータを読み取るようにrecv
関数に指示する必要があります。たとえば、毎回512バイトを読み取る必要があります。
#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];
recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);
_
error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
_ recv行に!
この特定の質問にダイヤルして、あなたは書いた(sansif
ステートメント):
_bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)
_
rcv.c_str()
は、_const char*
_ポインターを取得します。 _const char*
_は_const void*
_に強制変換されました。非constポインターを取得して未定義の動作を回避する唯一の方法は、_std::string
_または_std::vector
_の最初の要素のアドレスを取得することです。
_bytecount = recv(*csock, &rcv[0], rcv.length(), 0)
_
このような非constポインターの取得は、連続したメモリを提供するSTLコンテナーに対してのみ有効です。このトリックは、map
、multimap
、または他の連想コンテナでは機能しません。
@πάντα-ῥεῖがそれに答えた唯一の答えですが、彼は要点を強調しませんでした。