What is the correct way of reading from a TCP socket in C/C++?
Without knowing your full application it is hard to say what the best way to approach the problem is, but a common technique is to use a header which starts with a fixed length field, which denotes the length of the rest of your message.
Assume that your header consist only of a 4 byte integer which denotes the length of the rest of your message. Then simply do the following.
// This assumes buffer is at least x bytes long,
// and that the socket is blocking.
void ReadXBytes(int socket, unsigned int x, void* buffer)
{
int bytesRead = 0;
int result;
while (bytesRead < x)
{
result = read(socket, buffer + bytesRead, x - bytesRead);
if (result < 1 )
{
// Throw your error.
}
bytesRead += result;
}
}
Then later in the code
unsigned int length = 0;
char* buffer = 0;
// we assume that sizeof(length) will return 4 here.
ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);
// Then process the data as needed.
delete [] buffer;
This makes a few assumptions:
- ints are the same size on the sender and receiver.
- Endianess is the same on both the sender and receiver.
- You have control of the protocol on both sides
- When you send a message you can calculate the length up front.
Since it is common to want to explicitly know the size of the integer you are sending across the network define them in a header file and use them explicitly such as:
// These typedefs will vary across different platforms
// such as linux, win32, OS/X etc, but the idea
// is that a Int8 is always 8 bits, and a UInt32 is always
// 32 bits regardless of the platform you are on.
// These vary from compiler to compiler, so you have to
// look them up in the compiler documentation.
typedef char Int8;
typedef short int Int16;
typedef int Int32;
typedef unsigned char UInt8;
typedef unsigned short int UInt16;
typedef unsigned int UInt32;
This would change the above to:
UInt32 length = 0;
char* buffer = 0;
ReadXBytes(socketFileDescriptor, sizeof(length), (void*)(&length));
buffer = new char[length];
ReadXBytes(socketFileDescriptor, length, (void*)buffer);
// process
delete [] buffer;
I hope this helps.
C TCP write() and read() from sockets defined in main
As user user207421 pointed out, I was accepting a client before connecting.
Also acceptSock = accept(recvSock, (struct sockaddr *)&cli_addr, clilen);
Should be acceptSock = accept(recvSock, (struct sockaddr *)&cli_addr, &clilen);
socklen_t *addrlen
parameter of accept()
requires pointer, I was not passing a pointer.
Adding the & before the size parameter changes this.
How to read all the data in socket programming (c++)?
Just to complete my comment - this code snippet may help to understand
not tested code
for (i = 0;i < max_clients; i++) {
sd = clients_list[i];
if (FD_ISSET(sd,&temp)) {
char buf[10];
int n;
int flag;
do {
n = recv(sd, buf, sizeof(buf),0);
if (n > 0) {
buf[n] = '\0';
cout << "From the node: " << buf << endl;
ioctl(sd, FIONREAD, &flag);
} else {
flag = 0;
}
} while (flag > 0);
if (n < 0) {
perror("recv");
// in case of an error you may actively close the socket
// and end transmission by server
close(sd);
clients_list[i] = 0;
} else {
cout << "Client has currently no further transmission " << endl;
// don't close socket maybe later new transmission
// active close socket by server process only if
// e.g. a timeout has reached
}
}
}
TCP socket Read
Yes! TCP sockets provide a stream interface and it is quite possible that data is delivered in more than one part.
The receiver should continue reading until all data has been received.
while (totalRead < expectedSize) {
result = read(socketfd,buff + totalRead, expectedSize-totalRead);
if (result < 0) {
// nothing read, check for errors
} else {
totalRead += result;
if (result == 0) {
// Other end shutdown before sending the expected amount of data
}
}
}
The same is true for writing:
while (written < totalSize) {
result = write(socketfd,buff + written, totalSize - written);
if (result < 0) {
// nothing written, check for errors
} else {
written += result;
}
}
c++ read unknow amount of data from socket
You asked how to fix your low-level receiving code. That's simple -- just call read
once and don't use a while
loop. The call to read
will return as soon as at least one byte of data can be read. For the number of bytes to read, just pass in the size of your buffer (or the space left in it if there's already some leftover in it from a prior call).
You will also need high-level protocol code, just as you do if you know the number of bytes. That code will probably need to be a bit different. If the chunk of bytes you got includes your stop indication, then process all the bytes up to the stop indication and keep the extra in the buffer for next time. If not, just call read
again and get a bunch more bytes.
Your protocol handling code should look sort of like this:
- Call
read
and add however many bytes you got to the buffer. (Handle an error or normal close here.) - If the data in the buffer does not include the stop indication, go to step 1.
- Process all the bytes up to the stop indication.
- Remove the processed bytes from the buffer, leaving any unprocessed bytes.
- Go to step 2.
Also, the code you gave in the question will spin forever if the other side closes the connection. In this case, read
will return zero and you will never be able to read any more data from the connection. You should break out of the loop if read
returns zero.
Related Topics
Static Constexpr Member of Same Type as Class Being Defined
Tackling Class Imbalance: Scaling Contribution to Loss and Sgd
Unsequenced Value Computations (A.K.A Sequence Points)
Is Std::String Ref-Counted in Gcc 4.X/C++11
Parsing Strings of User Input Using the Cparse Library from Git
How to Sort the Texture Positions Based on the Texture Indices Given in a Wavefront (.Obj) File
Benchmarking (Python VS. C++ Using Blas) and (Numpy)
How to Get the Class Name from a C++ Object
C++, How to Determine If a Windows Process Is Running
What Is Copy Elision and How Does It Optimize the Copy-And-Swap Idiom
Is the Backslash Acceptable in C and C++ #Include Directives
Why Does Same_As Concept Check Type Equality Twice
Reading and Writing to the Same File Using the Same Fstream
Linker Error While Linking Boost Log Tutorial (Undefined References)