简体   繁体   中英

About socket recv and char[] in C++

I am creating a program that can get package and print it to console by C++. I set the char array to 1024 like :

char* buffer = new char[1024];

When I get a message is not exactly 1024 character, there is many unknown character on the end of my message because of the empty space in the array. What can I do?

More information (I dont know if it is useful)

The socket is sent by a Java program

Socket socket = new Socket("127.0.0.1", 27555);

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("I am your client :D");
out.flush(); 

And the server is written by C++ console application

char* recvData = new char[1024];
recv(socket, recvData, strlen(recvData), 0);
cout << recvData << endl;

There are three problems with the code:

  • recvData is unitialised when passed to strlen() . strlen() determines the length of the buffer when it finds a null terminating character, which could be within the buffer or outside. The size of the buffer, less one for terminating null character, should be passed as the maximum number of bytes to read.
  • the result of recv() is not queried. The code will use recvData even if the recv() failed, which is a bug.
  • recv() does not null terminate the buffer.

Save the result of recv() and if not -1 use it as an index into recvData to insert the null terminating character.

Alternatively, as this is c++ use a std::vector<char> and to manage dynamic memory allocation for you (if dynamic memory allocation is really required):

std::vector<char> recvData(1025); // Default initializes all elements to 0.
int result = recv(socket, recvData.data(), recvData.size() - 1);
if (result != -1)
{
    std::cout << recvData.data() << std::endl;
}

Remember that data sent via sockets it just a stream of bytes, it is not separated into distinct messages. This means that:

out.write("I am your client :D");

might not be read by a single call to recv() . Equally:

out.write("I am your client :D");
out.write("OK");

might be read by a single call to recv() . It is the programmer's responsibility to implement a protocol if message-based processing is required.

strlen counts the number of bytes until a null ( '\\0' ) character is encountered. There is no guarantee that data returned by a single recv call wil be nul-terminated so you'll need to check the number of bytes returned then add your own terminator.

char* recvData = new char[1024];
int bytes = recv(socket, recvData, 1023, 0);
if (bytes == -1) {
    cout << "error on recv" << endl;
}
else {
    recvData[bytes] = '\0';    
    cout << recvData << endl;
}

recvData is not null terminated , so result of strlen() is undefined in this case. you have to do something like the following:

int len = 1024;
char *recvData = new char[len + 1];
int lenRead = recv(socket, recvData, len, 0);
if (lenRead < len)
    recvData[lenRead] = '\0';
else
    recvData[len] = '\0'; 
cout << recvData << endl;

Isn't this obvious? :)

Just send the length of the string first or terminate the string "properly" (by sending a \\0 after the end of your string; I guess that's something Java isn't doing here).

But overall, you should include the "packet length" anyway, because you might want to ensure there's enough free space before writing to the buffer (using strlen() on an uninitialized array is usually a bad idea).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM