Send messages between sockets - c++

I have 1 server that's built with C++ and c sockets in Unix. The client is using QT and the socket api that comes with it.
The server sends 345 bytes of data to the client.
Sending message from server:
void Moderator::testSynch(){
int type = (int) SYNCRHONIZE_M;
//Update all connected clients with info about other clients
for(int i = 0; i<nrOfClients_; i++){
const TcpSocket &clientSocket = clients_[i].getSocket();
int clientID = clients_[i].getID();
int tempType = htonl(type);
int tempClientID = htonl(clientID);
int tempNrOfClients = htonl(funNrOfClients);
clientSocket.writeData((const char*) &tempType, sizeof(tempType));
clientSocket.writeData((const char*) &tempClientID, sizeof(tempClientID));
clientSocket.writeData((const char*) &tempNrOfClients, sizeof(tempNrOfClients));
for(int j = 0; j<nrOfClients; j++){ //Send info about connectecd clients
int tempLength = (int) clients_[j].getName().length();
int tempID = clients_[j].getID();
string tempName = clients_[j].getName();
tempID = htonl(tempID);
tempLength = htonl(tempLength);
clientSocket.writeData((const char*) &tempID, sizeof(tempID));
clientSocket.writeData((const char*) &tempLength, sizeof(tempLength));
clientSocket.writeData(tempName.c_str(), (int)tempName.length());
}
}
}
bool TcpSocket::writeData(const char* buffer, int length)const{
size_t bytesLeft = length;
ssize_t bytesWritten = 0;
while((bytesWritten = write(socketFD_, buffer, bytesLeft)) > 0){
bytesLeft -= bytesWritten;
buffer += bytesWritten;
}
return bytesLeft == 0;
}
Reading message in client:
void ChatClient::readMessage(Message &message){
if(socket_->readData((char*) &type, sizeof(type))){
if(type == SYNCRHONIZE_M){
int nrOfUsers = 0;
socket_->readData((char*) &ID_, sizeof(ID_)); //Set the client ID that server gave us
socket_->readData((char*) &nrOfUsers, sizeof(nrOfUsers));
ID_ = ntohl(ID_);
nrOfUsers = ntohl(nrOfUsers);
qDebug("%s=%d", "nrOfUsers", nrOfUsers);
message.setMessageType(SYNCRHONIZE_M);
messageOK = true;
for(int i = 0; i<nrOfUsers; i++){ //Update client with all connected users to server
int userID = 0;
int nameLength = 0;
socket_->readData((char*) &userID, sizeof(userID));
socket_->readData((char*) &nameLength, sizeof(nameLength));
userID = ntohl(userID);
nameLength = ntohl(nameLength);
if(nameLength > 0){
qDebug("%s=%d", "nameLength", nameLength);
buffer = new char[nameLength];
socket_->readData(buffer, nameLength);
message.addUser(ConnectedUser(buffer, nameLength, userID));
delete [] buffer;
}
}
}
}
}
bool TcpSocket::readData(char* buffer, int length){
int bytesLeft = length;
int bytesRead = 0;
while((bytesRead = qSocket_->read(buffer, bytesLeft)) > 0){
bytesLeft -= bytesRead;
buffer += bytesRead;
}
return bytesLeft == 0;
}
The problem i'm having is sometimes the entire message from server is not available at once.
For example, first 45 bytes is available in the client. The client then tries to read the entire message (345 bytes) which results in weird behavior. Immediately after the client is done reading the next 300 bytes becomes available.
What is the best way to send messages between sockets? Also, how can I determine if the entire message have been received?

You have some notion of a "message" that exists only in your head. Nothing in your code reflects that. If you have an application protocol that involves a "message" that is sent, then you need to write code to send a message and code to receive a message based on your protocol's definition of a message. TCP only provides streams of bytes and doesn't glue them together for the application into anything bigger than one byte.

Related

how can I receive all message by libevent

