SocketTutorial icon indicating copy to clipboard operation
SocketTutorial copied to clipboard

Changing a message from string to a binary

Open maradanovic opened this issue 4 years ago • 2 comments

Hi,

Thanks for this amazing repo!

I used it to set up a server on a Linux machine. The client is a Unity app running on a HoloLens (UWP), a modification of this script c# (https://foxypanda.me/tcp-client-in-a-uwp-unity-app-on-hololens/).

I'm sending a large polygonal mesh from HL to the server. Because the server is set up to receive a string, I serialize two arrays, of Vector3 vertices and integer triangles/faces, to strings on the client side before sending them across. But, the serialization is very slow, and I was advised to send a compact binary format (https://forum.unity.com/threads/mesh-to-string-conversion-taking-too-long-hope-to-get-some-optimization-suggestions.1172413/#post-7509872).

I was hoping you could help me with this - can the server be modified to accept a binary format, or arrays of floats or integers?

Thanks again for sharing this great work!

maradanovic avatar Sep 21 '21 06:09 maradanovic

Hi, not sure if you are still looking for a solution or what you were actually doing, however here it is i guess?(in c++ not c#). i assume that Append(" ").Append(vt.z).Append("\n"); converts data into human readable version. You can send object reinterpreted as bytes, so binary format? instead of ' ' or '\n' just something like: "fue&"(for 4 byte variable)and hopefully it would be faster? not sure what here is slow if object can be destroyed by the default default destructor, the object is simple and all you need to do is reinterpret your object as char array[sizeof(your_class)].

#include <iostream>
#include <cstring> // std::memcpy

using std::endl;
using std::cout;
using std::string;
using std::memcpy;

void sendData(char * x, long size);
void sendData(const string &x);

struct simple_class{
    int id, size;
    uint64_t content;
    simple_class()
	    :id(*reinterpret_cast<int*>((void*)"asm ")),size(0x6f006f6f),content(0x21216273646f6c20){}
                                   //^ NULL character!
}simple_obj;

struct deep_class{
    int id, size, something; // not deep since the data is "here"
    string name; // deep, since string object contains iterators and pointers, not the string itself
    char *x; // this also make class deep
   // ^ in this case you would need to copy string/pointer content manually
   deep_class()
	   :x(new char('c')),name(" deep class string "), id(*reinterpret_cast<int*>((void*)" id ")), size(*reinterpret_cast<int*>((void*)"size")),something(*reinterpret_cast<int*>((void*)"smth")){}
   ~deep_class(){delete x;}
}deep_obj;

int main(){
    // send simple class
    sendData(/*char array start pointer*/reinterpret_cast<char*>(&simple_obj), /*char array size*/sizeof(simple_obj));
    // or string
    sendData(string(reinterpret_cast<char*>(&simple_obj), sizeof(simple_obj)));
    // send deep class
    const size_t deep_c_data_size = sizeof(deep_obj)
	    +(deep_obj.name.length() + sizeof(*deep_obj.x))
	    -(sizeof(deep_obj.name) +  sizeof( deep_obj.x));
    char *x = new char[ deep_c_data_size ];
    char const * const x0 = x;
    memcpy(x, &deep_obj, sizeof(deep_obj.id)*3);
    cout << "writing " << sizeof(deep_obj.id)*3 << endl;
    cout << "remaining " << deep_c_data_size - sizeof(deep_obj.id)*3 << endl;
    x += ( reinterpret_cast<uint64_t>(&deep_obj.name)-reinterpret_cast<uint64_t>(&deep_obj) );
    cout << "moving fwd " << ( reinterpret_cast<uint64_t>(&deep_obj.name)-reinterpret_cast<uint64_t>(&deep_obj) ) << endl;
    memcpy(x, deep_obj.x, sizeof(*deep_obj.x)); // overwrite copied pointer, because they would be useless on other computer
    cout << "writing " << sizeof(*deep_obj.x) << endl;
    cout << "remaining " << deep_c_data_size - (sizeof(deep_obj.id)*3 + sizeof(*deep_obj.x)) << endl;
    x += sizeof(*deep_obj.x);
    const auto cstr = deep_obj.name.c_str();
    memcpy(x, cstr, deep_obj.name.length());
    cout << "writing " << deep_obj.name.length() << endl;
    cout << "remaining " << deep_c_data_size - (sizeof(deep_obj.id)*3 + sizeof(*deep_obj.x) + deep_obj.name.length()) << endl;
    sendData(string(x0, deep_c_data_size));
    delete x0;
    return 0;
}

void sendData(char *x, long size){
	while(size!=0){
		size--;
		cout << *x << std::flush;
		x++;
	}
	cout << endl;
}
void sendData(const std::string &x){
	cout << x << endl;
}

kofi2718 avatar Jun 29 '22 08:06 kofi2718

Hi, thanks for the reply! Already found the answer though. If anyone wants me to share it just let me know.

maradanovic avatar Oct 02 '22 21:10 maradanovic