3

I'm trying to send boolean values through sockets from Client(Python) to Server(C++).

So I have used json and converted the boolean values to string format and send the string through sockets.

Here is my code: Client side (Python):

# TCP Client Code

host="128.0.0.1"            # Set the server address to variable host

port=8080               # Sets the variable port to 4446

from socket import *             # Imports socket module
import json

s=socket(AF_INET, SOCK_STREAM)      # Creates a socket



s.connect((host,port))          # Connect to server address
print "Successfully connected to the server and ready to send some data"

data= json.dumps("{\"A\":true,\"B\":false,\"C\":false,\"D\":false}")

s.send(data)



msg=s.recv(1024)            # Receives data upto 1024 bytes and stores in variables msg

print "Message from server : " + msg

s.close()                            # Closes the socket
# End of code

Now I'm receving them in the format of string along with \n \t tags. How can I interpret the boolean values sent and assign them to required variables in C++.

Here is my code on Server side (C++):

using namespace std;
//Server side
int main(int argc, char *argv[8080])
{
bool Style1;
    //buffer to send and receive messages with
    char msg[1500];

    //setup a socket and connection tools
    sockaddr_in servAddr;
    memset((char*)&servAddr, 0,sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(8080);

    //open stream oriented socket with internet address
    //also keep track of the socket descriptor
    int serverSd = socket(AF_INET, SOCK_STREAM, 0);
    if(serverSd < 0)
    {
        cerr << "Error establishing the server socket" << endl;
        exit(0);
    }


    //bind the socket to its local address
    int bindStatus = bind(serverSd, (struct sockaddr*) &servAddr, 
        sizeof(servAddr));
    if(bindStatus < 0)
    {
        cerr << "Error binding socket to local address" << endl;
        exit(0);
    }
    cout << "Waiting for a client to connect..." << endl;


    //listen for up to 5 requests at a time
    listen(serverSd, 5);


    //receive a request from client using accept
    //we need a new address to connect with the client
    sockaddr_in newSockAddr;
    socklen_t newSockAddrSize = sizeof(newSockAddr);


    //accept, create a new socket descriptor to 
    //handle the new connection with client
    int newSd = accept(serverSd, (sockaddr *)&newSockAddr, &newSockAddrSize);
    if(newSd < 0)
    {
        cerr << "Error accepting request from client!" << endl;
        exit(1);
    }
    cout << "Connected with client!" << endl;


        //receive a message from the client (listen)
        cout << "Awaiting client response..." << endl;
        memset(&msg, 0, sizeof(msg));//clear the buffer

        recv(newSd, (char*)&msg, sizeof(msg), 0);
        if(!strcmp(msg, "exit"))
        {
            cout << "Client has quit the session" << endl;

        }
        string str(msg);
        cout << "Client: " << msg << endl;
        cout << ">";
        string data = "Instructions Received \n";
        memset(&msg, 0, sizeof(msg)); //clear the buffer
        strcpy(msg, data.c_str());
        if(data == "exit")
        {
            //send to the client that server has closed the connection
            send(newSd, (char*)&msg, strlen(msg), 0);

        }
        //send the message to client
        send(newSd, (char*)&msg, strlen(msg), 0);

    //we need to close the socket descriptors after we're all done



    close(newSd);
    close(serverSd);

    cout << "Connection closed..." << endl;
    return 0;   
}

I'm a beginner, I appreciate you guys in helping me.

FYI - If I print the string in C++ after receiving it looks like this

"{\"A\":true,\"B\":false,\"C\":false,\"D\":false}"

Thanks EVERYONE for your suggestions and I tried using json in C++ and made some changes

#include<iostream>
#include <jsoncpp/json/json.h>
using namespace std;

    void decode()
    {
         bool a,b,c,d;
        string text = "{\"A\":true,\"B\":false,\"C\":false,\"D\":false}";
            Json::Value root;
            Json::Reader reader;
            bool parsingSuccessful = reader.parse( text, root );
            if ( !parsingSuccessful )
                    {
                        cout << "Error parsing the string" << endl;
                    }


            const Json::Value mynamesA = root["A"];
            const Json::Value mynamesB = root["B"];
            const Json::Value mynamesC = root["C"];
            const Json::Value mynamesD= root["D"];


            cout<<mynamesA<<endl;
            cout<<mynamesB<<endl;
            cout<<mynamesC<<endl;
            cout<<mynamesD<<endl;


    }

    int main()
    {   
    decode();
        return 0;
    }

Now its printing

true
false
false
false

as expected. But I want to assign these values to bool a,b,c,d; How can I do that ??

1
  • 3
    Have a look at this JSON library for C++ Commented Oct 12, 2018 at 13:03

2 Answers 2

3

It is best to control what is actually sent.

This line:

data= json.dumps("{\"A\":true,\"B\":false,\"C\":false,\"D\":false}")

is highly suspect: you use json.dumps on what is already a json encoded string when it is supposed to be used on a object to produce the json string.

I have tested it in an interactive Python and got:

>>> data= json.dumps("{\"A\":true,\"B\":false,\"C\":false,\"D\":false}")
>>> print(data)
"{\"A\":true,\"B\":false,\"C\":false,\"D\":false}"
>>> print([(i, hex(ord(i))) for i in data])   # control individual characters
[('"', '0x22'), ('{', '0x7b'), ('\\', '0x5c'), ('"', '0x22'), ('A', '0x41'), ('\\', '0x5c'), ('"', '0x22'), (':', '0x3a'), ('t', '0x74'), ('r', '0x72'), ('u', '0x75'), ('e', '0x65'), (',', '0x2c'), ('\\', '0x5c'), ('"', '0x22'), ('B', '0x42'), ('\\', '0x5c'), ('"', '0x22'), (':', '0x3a'), ('f', '0x66'), ('a', '0x61'), ('l', '0x6c'), ('s', '0x73'), ('e', '0x65'), (',', '0x2c'), ('\\', '0x5c'), ('"', '0x22'), ('C', '0x43'), ('\\', '0x5c'), ('"', '0x22'), (':', '0x3a'), ('f', '0x66'), ('a', '0x61'), ('l', '0x6c'), ('s', '0x73'), ('e', '0x65'), (',', '0x2c'), ('\\', '0x5c'), ('"', '0x22'), ('D', '0x44'), ('\\', '0x5c'), ('"', '0x22'), (':', '0x3a'), ('f', '0x66'), ('a', '0x61'), ('l', '0x6c'), ('s', '0x73'), ('e', '0x65'), ('}', '0x7d'), ('"', '0x22')]

This is an evidence that the offending double quotes (") and backslashes (\) have been sent by the Python code.

What you wanted is probably:

data = '{"A":true,"B":false,"C":false,"D":false}'  # directly store the json string

or

# build the json string from a dict
data = json.dumps({'A': True, 'B': False, 'C': False, 'D': False})
Sign up to request clarification or add additional context in comments.

Comments

2

If possible, it is probably best to use a JSON parsing library. Here is a link to a RapidJSON tutorial that you can use.

If you want to code a solution yourself, then try the below.

Self-coded Solution

Go through the string find all the indices of "\"" and store them in an vector. If none of the values in your key-value pairs are strings, then you can use this to find the keys. So, if you have a vector with 3 and 7 in it, then your key starts at 4 and ends at 6.

You can use similar logic to extract the values. Go through the string and find the first occurrence of ": ". After this, find the first occurrence of "," that is located after the index of the last found ": ". So, if you have 9 and 15 then your value will start at 11 and end at 14.

Just note that when you reach the last value, it will end in "]" as per your example. So, if a comma isn't found, then look for "]" or possibly " ".

bool findKeyIndices(string s, vector<int> & kIndices) {
    string substr = "\"";
    vector<int> indices;

    size_t index = s.find(substr, 0);

    while (index != string::npos) {
         indices.push_back(index);
         s.find(substr, index+1);
    }

    if (indices.size() % 2 != 0)
          return FALSE;

    for(int x =0; x < indices.size(); x++) {
         if(indices.at(x) % 2 == 0) {
               kIndex.push_back(++x);
         } else {
               kIndex.push_back(--x)
         }
    }

    return TRUE;
} 

bool findValIndices(string s, vector<int> & vIndices){
  string start = ": ", endOne = ",", endTwo = "]";
  vector<int> indices;

  size_t index = s.find(start, 0), backupIndex;

  while (index != string::npos) {
         indices.push_back(index);

         backupIndex = index;

         s.find(endOne, index+1);
         if(index != string::npos) {
              indices.push_back(index);
         } else {
              s.find(endTwo, backupIndex + 1);
              if(backupIndex != string::npos){
                    index = backupIndex;
              } else {
                    return FALSE;
              }

         }
    }

    if (indices.size() % 2 != 0)
           return FALSE;

    for(int x =0; x < indices.size(); x++) {
         if(indices.at(x) % 2 == 0) {
               vIndex.push_back(x + 2);
         } else {
               vIndex.push_back(--x)
         }
    }

 }

The solution could have been simpler if you could assume that values will only be true or false. In which case you could find the starting index of each key and the starting index of all "true" and "false" substrings. Then you could figure out from there which key is associated with either true or false.

For example, if you had [2, 10] for the starting indices of the keys and the starting index for "true" was 4, then the key that starts at 2 would be associated with true since key1-start < value1-start < key2-start.

Enhancing the algirithm

The above algorithm assumed none of the values in your key-value pairs were strings. You can modify the above code so you don't have to make that assumption.

Here are the steps:

  1. Find all occurrences of "\"" and store the indices in a vector (call it quoteIndices)
  2. Find all occurrences of commas and store indices in a vector
  3. Find the index of the character that can be used to find the end of the last value. In your example in the comments, it was "]".

Determine the key value pairs using the following equation:

quote-open-indx < key-start-index < key-end-index < quote-close-index < x < (comma-index || end-char)...

Now, x can either be a value or a string. Use a process like the one below to determine what x is and parse accordingly.

  1. The first and second indices in the quoteIndices will always contain a key. So, you can assume that the first quote-end-index is at quoteIndices.at(1). Let's just say it is equal to 5.
  2. If there is another value in quoteIndices such that it is greater than 5 but smaller than the first comma index, then your value is a string. Otherwise, it is not.

7 Comments

FYI - This is how the string is looking if I'm printing it in Server side (C++) "\n{\n\t[\"A\":true,\"B\":false,\"C\":false,\"D\":false]\n}"
Ok, gotcha. Adjusted my answer a bit. Hope this helps.
This is incredibly complex, brittle and error-prone. Why not use an existing JSON library?
@Graindor root["A"].get<bool>() (etc.) should do the trick. You can also use implicit conversions: bool a = root["A"]; works.
@Graindor I read through the documentation on the Json::Value class and I believe you should be able to do the following:if (root["A"] == TRUE) a = TRUE; ELSE IF (root["A"] == FALSE) a = FALSE; ELSE cout << "error" << endl;
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.