Socket Write Failure when sending File - c++

I've been stuck on this issue for awhile where I'm unable to send a file through a socket. I've sent other information just fine using this method, but the problem seems to appear when I try to send a PNG file as a string.
These are the methods I use to to send and receive information:
// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message)
{
// Write the Message Size to the Socket
send(socket, itoa((message.length() + 1)), sizeof(size_t));
// Wait for Write Confirmation
bool response;
receive(socket, &response, 2);
// Write the Message to the Socket
send(socket, (char*) message.c_str(), message.length() + 1);
// Wait for Write Confirmation
receive(socket, &response, 2);
}
// Receives Message from the specified Socket
string Server::receiveMessage(int socket)
{
// Read the Message Size from the Socket
int size;
receive(socket, &size, sizeof(size_t));
// Send Write Confirmation
send(socket, itoa(true), 2);
// Receive the Message from the Socket
char message[size];
receive(socket, message, size);
// Send Write Confirmation
send(socket, itoa(true), 2);
// Return the Message as a String
string msg(message);
return msg;
}
The send and receive methods are just relays for write and read respectively. I'm only doing error checking in those methods, and it's the send method that's telling me that the write isn't working. In case it matters, this is my send method:
// Sends a Data Packet to the specified Socket
int Server::send(int socket, void* data, int size)
{
// Write the Data to the Socket
int count = write(socket, data, size);
// Make sure the Write Succeeded
if(count == -1)
{
print("$f1Error: $f0Unable to Write to Socket $t1%i$t0\n", socket);
exit(1);
}
return count;
}
I should note that the Server operates as a Thread, therefore the above three functions are static. The Client also contains the same four networking functions.
The command line breaking this happens in a separate static function which I use to handle Clients. Here is the relevant portion of said method:
// Handles each Client with a Thread
void* Server::server_handleClient(void* arg)
{
// Determine the Socket Descriptor
int socket = *((int*) arg);
free(arg);
// Create the Rover
Rover* rover = new Rover();
// Loop Indefinitely
while(true)
{
...
// Take a Picture and Send it
sendMessage(socket, rover -> takePicture());
...
}
// Delete the Rover
delete rover;
// Close the Socket
close(socket);
// Return a Successful Status
return (void*) new int(0);
}
Here you can see that I make use of a method from another class I've created. Here is the takePicture method from the Rover class, which is where I actually grab the picture:
// Takes a Picture and Returns the Photo as a String
inline string Rover::takePicture()
{
// Open the Picture File
ifstream picture;
string filepath = "./Server/Pictures/" + getDirection() + ".png";
picture.open(filepath.c_str());
// Make sure the File Opened
if(!picture.is_open())
return "";
// Read the File into a String Buffer
stringstream buffer;
buffer << picture.rdbuf();
return buffer.str();
}
So in short, the Server gets a picture from the Rover which it then sends to a Client. When I check the contents of the string for the photo, it's all there. All possible photos are reasonable in size (the photo used for testing is 674,962 bytes, and the buffer size sent is 674,963 which is expected).
I've used these methods for sending various messages, and all of that worked fine. I'm able to send strings (Like "Hello World!") and integers just fine.
Is there something that I'm doing wrong? Is the file that I'm trying to send simply too large? Is there some information that I'm missing? I need help...
Edit:
I've made a few changes with a little progress. I made one small change to the sendMessage command. The current problem is that the picture isn't being sent properly.
New sendMessage function:
// Sends a Message to the specified Socket
void Server::sendMessage(int socket, string message, bool data = false)
{
// Write the Message Size to the Socket
send(socket, itoa((message.length() + 1)), sizeof(size_t));
// Wait for Write Confirmation
bool response;
receive(socket, &response, 2);
// Determine the Type of Data to Send
if(data)
{
// Write the Message Data to the Socket
send(socket, (char*) message.data(), message.length() + 1);
}
else
{
// Write the Message to the Socket
send(socket, (char*) message.c_str(), message.length() + 1);
}
// Wait for Write Confirmation
receive(socket, &response, 2);
}
The Client's copy of this function has been updated to match as well.
Now that we're working on getting the PNG file saved, here's the function that deals with that as well:
// Handles each Client with a Thread
void* Client::client_handleServer(void* arg)
{
// Define Socket Variables
int socket = *((int*) arg);
free(arg);
...
// Export the Picture to the Client's Directory
message = receiveMessage(socket);
ofstream picture;
picture.open("./Client/Pictures/Picture.png", std::ifstream::binary);
picture << message;
picture.close();
...
}

