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