Currently, I use libevent to send and receive messages. The issue I am currently encountering is that I do not receive all messages on the server; and only receive the first message I sent.
Client Code:
for (int i=0; i < 10 ; i++)
{
bufferevent_write(bev, data, strlen(data) + 1);
}
Server Code:
static void read_cb(struct bufferevent* bev, void* arg)
{
char buf[2048] = {};
bufferevent_read(bev, buf, sizeof(buf));
//do something
}
I have modified the client like this:
for (int i=0; i < 10 ; i++)
{
bufferevent_write(bev, data, strlen(data) + 1);
sleep(1)
}
When I add a sleep(1),I can receive all messages.
I would like to avoid using sleep(1). What needs to be added / changed in code, such that all messages can be received, and sleep is not used.
This situation seems to be a bit like a spacket splicing problem, you can try this
static void read_cb(struct bufferevent* bev, void* arg)
{
char bufs[2048];
struct evbuffer *input = bufferevent_get_input(bev);
size_t lens = evbuffer_get_length(input);
char * rline = bufs;
while( lens > 0){
char buf [1024]
memcpy(buf, rline, strlen(data));
rline = rline + strlen(data);
lens = lens -strlen(data);
// use buf do something else
}
}

Why is msgrcv() feeding garbage characters into the buffer?