Currently you are opening the file in textmode. that means any characters in the files which contain newlines "\n" are converted to new line + carriage returns "\r\n".
Open your file in binary mode, like so
picture.open(filepath.c_str(), std::ifstream::binary);
then it may work.

void Server::sendMessage(int socket, string message)
The problem is right here. Don't use string as a container for binary data. Pass the image around as a byte array. Same applies to this:
string Server::receiveMessage(int socket)

I eventually figured everything out in the long run.
Pictures are binary files, and I was using Strings which use ASCII Characters. The issue with this is that binary data does not always translate to ASCII, and Strings are terminated by null characters, whereas binary data can contain null data within it. Long story short, strings do not work.
To preserve the message handling I had in place, I ended up just converting the binary data to hexadecimal data (0-F) which could be displayed in a String.

Related

How to check boost socket write_some method ends or not

I am trying to send some data by using boost socket.
TCPClient class's role is to make a connection cna can send data throw sendMessage method.
When I executed under code it does not work. However, it works when I debug it.
I think the problem is timing.
delete[] msg; works before sending msg.(just my thought)
so, I want to check whether msg is sent or not.
or any other good way.
client main() code
TCPClient *client = new TCPClient(ip, port);
client->sendMessage((char *)msg, 64 + headerLength + bodyLength);
delete[] msg;
under code is snedMessage method.
void TCPClient::sendMessage(const char *message, int totalLength) throw(boost::system::system_error) {
if(false == isConnected())
setConnection();
boost::system::error_code error;
this->socket.get()->write_some(boost::asio::buffer(message, totalLength), error);
if(error){
//do something
}
}
Your sendMessage() function is written incorrectly. You cannot expect that socket will send all of your data at once, you need a loop where you try to send, check how many bytes were sent, offset buffer (and update totalLength accordingly of course) if necessary and repeat until all data is sent. Or interrupt if there is error condition. You try to send only once, ignore result and assume that if there is no error then all data was sent. This is not a case. Stream socket may send one or two or whatever amount of bytes at a time, and your code needs to handle that.
Your code should be something like this:
while( totalLength ) {
boost::system::error_code error;
auto sz = this->socket.get()->write_some(boost::asio::buffer(message, totalLength), error);
if(error){
//do something and interrupt the loop
}
totalLength -= sz;
message += sz;
}

Determine Data Type on a TCP Socket in Qt

I am writing a program to send images captured from an OpenCV window over a TCP connection, using Qt libraries to setup the connections etc.
I have to functions (below) which are both working to send either text or a byte array. The problem I have is at the other end how can I tell if the data coming in is plain text, or an array containing an image. Is there an inbuilt way to do this, or do I need to put a byte at the start of the data to tell the receiver what data is coming? I already put the array length at the start of the serialized image data.
void Screenshot_controller::sendText(std::string textToSend)
{
if(connectionMade)
{
std::string endLine = "\r\n";
textToSend = textToSend + endLine;
const char * textChar = textToSend.c_str();
sendSocket->write(textChar);
sendSocket->flush();
qDebug() << "Text Sent from Server";
}
}
void Screenshot_controller::sendData(QByteArray dataToSend)
{
if(connectionMade)
{
sendSocket->write(dataToSend);
sendSocket->flush();
qDebug() << "Data Sent from Server";
}
}
You need to define the protocol yourself, whether that's with a byte, string, JSON header or any other method. The Tcp socket will allow you to transfer the data, but doesn't care what that data is; it's up to you to handle that.

