python 和 c++ 之间发消息用json

5 篇文章 0 订阅

这段代码是py发给c++的一个消息包,包里含json字符串,没有c++返回的过程!

-------------------

因为工作需要...中间省略5000字,所以用c++做的服务器,收发消息需要用json来打包并解析消息。
我以前收发消息都是结构体直接强转,所以这也是第一次,发个帖子上来,希望对有的朋友有帮助。
-------------------
先说python,这个语言一直想学,这段时间学了个把星期,发现测试的确非常方便,总比用c++写测试代码好多了,用c++写测试代码的那个蛋疼,py几行代码就搞到了。
准备发上py代码,这之前先做一个大概的说明,这段py代码不是纯粹的发一条json消息,还附带了一个简单的tcp socket的并发连接测试代码,也就是创建N个线程去connect服务器,不需要的自己过滤吧。这段代码用了py的那个好像叫装饰器的东西,就是@这个,不明白的朋友可以百度,简单的来说,我的这个装饰器就是用来统计时间的。

__author__ = 'Administrator'


import socket
import json
import threading
import datetime
import struct


def get_execute_time_p2(f):
    def inner(p1=None, p2=None):
        begin = datetime.datetime.now().microsecond
        f(p1, p2)
        end = datetime.datetime.now().microsecond
        print("{0} execute time is {1}".format(f.__name__, end-begin))
        return f
    return inner


def get_execute_time_p1(f):
    def inner(p1=None):
        begin = datetime.datetime.now().microsecond
        f(p1)
        end = datetime.datetime.now().microsecond
        print("{0} execute time is {1}".format(f.__name__, end-begin))
        return f
    return inner


def get_socket():
    host = "localhost"
    port = 8001
    address = (host, port)

    tcp_socket_temp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_socket_temp.settimeout(2)
    tcp_socket_temp.connect(address)
    return tcp_socket_temp


@get_execute_time_p1
def test_accept(cnt):
    print("thread launched.")

    ok__ = 0
    for xer34 in range(cnt):
        try:
            sd2342 = get_socket()
            # input("enter any key to continue...")
            sd2342.close()
            ok__ += 1
            # print(xer34, end="  ")
            # if xer34 % 30 == 0:
            #     print("")   # C R L F
        except Exception as e:
            print(e)
    print("connect svr success cnt is {0}".format(ok__))


@get_execute_time_p2
def create_thread_to_test_accept(thread_count, con_cnt_every_thread):
    for x342df in range(thread_count):
        thread = threading.Thread(None, test_accept, "test_accept", (con_cnt_every_thread,))
        thread.start()


def print_binary(number):
    for sda24 in range(32):
        if number & (1 << sda24):
            print(1, end="")
        else:
            print(0, end="")

        if (sda24 + 1) % 8 == 0:
            print(" ", end="")


data_list_child = []
for cnt in range(3):
    data_list_child.append({"_f": 123.123, "_long_id": "1234567890123456789"})
data_list = {"_msg_enum": 0, "_buffer": "abcdefg", "_element_len": 3, "_element": data_list_child}

data_json = json.dumps(data_list)
print(data_list)
print(len(data_json), data_json)

# use 4 threads and every thread executes 10000 connections test to connect svr
# test OK!
# create_thread_to_test_accept(4, 50000)


my_fmt = "i{0}s".format(len(data_json))
print(my_fmt)
send_string = struct.pack(my_fmt, 4 + len(data_json), bytes(data_json, "utf8"))
print(send_string, type(send_string))
a1, a2 = struct.unpack(my_fmt, send_string)
print(a1, a2)
tmp_socket = get_socket()
tmp_socket.send(send_string)
input("enter 'enter' to close socket and quit.")
tmp_socket.close()

使用的py3,运行结果差点忘记了,如下:

E:\Python34\python.exe E:/PycharmProjects/study/resource-svr-test.py
{'_msg_enum': 0, '_element_len': 3, '_buffer': 'abcdefg', '_element': [{'_long_id': '1234567890123456789', '_f': 123.123}, {'_long_id': '1234567890123456789', '_f': 123.123}, {'_long_id': '1234567890123456789', '_f': 123.123}]}
227 {"_msg_enum": 0, "_element_len": 3, "_buffer": "abcdefg", "_element": [{"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}]}
i227s
b'\xe7\x00\x00\x00{"_msg_enum": 0, "_element_len": 3, "_buffer": "abcdefg", "_element": [{"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}]}' <class 'bytes'>
231 b'{"_msg_enum": 0, "_element_len": 3, "_buffer": "abcdefg", "_element": [{"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}, {"_long_id": "1234567890123456789", "_f": 123.123}]}'
enter 'enter' to close socket and quit.

Process finished with exit code 0
或许你看到了在大括号“{”前面的227,这个227是一个完整的消息包的一部分,但是不属于json的一部分,这个227表示整个包的大小,做tcp socket的应该都知道,这个协议收到的包是要自己拆粘的。包的格式是:
{int, char[]}。

-----------------

以上py的已经说完了,下面说c++的代码,c++用的jsoncpp解析的,这个使用非常简单,这里只传上解析的过程, 因为c++的代码太多.下面第一部分代码是从消息包里解析出json,1:

	static Json::Reader _g_this_reader;
	void DoClientReq::Do(__cr_phd_ptr phd)
	{
		/* 包头定义包的长度,该定义不属于json需要解析的范围 */
		Json::Value value;
		char* buffer = phd->_buffer.Get() + HEADSIZE;
		_g_this_reader.parse(buffer, buffer + phd->_offset, value);
		do_client_req(value);
	}
第二部分是获取json里的内容,内容涵盖了int, int64, float/double, char[], 以及结构体里的数组信息等:

void DoClientReq::do_client_req(const Json::Value& value)
	{
		if (value.empty() || !value.isMember("_msg_enum")){
			return;
		}

		eProtocol e = (eProtocol)value["_msg_enum"].asInt();

		switch (e)
		{
		case eProtocol::_req_test:
			/* 227 {"_buffer": "abcdefg", "_element_len": 3, "_msg_enum": 0, "_element": [{"_f": 123.123, "_long_id": "1234567890123456789"}, {"_f": 123.123, "_long_id": "1234567890123456789"}, {"_f": 123.123, "_long_id": "1234567890123456789"}]} */
			/* 
			 *	227 
			 *	{"_buffer": "abcdefg", "_element_len": 3, "_msg_enum": 0, 
			 *	"_element": \
			 *		[{"_f": 123.123, "_long_id": "1234567890123456789"}, 
			 *		{"_f": 123.123, "_long_id": "1234567890123456789"}, 
			 *		{"_f": 123.123, "_long_id": "1234567890123456789"}]}
			 */
			{
				printf("\n-------------------JSON TEST BEGIN-----------------------------\n");
				printf("_msg_enum(int):		%d\n", value["_msg_enum"].asInt());
				printf("_buffer(char[]):	%s\n", value["_buffer"].asCString());
				printf("_element_len(int):	%d\n", value["_element_len"].asInt());

				Json::Value child = value["_element"];
				for (int i = 0; i < value["_element_len"].asInt(); i++)
				{
					printf("_element(array):\n");
					printf("\t_element::_long_id(int64):	%lld\n", _atoi64(child[i]["_long_id"].asCString()));
					printf("\t_element::_f(double/float):	%f\n", child[i]["_f"].asDouble());
				}
				printf("-------------------JSON TEST END-------------------------------\n");
			}
			break;
		default:
			break;
		}
	}

下面附上c++解析的结果:

-------------------JSON TEST BEGIN-----------------------------
_msg_enum(int):         0
_buffer(char[]):        abcdefg
_element_len(int):      3
_element(array):
        _element::_long_id(int64):      1234567890123456789
        _element::_f(double/float):     123.123000
_element(array):
        _element::_long_id(int64):      1234567890123456789
        _element::_f(double/float):     123.123000
_element(array):
        _element::_long_id(int64):      1234567890123456789
        _element::_f(double/float):     123.123000
-------------------JSON TEST END-------------------------------


或许你看到了解析int64的过程,我发现,py如果发字符串"12345678901234567890"20个字符给c++解析成int64的时候,会出问题,解析的不对,没有报错。

如果去掉最后一个0,则解析成功,难道19位数字是有符号int64的最大数字长度?如果有朋友了解,麻烦回复下,谢谢!以便我日后参考以及留给他人。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值