right now, I am currently trying to output the contents of buf.mtext so I can make sure take the correct input before moving on with my program. Everything seems to work fine, except one thing; msgrcv() puts garbage characters into the buffer, and the reciever process outputs garbage characters.
Here is my sender process:
int main (void)
{
int i; // loop counter
int status_01; // result status
int msqid_01; // message queue ID (#1)
key_t msgkey_01; // message-queue key (#1)
unsigned int rand_num;
float temp_rand;
unsigned char eight_bit_num;
unsigned char counter = 0;
unsigned char even_counter = 0;
unsigned char odd_counter = 0;
srand(time(0));
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf_01;
msgkey_01 = MSG_key_01; // defined at top of file
msqid_01 = msgget(msgkey_01, 0666 | IPC_CREAT)
if ((msqid_01 <= -1) { exit(1); }
/* wait for a key stroke at the keyboard ---- */
eight_bit_num = getchar();
buf_01.mtype = 1;
/* send one eight-bit number, one at a time ------------ */
for (i = 0; i < NUM_REPEATS; i++)
{
temp_rand = ((float)rand()/(float)RAND_MAX)*255.0;
rand_num = (int)temp_rand;
eight_bit_num = (unsigned char)rand_num;
if ((eight_bit_num % 2) == 0)
{
printf("Even number: %d\n", eight_bit_num);
even_counter = even_counter + eight_bit_num;
}
else
{
printf("Odd number: %d\n", eight_bit_num);
odd_counter = odd_counter + eight_bit_num;
}
/* update the counters ------------------------------ */
counter = counter + eight_bit_num;
if((eight_bit_num % 2) == 0) { even_counter = even_counter + eight_bit_num; }
else { odd_counter = odd_counter + eight_bit_num; }
buf_01.mtext[0] = eight_bit_num; // copy the 8-bit number
buf_01.mtext[1] = '\0'; // null-terminate it
status_01 = msgsnd(msqid_01, (struct msgbuf *)&buf_01, sizeof(buf_01.mtext), 0);
status_01 = msgctl(msqid_01, IPC_RMID, NULL);
}
Here is my receiver process:
int main() {
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf;
int msqid;
key_t msgkey;
msgkey = MSG_key_01;
msqid = msgget(msgkey, 0666); // connect to message queue
if (msqid < 0) {
printf("Failed\n");
exit(1);
}
else {
printf("Connected\n");
}
if (msgrcv(msqid, &buf, BUFFER_SIZE, 0, 0) < 0) { // read message into buf
perror("msgrcv");
exit(1);
}
printf("Data received is: %s \n", buf.mtext);
printf("Done receiving messages.\n");
return 0;
}
The output is usually something like as follows:
Data received is: ▒
Done receiving messages.
I have made sure to clear my message queues each time after running the sender and receiver processes, as well, since I have come to find out this can cause issues. Thanks in advance for your help.
Turns out neither of the suggested solutions were the issue, as I suspected; the sender process actually works just fine. The problem was that I was trying to print buf.mtext instead of buf.mtext[0] which isn't an actual integer value. I fixed the issue by just doing this:
int temp_num = buf.mtext[0];
printf("Data recieved is %d \n", temp_num);

How to get the exact message from recv() in winsock programming?

I'm developing a server-client application using Winsock in c++ and have a problem.
For getting the message from the client by the server I use the code below.
int result;
char buffer[200];
while (true)
{
result = recv(client, buffer, 200, NULL);
if (result > 0)
cout << "\n\tMessage from client: \n\n\t" << message << ";";
}
I send the message "Hello" from the client to the server. However the buffer is actually this:
HelloÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ
What am I missing?
Since recv might not receive as many bytes as you told it, you typically use a function
like this to receive specified number of bytes. Modified from here
int receiveall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've received
int bytesleft = *len; // how many we have left to receive
int n = -1;
while(total < *len) {
n = recv(s, buf+total, bytesleft, 0);
if (n <= 0) { break; }
total += n;
bytesleft -= n;
}
*len = total; // return number actually received here
return (n<=0)?-1:0; // return -1 on failure, 0 on success
}
It's up to you to null terminate the string if you receive string which is not null terminated.
The result tells you how many bytes were received. recv doesn't add a terminator since, in general, network data is binary data which might not be usable as a C-style string.
You can add a terminator yourself, if you know the message won't contain the termination character:
buffer[result] = 0; // make sure the buffer is large enough
or make a string (or vector, or whatever) from it:
std::string message_str(message, result);
Note that what you receive might not be a single "message", especially if you're uses a stream protocol like TCP. It might contain more than one message, or just the start of one.
memset(&receive[0], 0, sizeof(receive));
To clear the buffer
You didn't initialize your buffer
char buffer[200] = {0};
while (true)
{
result = recv(client, buffer, 200, NULL);
if (result > 0)
cout << "\n\tMessage from client: \n\n\t" << message << ";";
memset(buffer, 0, 200);
}

fopen, fprintf and fclose forces socket connection end

I have a dll which hooks recv function of a network application. The code works just fine (it makes everything its suppossed to do), but if i add output logs to a file, the connection closes after some time working (the server side application throws the error "An existing connection was forcibly closed by the remote host").
That time isnt even always the same, sometimes it closes almost when initializing connection, other times i can use the connection for few secs before it gets closed. It does not give any error or warning message. If i remove the log code, the application runs fine. Any idea why is that happening? I run it in windows 8 x64
Also, even erasing the log code, the connection keeps being closed in windows xp x32.
Here is the recv hook code:
int __stdcall NewRecv(SOCKET socket, char *data, int datalen, int flags) {
int result = 0;
if(!IsLoginServerPacket(&socket)) {
INT size = 0,opcode = 0,temp = 0,writer = 0,second_op = 0;
do {
size = 0;
second_op = 0;
temp = 0;
writer = 0;
while(temp < 2) {
temp += recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
writer += temp;
}
size = (*(SHORT*)recv_gs_buffer) & 0xffff;
// THIS IS THE LOG CODE
FILE *f = fopen("debug.txt", "a");
fprintf(f, "datalen=%d, size=%d\n", datalen, size);
fclose(f);
while(temp < size) {
temp += recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
writer += temp;
}
Decrypt(&gs_crypt,recv_gs_buffer+2,size-2);
opcode = (*(recv_gs_buffer+2) & 0xff);
if(opcode == EXTENDED_PROTOCOL) {
second_op = *(SHORT*)(recv_gs_buffer + 3);
second_op &= 0xffff;
HandleGameServerPacket(second_op,recv_gs_buffer+2,size-2);
}
} while(second_op == 0x8a || second_op == 0x8b);
if(opcode == 0x00) {
SetKey(recv_gs_buffer+4,&gs_crypt);
SetKey(recv_gs_buffer+4,&client_crypt);
} else
Crypt(&client_crypt,recv_gs_buffer+2,size-2);
int i = 0;
while(i < size) {
data[i] = recv_gs_buffer[i];
i++;
}
//memcpy(data,recv_gs_buffer,size);
result = size;
} else
result = recvPacket(socket,data,datalen,flags);
return result;
}
I just found the problem and its solution.
The injected app was configuring sockets on non blocking mode. Any little delay was making it throwing WSAEWOULDBLOCK (10035 error code). All i had to do to fix it was to retry the recv request if i get any error
INT val = 0;
while(temp < 2) {
val = recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
if(val > 0) {
temp += val;
writer += temp;
}
}
And
val = 0;
while(temp < size) {
val = recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
if(val > 0) {
temp += val;
writer += temp;
}
}

How can I send all data over a socket?

I am trying to send large amounts of data over a socket, sometimes when I call send (on Windows) it won't send all the data I requested, as expected. So, I wrote a little function that should have solved my problems- but it's causing problems where the data isn't being sent correctly and causing the images to be corrupted. I'm making a simple chat room where you can send images (screenshots) to each other.
Why is my function not working?
How can I make it work?
void _internal_SendFile_alignment_512(SOCKET sock, BYTE *data, DWORD datasize)
{
Sock::Packet packet;
packet.DataSize = datasize;
packet.PacketType = PACKET_FILETRANSFER_INITIATE;
DWORD until = datasize / 512;
send(sock, (const char*)&packet, sizeof(packet), 0);
unsigned int pos = 0;
while( pos != datasize )
{
pos += send(sock, (char *)(data + pos), datasize - pos, 0);
}
}
My receive side is:
public override void OnReceiveData(TcpLib.ConnectionState state)
{
if (state.fileTransfer == true && state.waitingFor > 0)
{
byte[] buffer = new byte[state.AvailableData];
int readBytes = state.Read(buffer, 0, state.AvailableData);
state.waitingFor -= readBytes;
state.bw.Write(buffer);
state.bw.Flush();
if (state.waitingFor == 0)
{
state.bw.Close();
state.hFile.Close();
state.fileTransfer = false;
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Ended file transfer with " + ip);
}
}
else if( state.AvailableData > 7)
{
byte[] buffer = new byte[8];
int readBytes = state.Read(buffer, 0, 8);
if (readBytes == 8)
{
Packet packet = ByteArrayToStructure<Packet>(buffer);
if (packet.PacketType == PACKET_FILETRANSFER_INITIATE)
{
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
String filename = getUniqueFileName("" + ip.Address);
if (filename == null)
{
Program.MainForm.log("Error getting filename for " + ip);
state.EndConnection();
return;
}
byte[] data = new byte[state.AvailableData];
readBytes = state.Read(data, 0, state.AvailableData);
state.waitingFor = packet.DataSize - readBytes;
state.hFile = new FileStream(filename, FileMode.Append);
state.bw = new BinaryWriter(state.hFile);
state.bw.Write(data);
state.bw.Flush();
state.fileTransfer = true;
Program.MainForm.log("Initiated file transfer with " + ip);
}
}
}
}
It receives all the data, when I debug my code and see that send() does not return the total data size (i.e. it has to be called more than once) and the image gets yellow lines or purple lines in it — I suspect there's something wrong with sending the data.
I mis-understood the question and solution intent. Thanks #Remy Lebeau for the comment to clarify that. Based on that, you can write a sendall() function as given in section 7.3 of http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n = 0;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) {
/* print/log error details */
break;
}
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
You need to check the returnvalue of send(). In particular, you can't simply assume that it is the number of bytes sent, there is also the case that there was an error. Try this instead:
while(datasize != 0)
{
n = send(...);
if(n == SOCKET_ERROR)
throw exception("send() failed with errorcode #" + to_string(WSAGetLastEror()));
// adjust pointer and remaining number of bytes
datasize -= n;
data += n;
}
BTW:
Make that BYTE const* data, you're not going to modify what it points to.
The rest of your code seems too complicated, in particular you don't solve things by aligning to magic numbers like 512.