Reputation: 55
I am trying to send data to a local server using JSON from a client in C++ over TCP. This is my JSON server
comm.js
'use strict';
const net = require('net');
var client = new net.Socket();
var _SIGNATURE = 206;
client.connect(5000, '192.168.1.107', function () {
let info = {
"alo":"alo"
}
let message = JSON.stringify(info);
var messageLength = Buffer.byteLength(message, 'utf8');
var buffer = Buffer.alloc(messageLength + 6);
console.log(buffer);
buffer.writeUInt16LE(_SIGNATURE, 0);
console.log(buffer);
buffer.writeUInt32LE(messageLength, 2);
console.log(buffer);
buffer.write(message, 6);
console.log(buffer);
console.log(`${buffer} -> ${messageLength}` );
client.write(buffer);
})
And my C++ client
/**
C++ client
*/
#include<iostream> //cout
#include <sstream>
#include<stdio.h> //printf
#include<string.h> //strlen
#include<string> //string
#include<sys/socket.h> //socket
#include<arpa/inet.h> //inet_addr
#include<netdb.h> //hostent
using namespace std;
/**
TCP Client class
*/
class tcp_client {
private:
int sock;
std::string address;
int port;
struct sockaddr_in server;
public:
tcp_client();
bool conn(string, int);
bool send_data(string data);
string receive(int);
};
tcp_client::tcp_client() {
sock = -1;
port = 0;
address = "";
}
/**
Connect to a host on a certain port number
*/
bool tcp_client::conn(string address , int port) {
//create socket if it is not already created
if(sock == -1)
{
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1)
{
perror("Could not create socket");
}
cout<<"Socket created\n";
}
else { /* OK , nothing */ }
//setup address structure
if(inet_addr(address.c_str()) == -1) {
struct hostent *he;
struct in_addr **addr_list;
//resolve the hostname, its not an ip address
if ( (he = gethostbyname( address.c_str() ) ) == NULL) {
//gethostbyname failed
herror("gethostbyname");
cout<<"Failed to resolve hostname\n";
return false;
}
//Cast the h_addr_list to in_addr , since h_addr_list also has the ip address in long format only
addr_list = (struct in_addr **) he->h_addr_list;
for(int i = 0; addr_list[i] != NULL; i++) {
//strcpy(ip , inet_ntoa(*addr_list[i]) );
server.sin_addr = *addr_list[i];
cout<<address<<" resolved to "<<inet_ntoa(*addr_list[i])<<endl;
break;
}
}
//plain ip address
else {
server.sin_addr.s_addr = inet_addr( address.c_str() );
}
server.sin_family = AF_INET;
server.sin_port = htons( port );
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0) {
perror("connect failed. Error");
return 1;
}
cout<<"Connected\n";
return true;
}
/**
Send data to the connected host
*/
bool tcp_client::send_data(string data) {
//Send some data
if( send(sock , data.c_str() , strlen( data.c_str() ) , 0) < 0) {
perror("Send failed : ");
return false;
}
cout<<"Data send\n";
return true;
}
/**
Receive data from the connected host
*/
string tcp_client::receive(int size=512) {
char buffer[size];
string reply;
//Receive a reply from the server
if( recv(sock , buffer , sizeof(buffer) , 0) < 0) {
puts("recv failed");
}
reply = buffer;
return reply;
}
int main(int argc , char *argv[]) {
tcp_client c;
string host, test;
host = "192.168.1.107";
cout<<"Hostname : 192.168.1.107:5000";
//connect to host
c.conn(host , 5000);
//send some data
std::cout << "Enter string to send:" << '\n';
cin >> test;
c.send_data(test);
//receive and echo reply
cout<<"----------------------------\n\n";
cout<<c.receive(1024);
cout<<"\n\n----------------------------\n\n";
//done
return 0;
}
The issue is that the JSON server needs to receive the value of _SIGNATURE 206
in byte form first to recognize the data or else it crashes. I've tried bit-shifting but that didn't work and I also tried memset()
on the data string from the client though that also failed.
I'm doing research to find a solution but am hoping someone here may know the answer, maybe something to do with the data buffer in the send function?
Any help is appreciated!
Upvotes: 0
Views: 4234
Reputation: 136475
You made a few common errors with send/recv
:
send
does not necessarily send an entire buffer. You need to keep calling send
until all bytes have been sent.recv
may receive less than expected and the received data is not zero-terminated, so you cannot do strlen
on it or pass it to std::string
. Rather do reply.append(buffer, received_bytes);
, where received_bytes
is the return value of recv
.Upvotes: 2