protobuf实战操作

 lua调用C/C++函数发送数据

主要操作函数是lua_table_to_protobuf

static google::protobuf::Message* lua_table_to_protobuf(lua_State* L, int stackIdx, const char* msg_name){
	if (!lua_istable(L, stackIdx)){
		return NULL;
	}
	Message* message = proto_man::create_message(msg_name);
	if (!message) {
		log_error("cant find message  %s from compiled poll \n", msg_name);
		return NULL;
	}

	const Reflection* reflection = message->GetReflection();
	const Descriptor* descriptor = message->GetDescriptor();

	// 遍历table的所有key, 并且与 protobuf结构相比较。如果require的字段没有赋值, 报错! 如果找不到字段,报错!
	for (int32_t index = 0; index < descriptor->field_count(); ++index) {
		const FieldDescriptor* fd = descriptor->field(index);
		const string& name = fd->name();

		bool isRequired = fd->is_required();
		bool bReapeted = fd->is_repeated();
		lua_pushstring(L, name.c_str());
		lua_rawget(L, stackIdx);

		bool isNil = lua_isnil(L, -1);

		if (bReapeted) {
			if (isNil) {
				lua_pop(L, 1);
				continue;
			}
			else {
				bool isTable = lua_istable(L, -1);
				if (!isTable) {
					log_error("cant find required repeated field %s\n", name.c_str());
					proto_man::release_message(message);
					return NULL;
				}
			}

			lua_pushnil(L);
			for (; lua_next(L, -2) != 0;) {
				switch (fd->cpp_type()) {

				case FieldDescriptor::CPPTYPE_DOUBLE:
				{
														double value = luaL_checknumber(L, -1);
														reflection->AddDouble(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_FLOAT:
				{
													   float value = luaL_checknumber(L, -1);
													   reflection->AddFloat(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_INT64:
				{
													   int64_t value = luaL_checknumber(L, -1);
													   reflection->AddInt64(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_UINT64:
				{
														uint64_t value = luaL_checknumber(L, -1);
														reflection->AddUInt64(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
				{
														int32_t value = luaL_checknumber(L, -1);
														const EnumDescriptor* enumDescriptor = fd->enum_type();
														const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
														reflection->AddEnum(message, fd, valueDescriptor);
				}
					break;
				case FieldDescriptor::CPPTYPE_INT32:
				{
													   int32_t value = luaL_checknumber(L, -1);
													   reflection->AddInt32(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_UINT32:
				{
														uint32_t value = luaL_checknumber(L, -1);
														reflection->AddUInt32(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_STRING:
				{
														size_t size = 0;
														const char* value = luaL_checklstring(L, -1, &size);
														reflection->AddString(message, fd, std::string(value, size));
				}
					break;
				case FieldDescriptor::CPPTYPE_BOOL:
				{
													  bool value = lua_toboolean(L, -1);
													  reflection->AddBool(message, fd, value);
				}
					break;
				case FieldDescriptor::CPPTYPE_MESSAGE:
				{
														 Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
														 if (!value) {
															 log_error("convert to message %s failed whith value %s\n", fd->message_type()->name().c_str(), name.c_str());
															 proto_man::release_message(value);
															 return NULL;
														 }
														 Message* msg = reflection->AddMessage(message, fd);
														 msg->CopyFrom(*value);
														 proto_man::release_message(value);
				}
					break;
				default:
					break;
				}

				// remove value, keep the key
				lua_pop(L, 1);
			}
		}
		else {

			if (isRequired) {
				if (isNil) {
					log_error("cant find required field %s\n", name.c_str());
					proto_man::release_message(message);
					return NULL;
				}
			}
			else {
				if (isNil) {
					lua_pop(L, 1);
					continue;
				}
			}

			switch (fd->cpp_type()) {
			case FieldDescriptor::CPPTYPE_DOUBLE:
			{
													double value = luaL_checknumber(L, -1);
													reflection->SetDouble(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_FLOAT:
			{
												   float value = luaL_checknumber(L, -1);
												   reflection->SetFloat(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_INT64:
			{
												   int64_t value = luaL_checknumber(L, -1);
												   reflection->SetInt64(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_UINT64:
			{
													uint64_t value = luaL_checknumber(L, -1);
													reflection->SetUInt64(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
			{
													int32_t value = luaL_checknumber(L, -1);
													const EnumDescriptor* enumDescriptor = fd->enum_type();
													const EnumValueDescriptor* valueDescriptor = enumDescriptor->FindValueByNumber(value);
													reflection->SetEnum(message, fd, valueDescriptor);
			}
				break;
			case FieldDescriptor::CPPTYPE_INT32:
			{
												   int32_t value = luaL_checknumber(L, -1);
												   reflection->SetInt32(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_UINT32:
			{
													uint32_t value = luaL_checknumber(L, -1);
													reflection->SetUInt32(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_STRING:
			{
													size_t size = 0;
													const char* value = luaL_checklstring(L, -1, &size);
													reflection->SetString(message, fd, std::string(value, size));
			}
				break;
			case FieldDescriptor::CPPTYPE_BOOL:
			{
												  bool value = lua_toboolean(L, -1);
												  reflection->SetBool(message, fd, value);
			}
				break;
			case FieldDescriptor::CPPTYPE_MESSAGE:
			{
													 Message* value = lua_table_to_protobuf(L, lua_gettop(L), fd->message_type()->name().c_str());
													 if (!value) {
														 log_error("convert to message %s failed whith value %s \n", fd->message_type()->name().c_str(), name.c_str());
														 proto_man::release_message(message);
														 return NULL;
													 }
													 Message* msg = reflection->MutableMessage(message, fd);
													 msg->CopyFrom(*value);
													 proto_man::release_message(value);
			}
				break;
			default:
				break;
			}
		}

		// pop value
		lua_pop(L, 1);
	}

	return message;



	return  NULL;
}

protobuf实战操作_第1张图片

protobuf文件

syntax = "proto3"; 
enum Cmd {
	eLoginReq = 0;
	eLoginRes = 1;
}

message LoginReq {  
  string name = 1;  
  int32 age = 2;  
  string email = 3;  
  repeated int32 int_set = 4;
}

message LoginRes {
  int32 status = 1;	
}

lua_table_to_protobuf(toLua_S, 6, msg_name);     //msg_name就是根据ctype返回的命令名称

假如发送数据是

Data = {
    Stype = 0,
    ctype = 0, 
    utag = 0,
    body = { 
        Name:’hello’,
        Age:20,
        Email:’[email protected]’,
        int_set:[a = 100, b = 200, c = 300]
    }
}

const Reflection* reflection = message->GetReflection();

const Descriptor* descriptor = message->GetDescriptor();

获得Message对象的反射和描述

const FieldDescriptor* fd = descriptor->field(index);

const string& name = fd->name()   //得到name = ‘Name’

 

获取索引6表中的key为Name的value压入栈中

lua_pushstring(L, name.c_str());

lua_rawget(L, stackIdx);

Stack: session,table,stype,ctype,tag, body, hello

fd->cpp_type = CPPTYPE_STRING;

把hello 通过反射reflection->AddString写入到Message中

size_t size = 0;

const char* value = luaL_checklstring(L, -1, &size);

reflection->AddString(message, fd, std::string(value, size));

 

循环到int_set是repeated的就执行if循环

先压入一个nil,lua_pushnil(L);作为key位  table在-2索引上

lua_next(L,-2); 可以遍历lua表中的数据,到尾部就返回0退出循环,

 

C/C++接收到的客户端数据压入lua栈中

static void push_proto_message_to_lua(const Message* message){
	lua_State* state = lua_wrapper::lua_state();
	if (!message) {
		// printf("PushProtobuf2LuaTable failed, message is NULL");
		return;
	}
	const Reflection* reflection = message->GetReflection();                  //操作字段

	// 顶层table
	lua_newtable(state);

	const Descriptor* descriptor = message->GetDescriptor();               //descriptor获取字段
	for (int32_t index = 0; index < descriptor->field_count(); ++index) {
		const FieldDescriptor* fd = descriptor->field(index);
		const std::string& name = fd->lowercase_name();

		// key
		lua_pushstring(state, name.c_str());

		bool bReapeted = fd->is_repeated();

		if (bReapeted) {
			// repeated这层的table
			lua_newtable(state);
			int size = reflection->FieldSize(*message, fd);
			for (int i = 0; i < size; ++i) {
				char str[32] = { 0 };
				switch (fd->cpp_type()) {
				case FieldDescriptor::CPPTYPE_DOUBLE:
					lua_pushnumber(state, reflection->GetRepeatedDouble(*message, fd, i));
					break;
				case FieldDescriptor::CPPTYPE_FLOAT:
					lua_pushnumber(state, (double)reflection->GetRepeatedFloat(*message, fd, i));
					break;
				case FieldDescriptor::CPPTYPE_INT64:
					sprintf(str, "%lld", (long long)reflection->GetRepeatedInt64(*message, fd, i));
					lua_pushstring(state, str);
					break;
				case FieldDescriptor::CPPTYPE_UINT64:

					sprintf(str, "%llu", (unsigned long long)reflection->GetRepeatedUInt64(*message, fd, i));
					lua_pushstring(state, str);
					break;
				case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
					lua_pushinteger(state, reflection->GetRepeatedEnum(*message, fd, i)->number());
					break;
				case FieldDescriptor::CPPTYPE_INT32:
					lua_pushinteger(state, reflection->GetRepeatedInt32(*message, fd, i));
					break;
				case FieldDescriptor::CPPTYPE_UINT32:
					lua_pushinteger(state, reflection->GetRepeatedUInt32(*message, fd, i));
					break;
				case FieldDescriptor::CPPTYPE_STRING:
				{
														std::string value = reflection->GetRepeatedString(*message, fd, i);
														lua_pushlstring(state, value.c_str(), value.size());
				}
					break;
				case FieldDescriptor::CPPTYPE_BOOL:
					lua_pushboolean(state, reflection->GetRepeatedBool(*message, fd, i));
					break;
				case FieldDescriptor::CPPTYPE_MESSAGE:
					push_proto_message_to_lua(&(reflection->GetRepeatedMessage(*message, fd, i)));
					break;
				default:
					break;
				}

				lua_rawseti(state, -2, i + 1); // lua's index start at 1
			}

		}
		else {
			char str[32] = { 0 };
			switch (fd->cpp_type()) {

			case FieldDescriptor::CPPTYPE_DOUBLE:
				lua_pushnumber(state, reflection->GetDouble(*message, fd));
				break;
			case FieldDescriptor::CPPTYPE_FLOAT:
				lua_pushnumber(state, (double)reflection->GetFloat(*message, fd));
				break;
			case FieldDescriptor::CPPTYPE_INT64:

				sprintf(str, "%lld", (long long)reflection->GetInt64(*message, fd));
				lua_pushstring(state, str);
				break;
			case FieldDescriptor::CPPTYPE_UINT64:

				sprintf(str, "%llu", (unsigned long long)reflection->GetUInt64(*message, fd));
				lua_pushstring(state, str);
				break;
			case FieldDescriptor::CPPTYPE_ENUM: // 与int32一样处理
				lua_pushinteger(state, (int)reflection->GetEnum(*message, fd)->number());
				break;
			case FieldDescriptor::CPPTYPE_INT32:
				lua_pushinteger(state, reflection->GetInt32(*message, fd));
				break;
			case FieldDescriptor::CPPTYPE_UINT32:
				lua_pushinteger(state, reflection->GetUInt32(*message, fd));
				break;
			case FieldDescriptor::CPPTYPE_STRING:
			{
													std::string value = reflection->GetString(*message, fd);
													lua_pushlstring(state, value.c_str(), value.size());
			}
				break;
			case FieldDescriptor::CPPTYPE_BOOL:
				lua_pushboolean(state, reflection->GetBool(*message, fd));
				break;
			case FieldDescriptor::CPPTYPE_MESSAGE:
				push_proto_message_to_lua(&(reflection->GetMessage(*message, fd)));
				break;
			default:
				break;
			}
		}

		lua_rawset(state, -3);
	}
}

你可能感兴趣的:(游戏服务器)