C++ socket only sends first 4 bytes of data - c++

I am currently writing a socket wrapper in C++ for Linux. It is basically a collection of classes that handle the creation, connection, sending, reading, and closing of a TCP socket.
In my socket class, all functions work well except for the send and receive function. They do not return an error; instead, it only sends the first four bytes of data.
My send function:
int Socket::sends(char* buffer){
int bytes; // for number of bytes sent
/* First, send the size of buffer */
int datalen = strlen(buffer); // get sizeof buffer
int len = htonl(datalen); // reformat
// send the size of the buffer
bytes = send(socketfd, (char*)&len, sizeof(len), 0); // send the size
if (bytes < 0){
cerr << "Error sending size of buffer to socket" << endl;
return 1;
}
/* Now acutally send the data */
bytes = send(socketfd, buffer, datalen, 0);
if (bytes < 0){
cerr << "Error writing buffer to socket" << endl;
return 1;
}
cout << bytes << " written" << endl;
return 0;
}
The ideas behind it is that It sends the buffer (char* buffer) by first sending the size of the buffer, and then sending the actual buffer. If an error is encountered (returning -1) the function terminates by returning 1.
Now, here is the read method:
int Socket::reads(char* buffer){
int bytes, buflen; // for bytes written and size of buffer
/* Read the incoming size */
bytes = recv(socketfd, (char*)&buflen, sizeof(buflen), 0);
if (bytes < 0){
cerr << "Error reading size of data" << endl;
return 1;
}
buflen = ntohl(buflen);
/* Read the data */
bytes = recv(socketfd, buffer, buflen, 0);
if (bytes < 0){
cerr << "Error reading data" << endl;
return 1;
}
return 0;
}
Here, the idea is to read the size of the data first, and then set the buffer to that size and read into it. The function returns 1 on error (recv returns -1).
Using the methods would look something like this:
socket.sends("Hello World"); // socket object sends the message
char* buffer;
socket.reads(buffer); // reads into the buffer
However, when ever I use these functions, I only receive the first 4 bytes of data, followed by strange, non-ASCII characters. I have no idea why this happens. No error is not encountered in the send and recv functions, and the functions say that only 4 bytes were written. Is there a better way that I should send or receive data? I am overlooking a very simple error?
Thanks for your help!