Writing simple file-transfer program using boost::asio. Have major send\receive desync

I am learning boost::asio network programming and tried to make simple file transfer exercise, using blocking sockets, and so, stuck upon strange issue issue.
Server (receiver) loop is following:
while (true){
int bufSize{ static_cast<int>(pow(2, 18)) };
char* buf{ new char[bufSize] };
__int64 currPos{ 0 };
__int64 fileSize;
std::string fileName;
mSocket->receive(buffer(buf, bufSize)); // here we get pre-defined packet with XML
ParseDescXML(std::string{ buf }, &fileName, &fileSize); // and parse this XML, get name and size
std::ofstream ofs(mSavePath + fileName, std::ios::binary);
if (ofs.is_open()){
while (currPos != fileSize) {
if (bufSize > fileSize - currPos){
delete[] buf;
bufSize = fileSize - currPos;
buf = new char[bufSize];
}
mSocket->receive(buffer(buf, bufSize));
ofs.write(buf, bufSize);
currPos += bufSize;
std::cout << "SERVER " << currPos << std::endl;
}
}
delete[] buf;
ofs.close();
slDebug("Receive completed"); // output some stuff, not related to issue
}
client (sender) loop is following:
mWorkerOccupied = true;
std::ifstream ifs(filePath, std::ios::binary);
if (!ifs.is_open()){
mWorkerOccupied = false;
return false;
}
mFileName = filePath.substr(filePath.find_last_of('\\') + 1, filePath.length());
mCurrPos = 0;
mFileSize = GetFileSize(&ifs);
std::string xmlDesc{ MakeXMLFileDesc(mFileName, mFileSize) }; // here we make XML description
xmlDesc.push_back('\0');
int bufSize{ static_cast<int>(pow(2, 18)) };
char* buf{ new char[bufSize] };
mSocket->send(buffer(xmlDesc.c_str(), bufSize)); // and send it.
while (mCurrPos != mFileSize){
if (bufSize > mFileSize - mCurrPos){
delete[] buf;
bufSize = mFileSize - mCurrPos;
buf = new char[bufSize];
}
ifs.read(buf, bufSize);
mSocket->send(buffer(buf, bufSize));
mCurrPos += bufSize;
std::cout << "CLIENT " << mCurrPos << std::endl;
}
ifs.close();
delete[] buf;
mWorkerOccupied = false;
slDebug("SendFile completed");
All this stuff is running in parallels threads.
From my understanding it should be working this way:
Server thread runs servers and hangs, until incoming connection (working as expected, so I did not include this code here).
Client thread runs after some time and connects to server (working as expected)
Server waiting for first packet, contains XML (working as expected)
Client sends XML, server gets it (working as expected)
Client starts to send actual binary data, server get it. Here we have major problem.
I have a output of current position of file in both client and server loop.
I expect it to be something like:
CLIENT 228 // first we send some data
SERVER 228 // Server gets it and outputs the same file pos
or
CLIENT 228
CLIENT 456
SERVER 228
SERVER 456
But what I am actually getting - confuses me...
SERVER 499384320
SERVER 499646464
CLIENT 88604672
SERVER 499908608
CLIENT 88866816
SERVER 500170752
SERVER 500432896
SERVER 500695040
SERVER 500957184
Far more messages regarding receiving something by server, than client ones about sending. How it can be? Literally, looks like client sent only 80mb of data, while server already received 500mb of data... I thought, that server thread should wait on receive(), since I am using blocking socket, but this is strange. Could someone explain me, why I have this huge desync?
You're assuming that receive reads the entire buffer size at once, but it doesn't necessarily:
The receive operation may not receive all of the requested number of bytes. Consider using
the read function if you need to ensure that the requested amount of data is read before the
blocking operation completes
receive returns the amount of data read, you should change your code to something like:
size_t recvd = mSocket->receive(buffer(buf, bufSize));
ofs.write(buf, recvd);
currPos += recvd;

Cannot get response when using socket in C++.NET

I wrote two programs, one as server and another as client. The server is written in standard C++ using WinSock2.h. It is a simple echo server which means the server responds what it receives back to the client. I used a new thread for every client's connection, and in each thread:
Socket* s = (Socket*) a;
while (1) {
std::string r = s->ReceiveLine()
if (r.empty()) {
break;
}
s->SendLine(r);
}
delete s;
return 0;
Socket is a class from here. The server runs properly and I've tested it using telnet, it works well.
Then I wrote the client using C++.NET (or C++/CLI), TcpClient is used to send and receive message from the server. The code is like:
String^ request = "test";
TcpClient ^ client = gcnew TcpClient(server, port);
array<Byte> ^ data = Encoding::ASCII->GetBytes(request);
NetworkStream ^ stream = client->GetStream();
stream->Write(data, 0, data->Length);
data = gcnew array<Byte>(256);
String ^ response = String::Empty;
int bytes = stream->Read(data, 0, data->Length);
response = Encoding::ASCII->GetString(data, 0, bytes);
client->Close();
When I run the client and tries to show the response message onto my form, the program halted at the line int bytes = stream->Read(data, 0, data->Length); and cannot fetch the response. The server is running and there's nothing to do with the network as they are all running on the same computer.
I guess the reason is that the data server responds with is less than data->Length, so the Read method is waiting for more data. Is that right? How should I solve this problem?
Edit
I think I've solved the problem... There are another two methods in the Socket class, ReceiveBytes and SendBytes, and these two methods will not delete the unused space in the bytes array. So the length of data back from the server will match that from the client, thus the Read method will not wait for more data to come.
std::string Socket::ReceiveLine() {
std::string ret;
while (1) {
char r;
switch(recv(s_, &r, 1, 0)) {
case 0: // not connected anymore;
// ... but last line sent
// might not end in \n,
// so return ret anyway.
return ret;
case -1:
return "";
// if (errno == EAGAIN) {
// return ret;
// } else {
// // not connected anymore
// return "";
// }
}
ret += r;
if (r == '\n') return ret;
}
}
i guess receiveline function of the server is waiting for an enter key '\n'.
just try with "test\n" string.
String^ request = "test\n";
// other codes....

Berkeley Socket Send returning 0 on successful non-blocking send

I am writing a non-blocking chat server, so far the server works fine, but I can't figure out how to correct for partial sends if they happen. The send(int, char*, int); function always returns 0 on a success and -1 on a failed send. Every doc/man page I have read says it should return the number of bytes actually feed to the network buffer. I have checked to be sure that I can send to the server and recv back the data repeatedly without problem.
This is the function I use to call the send. I both tried to print the return data to the console first, then tried line breaking on the return ReturnValue; while debugging. Same result, ReturnValue is always 0 or -1;
int Connection::Transmit(string MessageToSend)
{
// check for send attempts on a closed socket
// return if it happens.
if(this->Socket_Filedescriptor == -1)
return -1;
// Send a message to the client on the other end
// note, the last parameter is a flag bit which
// is used for declaring out of bound data transmissions.
ReturnValue = send(Socket_Filedescriptor,
MessageToSend.c_str(),
MessageToSend.length(),
0);
return ReturnValue;
}
Why don't you try to send in a loop? For instance:
int Connection::Transmit(string MessageToSend)
{
// check for send attempts on a closed socket
// return if it happens.
if(this->Socket_Filedescriptor == -1)
return -1;
int expected = MessageToSend.length();
int sent = 0;
// Send a message to the client on the other end
// note, the last parameter is a flag bit which
// is used for declaring out of bound data transmissions.
while(sent < expected) {
ReturnValue = send(Socket_Filedescriptor,
MessageToSend.c_str() + sent, // Send from correct location
MessageToSend.length() - sent, // Update how much remains
0);
if(ReturnValue == -1)
return -1; // Error occurred
sent += ReturnValue;
}
return sent;
}
This way your code will continually try to send all the data until either an error occurs, or all data is sent successfully.