you're passing an uninitialized pointer (buffer) to your reads method, which probably explains that it works partially (undefined behaviour).
And you shouldn't pass buffer as a parameter since it won't be modified (and you don't know the size yet anyway)
Plus, you have to null-terminate your message when you recieve it.
I would do like this:
char *Socket::reads(){
char* buffer;
int bytes, buflen; // for bytes written and size of buffer
/* Read the incoming size */
bytes = recv(socketfd, (char*)&buflen, sizeof(buflen), 0);
if (bytes < 0){
cerr << "Error reading size of data" << endl;
return 1;
}
buflen = ntohl(buflen);
buffer = new char[buflen+1]; // +1 for the NUL-terminator
/* Read the data */
bytes = recv(socketfd, buffer, buflen, 0);
if (bytes < 0){
cerr << "Error reading data" << endl;
return 1;
}
buffer[buflen] = '\0'; // NUL-terminate the string
return buffer;
}
the main:
socket.sends("Hello World"); // socket object sends the message
char* buffer = socket.reads(); // reads into the buffer
don't forget to delete [] the buffer in the end.
Could also be done with std::string or std::vector<char> to avoid new and delete

Related

Unable to send the message again using C socket

I have created a ClientSocket and a ServerSocket class for simplifying functions. while sending a data, at first I am sending a 16 bytes header containing the message length followed by the message. But I am having trouble while sending data from client to server on the 2nd time. At first it is sending the header and the message properly but after that I am getting 0 bytes output from read() in ServerSocket::get_message while reading the header from the client. Please help me out here.
Sending and receiving part in Server.cpp
string ServerSocket::get_message(int client_socket_fd) {
//char *header = client_buffers[client_socket_fd].read_header;
char *read_buffer = client_buffers[client_socket_fd].read_buffer;
char header[16];
memset(header, 0, sizeof(header));
int read_result = -1;
read_result = read(client_socket_fd, header, 16);
cout << read_result << endl;
if (read_result > 0){
int read_size = stoi(string(header));
cout << read_size << endl;
memset(read_buffer, 0, sizeof(read_buffer));
read_result = read(client_socket_fd, read_buffer,read_size);
if (read_result > 0) return string(read_buffer);
}
cerr << "Unable to recieve message from client socket " << client_socket_fd << endl;
return "";
}
int ServerSocket::_send(int client_socket_fd, string message) {
//char *header = client_buffers[client_socket_fd].write_header;
char *write_buffer = client_buffers[client_socket_fd].write_buffer;
char header[16];
memset(header, 0, sizeof(header));
string write_size = to_string(message.length());
copy(write_size.begin(), write_size.end(), header);
int write_result = write(client_socket_fd, header, 16); // sending size of message
if (write_result > 0) {
write_result = write(client_socket_fd, message.c_str(), message.length());
}
if (write_result <= 0)
cerr << "Unable to send to client socket fd : " << client_socket_fd << endl;
return write_result;
}
Sending and receiving part in Client.cpp
string ClientSocket::_recieve(){
char read_header[16];
memset(read_header, 0, sizeof(read_header));
int read_result = read(socket_fd, read_header, 16);
if (read_result >0) {
int read_size = stoi(string(read_header));
memset(recieve_buffer, 0, sizeof(recieve_buffer));
read_result = read(socket_fd, recieve_buffer, read_size);
}
if ( read_result > 0) return string(recieve_buffer);
cerr << "Unable to read from server." << endl;
return "";
}
int ClientSocket::_send(string message) {
char write_header[16];
memset(write_header, 0, sizeof(write_header));
cout << message.length() << endl;
string s = to_string(message.length());
copy(s.begin(),s.end(), write_header);
int write_result = write(socket_fd, write_header, 16);
if (write_result > 0)
write_result = write(socket_fd, message.c_str(), message.length());
if (write_result <=0) cerr << "Unable to send message : "<< message << endl;
return write_result;
}
The code exhibits the two most frequent errors when using sockets:
Socket send/write and recv/read may not send/receive the number of bytes requested. The code must handle partial reads/writes in order to work correctly.
The received socket data is not zero-terminated. You need to zero-terminate the received data before passing it to functions that expect zero-terminated stings (std::string and stoi here). memset doesn't help when recv fills the entire buffer, you need to reserve one extra byte for the null terminator that recv doesn't overwrite.

C/C++ recv hangs altough local server sends data

I am having a hard time figuring out a bug in my TCP client-server app. The problem I am facing: in my recv function do-while loop, if the condition is bytes > 0, the function hangs forever. Replacing that with bytes == NMAX, everything works fine, UNLESS NMAX is equal to 1. A few side notes: doing a single send-recv works fine, but trying to do a send-recv and then recv-send hangs forever. NMAX is a constant set to 4096 by default. Server is ran first, then the client.
This is my send function:
ssize_t sendData(const std::string data, int fd)
{
ssize_t total = data.length(), bytes, sent = 0;
do
{
ssize_t chunk = total > NMAX ? NMAX : total;
bytes = send(fd, data.c_str() + sent, chunk, 0);
if (bytes == -1)
{
throw std::system_error(errno, std::generic_category(), "Error sending data");
}
total -= bytes;
sent += bytes;
} while (total > 0);
return sent;
}
This is my recv function:
std::string recvData(int fd)
{
ssize_t bytes;
std::string buffer;
do
{
std::vector<char> data(NMAX, 0);
bytes = recv(fd, &data[0], NMAX, 0);
if (bytes == -1)
{
throw std::system_error(errno, std::generic_category(), "Error receiving data");
}
buffer.append(data.cbegin(), data.cend());
} while (bytes > 0); // Replacing with bytes == NMAX partially fixes the issue, why?
return buffer;
}
This is the client's main function:
std::cout << "Sent " << sendData(data) << " bytes\n";
std::cout << "Received: " << recvData() << "\n";
And this is the server's main function:
std::cout << "Received: " << recvData(client) << "\n";
std::cout << "Sent " << sendData("Hello from the server side!", client) << " bytes\n";
The problem with your program is that the receiving side does not know how many bytes to receive in total. Therefore it will just endlessly try to read more bytes.
The reason why it "hangs" is that you perform a blocking system call (recv) which will only unblock if at least 1 more byte had been received. However since the peer does not send more data this will never happen.
To fix the issue you need to have a proper wire-format for your data which indicates how big the transmitted data is, or where it starts and ends. A common way to do this is to prefix data with it's length in binary form (e.g. a 32bit unsigned int in big endian format). Another way is to have indicators inside the data that indicate it's end (e.g. the \r\n\r\n line breaks in HTTP).
Btw: Your send function is not ideal for cases where data.length() == 0. In this case you perform a send system call with 0 bytes - which is rather unnecessary.

Sending files over TCP using C++, recving wrong size

I am very new to socket programming, and i am trying to send over TCP connection but getting few errors.
here is my code
FILE* File;
char* Buffer;
unsigned long Size;
File = fopen("C:\\test.zip", "rb");
if (!File)
{
printf("Error while readaing the file\n");
return;
}
// file size 1
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%i", Size);
cout << "MAX PATH " << MAX_PATH<<endl;
cout << "cSize: " << cSize << endl;
fclose(File);
`
So this to find the size of my file. most of the code i am trying it out from other questions in here but it didnt solve my problem.
'
my send and recv:
unsigned long filechunk = 1025;
unsigned long byteSent = 0;
unsigned long bytesToSend = 0;
send(Sub, cSize, MAX_PATH, 0); // File size to client
while (byteSent < Size) {
if ((Size - byteSent) >= filechunk) {
bytesToSend = filechunk;
}
else {
bytesToSend = Size - byteSent;
}
if (send(Sub, Buffer + byteSent, bytesToSend, 0)) {
std::cout << "Sent: ";
}
byteSent += bytesToSend;
std::cout << "Size : "<<Size<<" BytesSent : "<<byteSent<<" Bytes to send: " << bytesToSend << std::endl;
system("pause");
on the client side:
int Size;
char* Filesize = new char[5000000]; // is there a better way? my sfiles size are unknown but at least 50mb
if (recv(Socket, Filesize, 5000000, 0)) // File size
{
Size = atoi((const char*)Filesize);
printf("File size: %d\n", Size);
}
char* Buffer = new char[Size];
FILE* File;
File = fopen("test.zip", "wb"); //start copying from the server, creating the file first.
std::string convert;
long conv;
std::cout << "Size: " << Size << std::endl;
int total=Size;
int byteRecv = 0;
int recvCheck;
int bytes = 1025;
//getting the file
while (byteRecv < Size ) {
recvCheck = recv(Socket, Buffer, bytes, 0);
if (recvCheck >0) // File
{
fwrite(Buffer, 1, byteRecv, File);
std::cout << "Recieved:" << byteRecv << std::endl;
Size -= byteRecv;
byteRecv += byteRecv;
std::cout << "Error: " << WSAGetLastError();
}
else {
std::cout << "Error: " << WSAGetLastError();
total += 1; // the loop often get into infinit loop so i force it in case of this error.
if (total > 3) {
break;
}
}
}
fclose(File);
So, i know it is not very efficient and i am not sure if there are similar questions as i have been digging in here for a few weeks now.
-is there a better way i can make a char*[]? as i dont know the size of the files i want to send yet.
- does ftell() and sifeof() work the same way?
-when i check for the size i recved from the server it is alays wrong. Ex: server file: 32633513, recv size: 3263
-most of the code i have taken from other problems and combined it. if you see anything that is not needed do tell me so i take notes of that.
There is a lot of wrong things but that may correct your problem at first:
On the client side replace (your are both decrementing the total count of bytes and the received ones with the wrong value):
Size -= byteRecv;
byteRecv += byteRecv;
with:
byteRecv += recvCheck; // actualizes the count of received bytes
The other problem is your buffer size. Never try to get an entire file in memory, this is nonsense in general; files are usually managed chunks by chunks. As you are reading at most 1025 bytes in each loop, then only use a buffer of size 1025, you don't need more. Same for reading and writing...

Why I am always receiving data on the server side of a socket in C++?

After opening a connection between client and server, I need to handle any write command sent to the server using the command read(); (i.e. when the client write(); the server should read(); right away).
It sounds to be a trivial problem. Firstly, I sent 58 bytes from the client. But, I am always receiving huge amount of data on the server side. Here you could find just the relevant part of code:
int sockfd, newsockfd;//, n0,n1,n2;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int reuse=1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
cerr << "ERROR opening socket"<< endl;
if (setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR,&reuse, sizeof(int)) == -1)
cerr << "ERROR on reusing port"<< endl;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(iport);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
cerr << "ERROR on binding"<< endl;
cout << "Listening on port: "<< iport<< endl;
listen(sockfd,1);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
cerr << "ERROR on accept" << endl;
while (1) {
size_t msgSize=0;
int n = read(newsockfd,&msgSize,sizeof(size_t));
cout << "Breakpoint " << msgSize<< endl;
// Reading bytes size from socket until 10MB
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
if (read(newsockfd, bytes, msgSize) > 0) {
char ip [16];
memset (bytes + msgSize, '\0', MSGMAXSIZE - msgSize - 1);
if (read(newsockfd,ip,15) > 0) {
string cIP = (string)ip;
//cout << "Sender Ip: " << cIP << endl;
process p = currentView.getProcess(cIP);
message m(bytes,p);
cout << "*************************" << endl
<< "Message received:" << endl
<< "*****************" << endl;
m.print();
}
}
}
}
This is the result i got:
Listening on port: 4444
Connected to: 127.0.0.1:6666
Breakpoint 58
*************************
Message received:
*****************
Message text: I am trying to send a message
Message size: 58
Message sender: 127.0.0.1
Message stability: 0
**************************************************
Breakpoint 825634866
Breakpoint 808600630
Breakpoint 842478647
Breakpoint 959854903
Breakpoint 926303542
Breakpoint 876032050
Breakpoint 808601142
Breakpoint 892744503
Breakpoint 875971894
Breakpoint 825634866
Breakpoint 1144401970
Breakpoint 859256118
Breakpoint 825635639
Breakpoint 892745526
Breakpoint 775369265
Breakpoint 774909488
Breakpoint 14897
Segmentation fault
And here you could find the relevant part of code from the client side:
while (1)
{
if (!bufferMsg(m)) break;
}
bool bufferMsg(message m) // Sends a message (m) to a process (p)
{
mtx.lock();
if(fifoBuffer.size() < 5)
{
fifoBuffer.push_back(m);
size_t sizeMsg = m.getHeader().sizeMsg;
byte * bytes = m.getBytes();
if (!write(sendsockfd,&sizeMsg,sizeof(size_t)) || !write(sendsockfd,bytes,sizeMsg) || !write(sendsockfd,(char*)m.getHeader().sender.getIp().c_str(),strlen(m.getHeader().sender.getIp().c_str())))
cerr << "ERROR writing to socket"<< endl;
mtx.unlock();
return true;
}
else{
mtx.unlock();
return false;
}
}
Here you could find the header of the message:
typedef struct HeaderType {
size_t sizeMsg;
process sender; // The header.sender process
//view currentView; // the Current view
//iClock C; // reserved for later use
bool stability; // reserved for later use
}HeaderT;
PS: The terms message and process are some classes which I already created but are out of our concern.
Please feel free should you need more clarification or information.
I have the impression you think that client side write should be blocking and waits until the data is eaten up by the server. The OS is free to deliver as many bytes as it likes on a TCP stream.
You have a lot of if if(read(newsockfd, bytes, msgSize) > 0) in your code where you seem to silently assume that the read either fails completely or delivers exactly the amount of data you're waiting for. That doesn't need to be the case.
This:
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
is dangerous since the byte array (which I assume is a typedef) gets allocated on the stack and I assume no OS on the planet accepts a 10MB local variable. But I might be wrong or even modern compilers start to silently allocate it on the heap. It's the top candidate for your segfault the first time msgSize <10MB. Better do something like:
std::auto_ptr<byte> bytes(new byte[msgSize]);
For your read in of msgSize better do something like:
int n = 0;
int nn = 0;
while((nn=read(newsockfd,((char *)&msgSize)+n,sizeof(size_t)-n)>0
&& n<sizeof(size_t)) {
n+=nn;
}
On the client site you do something like:
write(sendsockfd,(char*)m.getHeader().sender.getIp().c_str(),strlen(m.getHeader().sender.getIp().c_str())
To transfer something like an IP (I assume a string like 88.1.2.250) But on the server side you read it like:
read(newsockfd,ip,15)
which doesn't need to fit each other. That would lead to a frame shift in your read and the next msgSize is bogus. May I assume the the first msgSize you ever read is correct ? Under the assumption that the first read actually delivers sizeof(size-t).
size_t msgSize=0;
int n = 0;
do{
int t=read(newsockfd,((char*)&msgSize) + n, sizeof(size_t) - n);
if(t<0)
continue; //if no data is available (in nonblocking mode, or on timeout)
if(t==0)
break; //connection closed
n+=t; //increase counter n by the amount actually read
} while(n<sizeof(size_t));
cout << "Breakpoint " << msgSize<< endl;
// Reading msgSize bytes from socket until 10MB
if ( n> 0 && msgSize< 10485760) {
byte bytes [msgSize];
n=0;
int t;
while((t=read(newsockfd, bytes + n, msgSize - n)) > 0 //if something was read
&& (n+=t)<msgSize //and the total is below msgSize, we continue reading
|| t<0) //or when there is no data available, we will give it another attempt
{
}
if(t>0){
cout << "successful: " << n << endl;
} else {
cout << "only " << n << " of " << msgSize << "read" << endl;
}
}
Tricky parts explained:
((char*)&msgSize) + n
This casts the pointer to size_t to a pointer to char and + n increments the pointer by n-times the size of the type it points to.
(t=read(newsockfd, bytes + n, msgSize - n)) > 0
An assignment returns the assigned value. It has to be inside brackets, as without brackets the boolean result of the > comparison would be assigned to t.
Sidenote:
You should not send the raw binary representation of an integer value to another computer. The sender might uses a MSB byte order while the recipient could be using LSB. You should use the methods provided to convert from host byte order to network byte order. They are called htonl and ntohl (h:host, to:to, n:network l:long [4 bytes]).

Receive Binary Data and Write (Socket Programming in C++)

i have created server and client to communication. Client sends binary data of image then server receives it and writes to file. I have pasted necessary code below.
std::stringstream binStr;
bytes_received = recv(new_sd, &binStr, sizeof(binStr) ,0);
std::cout << binStr << std::endl;
char buff[1024*1024];
std::string image;
while (!binStr.eof())
{
binStr.read(buff, sizeof (buff));
image.append(buff, binStr.gcount());
}
int id = 1;
std::stringstream ss2;
ss2 << id;
std::string str2 = ss2.str();
std::ofstream img(str2.c_str(),std::ios::binary);
std::cout << image.c_str() << std::endl;
img.write(image.c_str(), image.length());
this code creates file with name as id , but its an empty file. How can i fix it?
You cannot recv() into a std::stringstream like you are attempting to. You have to recv() into a buffer first and then you can copy that data into your std::stringstream afterwards. However, you are using the std::stringstream only as an intermediate to get data into your buff buffer, and then from there to a std::string. You can get rid of the std::stringstream altogether and recv() directly into buff instead. I would even go as far as getting rid of the std::string altogether as well, as you do not really need it:
int id = 1;
std::stringstream ss2;
ss2 << id;
std::ofstream img(ss2.str().c_str(), std::ios::binary);
// 1MB is a lot to put on the stack, use the heap instead
std::vector<char> buff(1024*1024);
do
{
bytes_received = recv(new_sd, &buff[0], buff.size(), 0);
if (bytes_received < 0)
break; // ERROR!
if (bytes_received == 0)
break; // DISCONNECT!
for (int i = 0; i < bytes_received; ++i)
std::cout << buff[i];
std::cout << std::endl;
img.write(&buff[0], bytes_received);
// TODO: if reached the end of the image, stop here
}
while (true);
Unless the sender closes its end of the connection after sending the image data to you, then you need a way to know when the end of the image has been reached. The sender will have to send the image data length to you so you know when to stop reading.