├── .gitignore ├── README.md ├── conf ├── rocket.xml └── rocket_client.xml ├── generator ├── rocket_generator.py └── template │ ├── business_exception.h.template │ ├── conf.xml.template │ ├── interface.cc.template │ ├── interface.h.template │ ├── interface_base.cc.template │ ├── interface_base.h.template │ ├── main.cc.template │ ├── makefile.template │ ├── run.sh │ ├── server.cc.template │ ├── server.h.template │ ├── shutdown.sh │ └── test_rocket_client.cc.template ├── imgs ├── main-sub-reactor.drawio.png └── multiple_definition.jpg ├── make.sh ├── makefile ├── rocket ├── common │ ├── config.cc │ ├── config.h │ ├── error_code.h │ ├── exception.h │ ├── log.cc │ ├── log.h │ ├── msg_id_util.cc │ ├── msg_id_util.h │ ├── mutex.h │ ├── run_time.cc │ ├── run_time.h │ ├── util.cc │ └── util.h └── net │ ├── coder │ ├── abstract_coder.h │ ├── abstract_protocol.h │ ├── string_coder.h │ ├── tinypb_coder.cc │ ├── tinypb_coder.h │ ├── tinypb_protocol.cc │ └── tinypb_protocol.h │ ├── eventloop.cc │ ├── eventloop.h │ ├── fd_event.cc │ ├── fd_event.h │ ├── fd_event_group.cc │ ├── fd_event_group.h │ ├── io_thread.cc │ ├── io_thread.h │ ├── io_thread_group.cc │ ├── io_thread_group.h │ ├── rpc │ ├── rpc_channel.cc │ ├── rpc_channel.h │ ├── rpc_closure.h │ ├── rpc_controller.cc │ ├── rpc_controller.h │ ├── rpc_dispatcher.cc │ ├── rpc_dispatcher.h │ ├── rpc_interface.cc │ └── rpc_interface.h │ ├── tcp │ ├── net_addr.cc │ ├── net_addr.h │ ├── tcp_acceptor.cc │ ├── tcp_acceptor.h │ ├── tcp_buffer.cc │ ├── tcp_buffer.h │ ├── tcp_client.cc │ ├── tcp_client.h │ ├── tcp_connection.cc │ ├── tcp_connection.h │ ├── tcp_server.cc │ └── tcp_server.h │ ├── timer.cc │ ├── timer.h │ ├── timer_event.cc │ ├── timer_event.h │ ├── wakeup_fd_event.cc │ └── wakeup_fd_event.h └── testcases ├── order.proto ├── test_client.cc ├── test_eventloop.cc ├── test_log.cc ├── test_rpc_client.cc ├── test_rpc_server.cc └── test_tcp.cc /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | lib/* 3 | obj/* 4 | log/* 5 | 6 | *.pb.h 7 | *.pb.cc 8 | -------------------------------------------------------------------------------- /conf/rocket.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEBUG 5 | test_rpc_server 6 | ../log/ 7 | 1000000000 8 | 500 9 | 10 | 11 | 12 | 12345 13 | 4 14 | 15 | 16 | 17 | 18 | 19 | 20 | default 21 | 0.0.0.0 22 | 12345 23 | 1000 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /conf/rocket_client.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEBUG 5 | test_rpc_client 6 | ../log/ 7 | 1000000000 8 | 500 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /generator/rocket_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.7 2 | 3 | import getopt 4 | import traceback 5 | import os 6 | import sys 7 | from string import Template 8 | from datetime import datetime 9 | 10 | project_name = "" 11 | proto_file = "" 12 | out_project_path = "./" 13 | bin_path = "" 14 | conf_path = "" 15 | test_client_path = "" 16 | test_client_tool_path = "" 17 | src_path = "" 18 | 19 | generator_path = sys.path[0] 20 | 21 | 22 | 23 | def to_camel(input_s): 24 | if input_s.find('_') == -1: 25 | return input_s 26 | re = '' 27 | for s in input_s.split('_'): 28 | re += s.capitalize() 29 | return re 30 | 31 | def to_underline(input_s): 32 | tmp = to_camel(input_s) 33 | re = '' 34 | for s in tmp: 35 | re += s if s.islower() else '_' + s.lower() 36 | re = re[1:] 37 | return re 38 | 39 | def parseInput(): 40 | opts,args = getopt.getopt(sys.argv[1:], "hi:o:", longopts=["help", "input=", "output="]) 41 | 42 | for opts,arg in opts: 43 | 44 | if opts=="-h" or opts=="--help": 45 | printHelp() 46 | sys.exit(0) 47 | if opts=="-i" or opts=="--input": 48 | global proto_file 49 | proto_file = arg 50 | elif opts=="-o" or opts=="--output_path": 51 | global out_project_path 52 | out_project_path = arg 53 | if out_project_path[-1] != '/': 54 | out_project_path = out_project_path + '/' 55 | else: 56 | raise Exception("invalid options: [" + opts + ": " + arg + "]") 57 | 58 | if not os.path.exists(proto_file): 59 | raise Exception("Generate error, not exist protobuf file: " + proto_file) 60 | 61 | if ".proto" not in proto_file: 62 | raise Exception("Generate error, input file is't standard protobuf file:[" + proto_file + "]") 63 | 64 | global project_name 65 | project_name = proto_file[0: -6] 66 | print("project name is " + project_name) 67 | 68 | 69 | def printHelp(): 70 | print('=' * 100) 71 | print('Welcome to use Rocket Generator, this is help document:\n') 72 | print('Run Environment: Python(version 3.6 or high version is better).') 73 | print('Run Platform: Linux Only(kernel version >= 3.9 is better).') 74 | print('Others: Only protobuf3 support, not support protobuf2.\n') 75 | print('Usage:') 76 | print('rocket_generator.py -[options][target]\n') 77 | print('Options:') 78 | print('-h, --help') 79 | print((' ') + 'Print help document.\n') 80 | 81 | print('-i xxx.proto, --input xxx.proto') 82 | print((' ') + 'Input the target proto file, must standard protobuf3 file, not support protobuf2.\n') 83 | 84 | print('-o dir, --output dir') 85 | print((' ') + 'Set the path that your want to generate project, please give a dir param.\n') 86 | 87 | print('') 88 | print('For example:') 89 | print('rocket_generator.py -i order_server.proto -o ./') 90 | 91 | print('') 92 | print('=' * 100) 93 | 94 | 95 | def generate_dir(): 96 | print('=' * 100) 97 | print('Begin to generate project dir') 98 | 99 | if out_project_path == "": 100 | proj_path = './' + project_name.strip() 101 | if out_project_path[-1] == '/': 102 | proj_path = out_project_path + project_name.strip() 103 | else: 104 | proj_path = out_project_path + './' + project_name.strip() 105 | 106 | global bin_path 107 | bin_path = proj_path + '/bin' 108 | 109 | global conf_path 110 | conf_path = proj_path + '/conf' 111 | 112 | global test_client_path 113 | test_client_path = proj_path + '/test_client' 114 | 115 | global test_client_tool_path 116 | test_client_tool_path = test_client_path + '/test_tool' 117 | 118 | log_path = proj_path + '/log' 119 | lib_path = proj_path + '/lib' 120 | obj_path = proj_path + '/obj' 121 | 122 | global src_path 123 | src_path = proj_path + '/' + project_name 124 | src_interface_path = src_path + '/interface' 125 | src_service_path = src_path + '/service' 126 | src_pb_path = src_path + '/pb' 127 | src_stubs_path = src_path + '/stubs' 128 | src_comm_path = src_path + '/comm' 129 | 130 | dir_list = [] 131 | dir_list.append(proj_path) 132 | dir_list.append(bin_path) 133 | dir_list.append(conf_path) 134 | dir_list.append(log_path) 135 | dir_list.append(lib_path) 136 | dir_list.append(obj_path) 137 | dir_list.append(test_client_path) 138 | dir_list.append(test_client_tool_path) 139 | dir_list.append(src_path) 140 | dir_list.append(src_interface_path) 141 | dir_list.append(src_service_path) 142 | dir_list.append(src_pb_path) 143 | dir_list.append(src_stubs_path) 144 | dir_list.append(src_comm_path) 145 | 146 | for each in dir_list: 147 | if not os.path.exists(each): 148 | os.mkdir(each) 149 | print("succ make dir in " + each) 150 | 151 | print('End generate project dir') 152 | print('=' * 100) 153 | 154 | 155 | 156 | def generate_pb(): 157 | print('=' * 100) 158 | print('Begin generate protobuf file') 159 | pb_path = src_path + '/pb/' 160 | cmd = 'cp -r ' + proto_file + ' ' + pb_path 161 | cmd += ' && cd ' + pb_path + ' && protoc --cpp_out=./ ' + proto_file 162 | print('excute cmd: ' + cmd) 163 | 164 | if os.system(cmd) is not 0: 165 | raise Exception("execute cmd failed [" + cmd + "]") 166 | 167 | print('End generate protobuf file') 168 | print('=' * 100) 169 | 170 | 171 | 172 | def generate_makefile(): 173 | print('=' * 100) 174 | print('Begin to generate makefile') 175 | out_file = src_path + '/makefile' 176 | if os.path.exists(out_file): 177 | print('makefile exist, skip generate') 178 | print('End generate makefile') 179 | print('=' * 100) 180 | return 181 | 182 | template_file = open(generator_path + '/template/makefile.template','r') 183 | tmpl = Template(template_file.read()) 184 | 185 | content = tmpl.safe_substitute( 186 | PROJECT_NAME = project_name, 187 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S')) 188 | 189 | file = open(out_file, 'w') 190 | file.write(content) 191 | file.close() 192 | print('succ write to ' + out_file) 193 | print('End generate makefile') 194 | print('=' * 100) 195 | 196 | 197 | def gen_run_script(): 198 | print('=' * 100) 199 | print('Begin to generate run script') 200 | script = open(generator_path + '/template/conf.xml.template','r') 201 | dir_src = generator_path + '/template/' 202 | cmd = 'cp -r ' + dir_src + '*.sh ' + bin_path + "/" 203 | print('excute cmd: ' + cmd) 204 | os.system(cmd) 205 | 206 | print('End generate run script') 207 | print('=' * 100) 208 | 209 | def gen_conf_file(): 210 | print('=' * 100) 211 | file_name = "rocket.xml" 212 | print('Begin to generate tinyrpc conf file') 213 | out_file = conf_path + '/' + file_name 214 | if os.path.exists(out_file): 215 | print('config exist, skip generate') 216 | print('End generate ' + file_name) 217 | print('=' * 100) 218 | return 219 | 220 | template_file = open(generator_path + '/template/conf.xml.template','r') 221 | # print(template_file.read()) 222 | tmpl = Template(template_file.read()) 223 | 224 | content = tmpl.safe_substitute( 225 | PROJECT_NAME = project_name, 226 | FILE_NAME = file_name, 227 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S')) 228 | 229 | file = open(out_file, 'w') 230 | file.write(content) 231 | file.close() 232 | print('succ write to ' + out_file) 233 | print('End generate rocket conf file') 234 | print('=' * 100) 235 | 236 | 237 | def generate_framework_code(): 238 | print('=' * 100) 239 | print('Begin to generate tinyrpc framework code') 240 | pb_head_file = src_path + '/pb/' + project_name + '.pb.h' 241 | file = open(pb_head_file, 'r') 242 | origin_text = file.read() 243 | 244 | # parse all rpc interface method from pb.h file 245 | begin = origin_text.find('virtual ~') 246 | i1 = origin_text[begin:].find('~') 247 | i2 = origin_text[begin:].find('(') 248 | service_name = origin_text[begin + i1 + 1 : begin + i2] 249 | print("service name is " + service_name) 250 | 251 | origin_text = origin_text[begin + i2: ] 252 | method_list = [] 253 | 254 | i1 = 0 255 | while 1: 256 | i1 = origin_text.find('virtual void') 257 | if (i1 == -1): 258 | break 259 | i2 = origin_text[i1:].find(');') 260 | method_list.append(origin_text[i1: i1 + i2 + 2]) 261 | # print(origin_text[i1: i1 + i2 + 2]) 262 | origin_text = origin_text[i1 + i2 + 3: ] 263 | 264 | 265 | print('=' * 100) 266 | print('Begin generate business_exception.h') 267 | exception_file = src_path + '/comm/' + 'business_exception.h' 268 | if not os.path.exists(exception_file): 269 | # generate business_exception.h 270 | exception_template = Template(open(generator_path + '/template/business_exception.h.template', 'r').read()) 271 | exception_content = exception_template.safe_substitute( 272 | PROJECT_NAME = project_name, 273 | FILE_NAME = 'business_exception.cc', 274 | HEADER_DEFINE = project_name.upper() + '_COMM_BUSINESSEXCEPTION_H', 275 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 276 | INCLUDE_INTERFACEBASE_HEADER_FILE = '#include "' + project_name + '/interface/interface.h"', 277 | ) 278 | out_exception_file = open(exception_file, 'w') 279 | out_exception_file.write(exception_content) 280 | out_exception_file.close() 281 | else: 282 | print("file: [" + exception_file + "] exist, skip") 283 | 284 | print('End generate business_exception.h') 285 | print('=' * 100) 286 | 287 | 288 | print('=' * 100) 289 | print('Begin generate server.h') 290 | # genneator server.h file 291 | class_name = to_camel(service_name) + 'Impl' 292 | head_file_temlate = Template(open(generator_path + '/template/server.h.template','r').read()) 293 | head_file_content = head_file_temlate.safe_substitute( 294 | HEADER_DEFINE = project_name.upper() + '_SERVICE_' + project_name.upper() + '_H', 295 | FILE_NAME = project_name + '.h', 296 | PROJECT_NAME = project_name, 297 | CLASS_NAME = class_name, 298 | SERVICE_NAME = service_name, 299 | PB_HEAD_FILE = project_name + '/pb/' + project_name + '.pb.h', 300 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 301 | INCLUDE_PB_HEADER = '#include "' + project_name + '/pb/' + project_name + '.pb.h"', 302 | ) 303 | 304 | i1 = head_file_content.find('${METHOD}') 305 | pre_content = head_file_content[0: i1] 306 | next_content = head_file_content[i1 + 9: ] 307 | for each in method_list: 308 | each = each.replace('PROTOBUF_NAMESPACE_ID', 'google::protobuf') 309 | pre_content += '// override from ' + service_name + '\n ' 310 | pre_content += each 311 | pre_content += '\n\n ' 312 | content = pre_content + next_content 313 | out_head_file = open(src_path + '/service/' + project_name + '.h', 'w') 314 | out_head_file.write(content) 315 | out_head_file.close() 316 | 317 | print('End generate server.h') 318 | print('=' * 100) 319 | 320 | print('=' * 100) 321 | print('Begin generate server.cc') 322 | # genneator server.cc file 323 | cc_file_temlate = Template(open(generator_path + '/template/server.cc.template','r').read()) 324 | cc_file_content = cc_file_temlate.safe_substitute( 325 | FILE_NAME = project_name + '.cc', 326 | PROJECT_NAME = project_name, 327 | INCLUDE_PB_HEADER = '#include "' + project_name + '/pb/' + project_name + '.pb.h"', 328 | INCLUDE_BUSINESS_EXCEPTION_HEADER = '#include "' + project_name + '/comm/business_exception.h"', 329 | INCLUDE_SERVER_HEADER = '#include "' + project_name + '/service/' + project_name + '.h"', 330 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 331 | ) 332 | 333 | 334 | method_i = cc_file_content.find('${METHOD}') 335 | pre_content = cc_file_content[0: method_i] 336 | next_content = cc_file_content[method_i + 9: ] 337 | interface_list = [] 338 | 339 | for each in method_list: 340 | tmp = each.replace('PROTOBUF_NAMESPACE_ID', 'google::protobuf') 341 | i1 = tmp.find('void') 342 | tmp = tmp[i1:] 343 | 344 | i2 = tmp.find('(') 345 | method_name = tmp[5: i2] 346 | # print(method_name) 347 | interface_class_name = to_camel(method_name) + 'Interface' 348 | interface_file_name = to_underline(method_name) 349 | l = tmp.split(',') 350 | y = l[1].find('request') 351 | request_type = l[1][0: y - 1].replace('*', '').replace('const ', '').replace('\n', '').replace(' ', '') 352 | # print(request_type) 353 | 354 | y = l[2].find('response') 355 | response_type = l[2][0: y - 1].replace('*', '').replace('\n', '').replace(' ', '') 356 | # print(response_type) 357 | 358 | 359 | interface_list.append({ 360 | 'interface_name': interface_file_name, 361 | 'method_name': method_name, 362 | 'interface_class_name': interface_class_name, 363 | 'request_type': request_type, 364 | 'response_type': response_type 365 | }) 366 | # print(interface_list) 367 | 368 | tmp = tmp[0: 5] + class_name + '::' + tmp[5:] 369 | tmp = tmp[0: -1] + '{\n\n ' + 'CALL_RPC_INTERFACE(' + interface_class_name + ');\n}' 370 | # print(tmp) 371 | pre_content += tmp 372 | pre_content += '\n\n' 373 | 374 | include_str = '' 375 | for each in interface_list: 376 | include_str += '#include "' + project_name + '/interface/' + each['interface_name'] + '.h"\n' 377 | pre_content = pre_content.replace('${INCLUDE_SERVICE}', include_str) 378 | 379 | out_cc_file = open(src_path + '/service/' + project_name + '.cc', 'w') 380 | out_cc_file.write(pre_content + next_content) 381 | out_cc_file.close() 382 | 383 | print('End generate server.cc') 384 | print('=' * 100) 385 | 386 | 387 | print('=' * 100) 388 | print('Begin generate main.cc') 389 | # genneator main.cc file 390 | main_file = src_path + '/main.cc' 391 | if not os.path.exists(main_file): 392 | main_file_temlate = Template(open(generator_path + '/template/main.cc.template','r').read()) 393 | main_file_content = main_file_temlate.safe_substitute( 394 | FILE_NAME = project_name + '.h', 395 | PROJECT_NAME = project_name, 396 | CLASS_NAME = project_name + "::" + class_name, 397 | INCLUDE_SERVER_HEADER = '#include "service/' + project_name + '.h"', 398 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 399 | ) 400 | main_file_handler = open(main_file, 'w') 401 | main_file_handler.write(main_file_content) 402 | main_file_handler.close() 403 | else: 404 | print("file: [" + main_file + "] exist, skip") 405 | 406 | print('End generate main.cc') 407 | print('=' * 100) 408 | 409 | 410 | # genneator interface.h file 411 | interfase_base_h_file = src_path + '/interface/interface.h' 412 | if not os.path.exists(interfase_base_h_file): 413 | interface_base_h_file_temlate = Template(open(generator_path + '/template/interface_base.h.template','r').read()) 414 | interfase_base_h_file_content = interface_base_h_file_temlate.safe_substitute( 415 | FILE_NAME = 'interface.h', 416 | PROJECT_NAME = project_name, 417 | HEADER_DEFINE = project_name.upper() + '_INTERFACE_H', 418 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 419 | ) 420 | interface_base_h_handler = open(interfase_base_h_file, 'w') 421 | interface_base_h_handler.write(interfase_base_h_file_content) 422 | interface_base_h_handler.close() 423 | else: 424 | print("file: [" + interfase_base_h_file + "] exist, skip") 425 | 426 | print('End generate interface.h') 427 | print('=' * 100) 428 | 429 | # genneator interface.cc file 430 | interfase_base_cc_file = src_path + '/interface/interface.cc' 431 | if not os.path.exists(interfase_base_cc_file): 432 | interface_base_cc_file_temlate = Template(open(generator_path + '/template/interface_base.cc.template','r').read()) 433 | interfase_base_cc_file_content = interface_base_cc_file_temlate.safe_substitute( 434 | FILE_NAME = 'interface.cc', 435 | PROJECT_NAME = project_name, 436 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 437 | INCLUDE_INTERFACEBASE_HEADER_FILE = '#include "' + project_name + '/interface/interface.h"', 438 | ) 439 | interface_base_cc_handler = open(interfase_base_cc_file, 'w') 440 | interface_base_cc_handler.write(interfase_base_cc_file_content) 441 | interface_base_cc_handler.close() 442 | else: 443 | print("file: [" + interfase_base_cc_file + "] exist, skip") 444 | 445 | print('End generate interface.cc') 446 | print('=' * 100) 447 | 448 | 449 | 450 | 451 | print('=' * 100) 452 | print('Begin generate each rpc method interface.cc & interface.h') 453 | # genneator each interface.cc and .h file 454 | interface_head_file_temlate = Template(open(generator_path + '/template/interface.h.template','r').read()) 455 | interface_cc_file_temlate = Template(open(generator_path + '/template/interface.cc.template','r').read()) 456 | interface_test_client_file_template = Template(open(generator_path + '/template/test_rocket_client.cc.template','r').read()) 457 | 458 | stub_name = service_name + "_Stub" 459 | for each in interface_list: 460 | 461 | # interface.h 462 | file = src_path + '/interface/' + each['interface_name'] + '.h' 463 | if not os.path.exists(file): 464 | header_content = interface_head_file_temlate.safe_substitute( 465 | PROJECT_NAME = project_name, 466 | INCLUDE_PB_HEADER = '#include "' + project_name + '/pb/' + project_name + '.pb.h"', 467 | HEADER_DEFINE = project_name.upper() + '_INTERFACE_' + each['interface_name'].upper() + '_H', 468 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 469 | CLASS_NAME = each['interface_class_name'], 470 | REQUEST_TYPE = each['request_type'], 471 | RESPONSE_TYPE = each['response_type'], 472 | INCLUDE_INTERFACEBASE_HEADER_FILE = '#include "' + project_name + '/interface/interface.h"', 473 | FILE_NAME = each['interface_name'] + '.h' 474 | ) 475 | out_interface_header_file = open(file, 'w') 476 | out_interface_header_file.write(header_content) 477 | out_interface_header_file.close() 478 | else: 479 | print("file: [" + file + "] exist, skip") 480 | 481 | # interface.cc 482 | file = src_path + '/interface/' + each['interface_name'] + '.cc' 483 | if not os.path.exists(file): 484 | cc_file_content = interface_cc_file_temlate.safe_substitute( 485 | PROJECT_NAME = project_name, 486 | INCLUDE_PB_HEADER = '#include "' + project_name + '/pb/' + project_name + '.pb.h"', 487 | INCLUDE_INTERFACE_HEADER_FILE = '#include "' + project_name + '/interface/' + each['interface_name'] + '.h"', 488 | INCLUDE_INTERFACEBASE_HEADER_FILE = '#include "' + project_name + '/interface/interface.h"', 489 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 490 | CLASS_NAME = each['interface_class_name'], 491 | REQUEST_TYPE = each['request_type'], 492 | RESPONSE_TYPE = each['response_type'], 493 | FILE_NAME = each['interface_name'] + '.cc' 494 | ) 495 | out_interface_cc_file = open(file, 'w') 496 | out_interface_cc_file.write(cc_file_content) 497 | out_interface_cc_file.close() 498 | else: 499 | print("file: [" + file + "] exist, skip") 500 | 501 | # test_interface_client.cc 502 | file = test_client_path + '/test_' + each['interface_name'] + '_client.cc' 503 | if not os.path.exists(file): 504 | cc_file_content = interface_test_client_file_template.safe_substitute( 505 | INCLUDE_PB_HEADER = '#include "' + project_name + '/pb/' + project_name + '.pb.h"', 506 | CREATE_TIME = datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 507 | REQUEST_TYPE = each['request_type'], 508 | RESPONSE_TYPE = each['response_type'], 509 | STUBCLASS = stub_name, 510 | METHOD_NAME = each['method_name'], 511 | FILE_NAME = 'test_' + each['interface_name'] + '_client.cc', 512 | ) 513 | out_interface_cc_file = open(file, 'w') 514 | out_interface_cc_file.write(cc_file_content) 515 | out_interface_cc_file.close() 516 | else: 517 | print("file: [" + file + "] exist, skip") 518 | 519 | 520 | 521 | print('End generate each interface.cc & interface.h & test_interface_client.h') 522 | print('=' * 100) 523 | 524 | print('End generate rocket framework code') 525 | print('=' * 100) 526 | 527 | def generate_project(): 528 | 529 | try: 530 | parseInput() 531 | 532 | print('=' * 150) 533 | print("Begin to generate rocket rpc server") 534 | 535 | generate_dir() 536 | 537 | generate_pb() 538 | 539 | generate_makefile() 540 | 541 | gen_run_script() 542 | 543 | gen_conf_file() 544 | 545 | generate_framework_code() 546 | 547 | print('Succ generate rocket project') 548 | print('=' * 150) 549 | 550 | except Exception as e: 551 | print("Failed to generate rocket rpc server, err: " + str(e)) 552 | print('=' * 150) 553 | 554 | 555 | if __name__ == '__main__': 556 | generate_project() 557 | -------------------------------------------------------------------------------- /generator/template/business_exception.h.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * File will not generate while exist 11 | * Allow editing 12 | ****************************************************/ 13 | 14 | 15 | #ifndef ${HEADER_DEFINE} 16 | #define ${HEADER_DEFINE} 17 | 18 | 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | namespace ${PROJECT_NAME} { 29 | 30 | class BusinessException : public rocket::RocketException { 31 | public: 32 | 33 | BusinessException(int code, const std::string& err_info, const std::string& file_name, int line): 34 | rocket::RocketException(code, err_info), m_file_name(file_name), m_line(line) { 35 | 36 | APPINFOLOG("[%s:%lld] throw BusinessException[code: %d, error info: %s]", file_name.c_str(), line, code, err_info.c_str()); 37 | } 38 | 39 | ~BusinessException() { 40 | 41 | } 42 | 43 | void handle() override { 44 | 45 | } 46 | 47 | const char* what() { 48 | return m_error_info.c_str(); 49 | } 50 | 51 | std::string file_name() { 52 | return m_file_name; 53 | } 54 | 55 | int line() { 56 | return m_line; 57 | } 58 | 59 | private: 60 | 61 | std::string m_file_name; 62 | 63 | int m_line {0}; 64 | 65 | }; 66 | 67 | } 68 | 69 | #endif -------------------------------------------------------------------------------- /generator/template/conf.xml.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | DEBUG 10 | 11 | 12 | ${PROJECT_NAME} 13 | 14 | 15 | ../log/ 16 | 17 | 18 | 1000000000 19 | 20 | 21 | 500 22 | 23 | 24 | 25 | 26 | 12345 27 | 28 | 29 | 4 30 | 31 | 32 | 33 | 34 | 35 | 36 | demo 37 | 38 | 127.0.0.1 39 | 54321 40 | 2000 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /generator/template/interface.cc.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * File will not generate while exist 11 | * Allow editing 12 | ****************************************************/ 13 | 14 | 15 | #include 16 | ${INCLUDE_INTERFACE_HEADER_FILE} 17 | ${INCLUDE_INTERFACEBASE_HEADER_FILE} 18 | ${INCLUDE_PB_HEADER} 19 | 20 | namespace ${PROJECT_NAME} { 21 | 22 | ${CLASS_NAME}::${CLASS_NAME}(const ${REQUEST_TYPE}* request, ${RESPONSE_TYPE}* response, 23 | rocket::RpcClosure* done, rocket::RpcController* controller) 24 | : Interface(dynamic_cast(request), dynamic_cast(response), done, controller), 25 | m_request(request), 26 | m_response(response) { 27 | APPINFOLOG("In|request:{%s}", request->ShortDebugString().c_str()); 28 | } 29 | 30 | ${CLASS_NAME}::~${CLASS_NAME}() { 31 | APPINFOLOG("Out|response:{%s}", m_response->ShortDebugString().c_str()); 32 | } 33 | 34 | void ${CLASS_NAME}::run() { 35 | 36 | // 37 | // Run your business logic at here 38 | // 39 | 40 | m_response->set_ret_code(0); 41 | m_response->set_res_info("OK"); 42 | 43 | } 44 | 45 | void ${CLASS_NAME}::setError(int code, const std::string& err_info) { 46 | m_response->set_ret_code(code); 47 | m_response->set_res_info(err_info); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /generator/template/interface.h.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * File will not generate while exist 11 | * Allow editing 12 | ****************************************************/ 13 | 14 | #ifndef ${HEADER_DEFINE} 15 | #define ${HEADER_DEFINE} 16 | 17 | #include 18 | ${INCLUDE_PB_HEADER} 19 | ${INCLUDE_INTERFACEBASE_HEADER_FILE} 20 | 21 | 22 | namespace ${PROJECT_NAME} { 23 | 24 | /* 25 | * Rpc Interface Class 26 | * Alloc one object every time RPC call begin, and destroy this object while RPC call end 27 | */ 28 | 29 | class ${CLASS_NAME} : public Interface { 30 | public: 31 | 32 | ${CLASS_NAME}(const ${REQUEST_TYPE}* request, ${RESPONSE_TYPE}* response, 33 | rocket::RpcClosure* done, rocket::RpcController* controller); 34 | 35 | ~${CLASS_NAME}(); 36 | 37 | public: 38 | // core business deal method 39 | virtual void run() override; 40 | 41 | // set error code and error into to response message 42 | virtual void setError(int code, const std::string& err_info) override; 43 | 44 | private: 45 | const ${REQUEST_TYPE}* m_request {NULL}; // request object fron client 46 | 47 | ${RESPONSE_TYPE}* m_response {NULL}; // response object that reply to client 48 | 49 | }; 50 | 51 | 52 | } 53 | 54 | 55 | #endif -------------------------------------------------------------------------------- /generator/template/interface_base.cc.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * File will not generate while exist 11 | * Allow editing 12 | ****************************************************/ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | ${INCLUDE_INTERFACEBASE_HEADER_FILE} 22 | 23 | namespace ${PROJECT_NAME} { 24 | 25 | 26 | Interface::Interface(const google::protobuf::Message* req, google::protobuf::Message* rsp, rocket::RpcClosure* done, rocket::RpcController* controller) 27 | : rocket::RpcInterface(req, rsp, done, controller) { 28 | 29 | } 30 | 31 | Interface::~Interface() { 32 | 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /generator/template/interface_base.h.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * File will not generate while exist 11 | * Allow editing 12 | ****************************************************/ 13 | 14 | #ifndef ${HEADER_DEFINE} 15 | #define ${HEADER_DEFINE} 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace ${PROJECT_NAME} { 23 | 24 | /* 25 | * Rpc Interface Base Class 26 | * All interface should extend this abstract class 27 | */ 28 | 29 | class Interface : public rocket::RpcInterface { 30 | public: 31 | 32 | Interface(const google::protobuf::Message* req, google::protobuf::Message* rsp, rocket::RpcClosure* done, rocket::RpcController* controller); 33 | 34 | virtual ~Interface() = 0; 35 | 36 | }; 37 | 38 | 39 | } 40 | 41 | 42 | #endif -------------------------------------------------------------------------------- /generator/template/main.cc.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * Do not edit !!! 11 | ****************************************************/ 12 | 13 | 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | ${INCLUDE_SERVER_HEADER} 24 | 25 | int main(int argc, char* argv[]) { 26 | 27 | if (argc != 2) { 28 | printf("Start ${PROJECT_NAME} error, argc not 2 \n"); 29 | printf("Start like this: \n"); 30 | printf("./${PROJECT_NAME} ../conf/rocket.xml \n"); 31 | return 0; 32 | } 33 | 34 | rocket::Config::SetGlobalConfig(argv[1]); 35 | 36 | rocket::Logger::InitGlobalLogger(); 37 | 38 | rocket::RpcDispatcher::GetRpcDispatcher()->registerService(std::make_shared<${CLASS_NAME}>()); 39 | 40 | rocket::IPNetAddr::s_ptr addr = std::make_shared("127.0.0.1", rocket::Config::GetGlobalConfig()->m_port); 41 | 42 | rocket::TcpServer tcp_server(addr); 43 | 44 | tcp_server.start(); 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /generator/template/makefile.template: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | ## **** *** **** * * ***** ***** 3 | ## * * * * * **** *** * 4 | ## * * *** **** * * ***** * 5 | ## MakeFile 6 | ## Generated by rocket framework rocket_generator.py 7 | ## Create Time: ${CREATE_TIME} 8 | ## How to use: 9 | ## make clean && make -j4 10 | ##################################################################### 11 | 12 | 13 | 14 | PATH_BIN = ../bin 15 | PATH_SERVICE = service 16 | PATH_INTERFACE = interface 17 | PATH_PB = pb 18 | PATH_COMM = comm 19 | PATH_STUBS = stubs 20 | PATH_OBJ = ../obj 21 | PATH_TEST_CLIENT = ../test_client 22 | PATH_TEST_CLIENT_TOOL = $(PATH_TEST_CLIENT)/test_tool 23 | 24 | 25 | # librocket 26 | # if you have installed librocket.a in another path, please modify it 27 | ROCKET_LIB = /usr/lib/librocket.a 28 | ROCKET_PATH = /usr/include/rocket 29 | 30 | # protobuf 31 | # if you have installed libprotobuf.a in another path, please modify it 32 | PROTOBUF_LIB = /usr/lib/libprotobuf.a 33 | 34 | # tinyxml 35 | # if you have installed libtinyxml.a in another path, please modify it 36 | TINYXML_LIB = /usr/lib/libtinyxml.a 37 | 38 | # out bin file 39 | TARGET = $(PATH_BIN)/${PROJECT_NAME} 40 | 41 | CXX := g++ 42 | 43 | CXX_FLAGS := -g -O3 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable 44 | 45 | CXX_FLAGS += -I../ -I ./$(PATH_PB) -I ./$(PATH_SERVICE) -I ./$(PATH_INTERFACE) -I ./$(PATH_COMM) -I$(PATH_STUBS) -I$(ROCKET_PATH) 46 | 47 | LIBS += $(ROCKET_LIB) 48 | 49 | LIBS += $(PROTOBUF_LIB) $(TINYXML_LIB) 50 | 51 | PB_OBJS := $(patsubst $(PATH_PB)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_PB)/*.cc)) 52 | STUB_OBJS := $(patsubst $(PATH_STUBS)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_STUBS)/*.cc)) 53 | SERVICE_OBJS := $(patsubst $(PATH_SERVICE)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_SERVICE)/*.cc)) 54 | INTERFACE_OBJS := $(patsubst $(PATH_INTERFACE)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_INTERFACE)/*.cc)) 55 | COMM_OBJS := $(patsubst $(PATH_COMM)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_COMM)/*.cc)) 56 | TEST_BINS := $(patsubst $(PATH_TEST_CLIENT)/%.cc, $(PATH_TEST_CLIENT_TOOL)/%, $(wildcard $(PATH_TEST_CLIENT)/*.cc)) 57 | 58 | OUT : $(TARGET) $(TEST_BINS) 59 | 60 | $(TARGET) : $(PB_OBJS) $(STUB_OBJS) $(SERVICE_OBJS) $(INTERFACE_OBJS) 61 | $(CXX) $(CXX_FLAGS) main.cc -o $@ $^ $(LIBS) -ldl -lpthread 62 | 63 | $(PATH_TEST_CLIENT_TOOL)/%: $(PATH_TEST_CLIENT)/%.cc $(PB_OBJS) 64 | $(CXX) $(CXX_FLAGS) $< -o $@ $(LIBS) $(PB_OBJS) -ldl -lpthread 65 | 66 | $(PATH_OBJ)/%.o : $(PATH_PB)/%.cc 67 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 68 | 69 | $(PATH_OBJ)/%.o : $(PATH_SERVICE)/%.cc 70 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 71 | 72 | $(PATH_OBJ)/%.o : $(PATH_INTERFACE)/%.cc 73 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 74 | 75 | $(PATH_OBJ)/%.o : $(PATH_COMM)/%.cc 76 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 77 | 78 | $(PATH_OBJ)/%.o : $(PATH_STUBS)/%.cc 79 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 80 | 81 | 82 | 83 | PRINT-% : ; @echo $* = $($*) 84 | 85 | clean : 86 | rm -f $(PB_OBJS) $(STUB_OBJS) $(SERVICE_OBJS) $(INTERFACE_OBJS) $(COMM_OBJS) $(TARGET) $(TEST_BINS) -------------------------------------------------------------------------------- /generator/template/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | FILE_NAME=$1 3 | PROJECT_NAME=$(basename ${FILE_NAME}) 4 | CURRENT_PATH=$(cd $(dirname $0); pwd) 5 | PROJECT_ROOT_PATH=$(cd $(dirname $0); cd ..; pwd) 6 | PROJECT_BIN_FILE="${CURRENT_PATH}"/"${PROJECT_NAME}" 7 | PROJECT_CONF_FILE="../conf/rocket.xml" 8 | 9 | 10 | echo "Run rocket rpc project, name: ${PROJECT_NAME}, path: ${PROJECT_BIN_FILE}" 11 | 12 | if [ -z "$1" ] 13 | then 14 | echo "Please input execuable binary file!" 15 | fi 16 | 17 | # check bin file exist 18 | if [ ! -e ${PROJECT_BIN_FILE} ] 19 | then 20 | echo "Run rocket rpc server eror, file: ${PROJECT_BIN_FILE} not exist, please check file" 21 | exit -1 22 | fi 23 | 24 | # check config xml file exist 25 | if [ ! -e ${PROJECT_CONF_FILE} ] 26 | then 27 | echo "Run rocket rpc error, file: ${PROJECT_CONF_FILE} not exist, please check config file" 28 | exit -1 29 | fi 30 | 31 | # check bin file execute privilege 32 | if [ ! -x ${PROJECT_BIN_FILE} ] 33 | then 34 | echo "chmod +x : ${PROJECT_BIN_FILE}" 35 | chmod +x ${PROJECT_BIN_FILE} 36 | fi 37 | 38 | sh shutdown.sh ${PROJECT_NAME} 39 | nohup ./${PROJECT_NAME} ${PROJECT_CONF_FILE} & > ${PROJECT_ROOT_PATH}/log/${PROJECT_NAME}.nohup_log 40 | echo "Start rocket rpc server ${PROJECT_CONF_FILE} succ" 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /generator/template/server.cc.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * Do not edit !!! 11 | ****************************************************/ 12 | 13 | 14 | #include 15 | #include 16 | #include 17 | ${INCLUDE_PB_HEADER} 18 | ${INCLUDE_SERVER_HEADER} 19 | ${INCLUDE_BUSINESS_EXCEPTION_HEADER} 20 | ${INCLUDE_SERVICE} 21 | 22 | #define CALL_RPC_INTERFACE(Type) \ 23 | { \ 24 | rocket::RpcClosure* clo = dynamic_cast(done); \ 25 | rocket::RpcController* con = dynamic_cast(controller); \ 26 | std::shared_ptr impl = std::make_shared(request, response, clo, con); \ 27 | rocket::RunTime::GetRunTime()->m_rpc_interface = std::dynamic_pointer_cast(impl).get(); \ 28 | response->set_ret_code(0); \ 29 | response->set_res_info("OK"); \ 30 | try { \ 31 | impl->run(); \ 32 | } catch (BusinessException& e) { \ 33 | APPDEBUGLOG("business exception"); \ 34 | response->set_ret_code(e.errorCode()); \ 35 | response->set_res_info(e.errorInfo()); \ 36 | } catch (rocket::RocketException& e) { \ 37 | APPDEBUGLOG("RocketException"); \ 38 | response->set_ret_code(-1); \ 39 | response->set_res_info("Unknown RocketException"); \ 40 | } catch (std::exception& e) { \ 41 | APPDEBUGLOG("std::exception"); \ 42 | response->set_ret_code(-1); \ 43 | response->set_res_info("Unknown std::exception"); \ 44 | } catch (...) { \ 45 | APPDEBUGLOG("... exception"); \ 46 | response->set_ret_code(-1); \ 47 | response->set_res_info("Unknown exception"); \ 48 | } \ 49 | } \ 50 | 51 | namespace ${PROJECT_NAME} { 52 | 53 | ${METHOD} 54 | 55 | } -------------------------------------------------------------------------------- /generator/template/server.h.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | * Do not edit !!! 11 | ****************************************************/ 12 | 13 | 14 | #ifndef ${HEADER_DEFINE} 15 | #define ${HEADER_DEFINE} 16 | 17 | #include 18 | ${INCLUDE_PB_HEADER} 19 | 20 | namespace ${PROJECT_NAME} { 21 | 22 | class ${CLASS_NAME} : public ${SERVICE_NAME} { 23 | 24 | public: 25 | 26 | ${CLASS_NAME}() = default; 27 | 28 | ~${CLASS_NAME}() = default; 29 | 30 | ${METHOD} 31 | 32 | }; 33 | 34 | } 35 | 36 | 37 | #endif -------------------------------------------------------------------------------- /generator/template/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] 4 | then 5 | echo "Please input rocket server name!" 6 | exit -1 7 | fi 8 | 9 | FILE_NAME=$1 10 | PROJECT_NAME=$(basename ${FILE_NAME}) 11 | CURRENT_PATH=$(cd $(dirname $0); pwd) 12 | PROJECT_BIN_FILE="${CURRENT_PATH}"/"${PROJECT_NAME}" 13 | PROJECT_CONF_FILE="../conf/rocket.xml" 14 | 15 | echo "Shutdown rocket rpc project, name: ${PROJECT_NAME}, path: ${PROJECT_BIN_FILE}" 16 | 17 | # check bin file exist 18 | if [ ! -e ${PROJECT_BIN_FILE} ] 19 | then 20 | echo "Shtdown rpcket rpc eror, file: ${PROJECT_BIN_FILE} not exist, please check file" 21 | exit -1 22 | fi 23 | 24 | 25 | proc_list=`ps -elf | grep "${PROJECT_NAME}" | grep -v 'grep' | grep -v 'shutdown.sh' | awk '{print $4}'` 26 | echo ${proc_list[0]} 27 | 28 | for i in ${proc_list[@]} 29 | do 30 | bin_path=`ls -l /proc/${i}/exe | awk '{print $11}'` 31 | echo ${bin_path} 32 | if [ "$bin_path" = "$PROJECT_BIN_FILE" ] 33 | then 34 | echo "kill this proc: ${i}" 35 | kill -9 ${i} 36 | fi 37 | done 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /generator/template/test_rocket_client.cc.template: -------------------------------------------------------------------------------- 1 | /**************************************************** 2 | * 3 | * **** *** **** * * ***** ***** 4 | * * * * * * **** *** * 5 | * * * *** **** * * ***** * 6 | * 7 | * ${FILE_NAME} 8 | * ${CREATE_TIME} 9 | * Generated by rocket framework rocket_generator.py 10 | ****************************************************/ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | ${INCLUDE_PB_HEADER} 19 | 20 | 21 | void test_client(const std::string& addr) { 22 | 23 | NEWMESSAGE(${REQUEST_TYPE}, request); 24 | NEWMESSAGE(${RESPONSE_TYPE}, response); 25 | 26 | // request->set_xxx(100); 27 | 28 | NEWRPCCONTROLLER(controller); 29 | controller->SetTimeout(2000); 30 | 31 | std::shared_ptr closure = std::make_shared(nullptr, [request, response, controller]() mutable { 32 | if (controller->GetErrorCode() == 0) { 33 | INFOLOG("call rpc success, request[%s], response[%s]", request->ShortDebugString().c_str(), response->ShortDebugString().c_str()); 34 | 35 | } else { 36 | ERRORLOG("call rpc failed, request[%s], error code[%d], error info[%s]", 37 | request->ShortDebugString().c_str(), 38 | controller->GetErrorCode(), 39 | controller->GetErrorInfo().c_str()); 40 | } 41 | 42 | exit(0); 43 | }); 44 | 45 | CALLRPRC(addr, ${STUBCLASS}, ${METHOD_NAME}, controller, request, response, closure); 46 | 47 | } 48 | 49 | int main(int argc, char* argv[]) { 50 | 51 | if (argc != 3) { 52 | printf ("param error, Usage: ./client ip port\n"); 53 | printf ("For example: ./client 127.0.0.1 12345\n"); 54 | return -1; 55 | } 56 | 57 | rocket::Config::SetGlobalConfig(NULL); 58 | 59 | rocket::Logger::InitGlobalLogger(0); 60 | 61 | std::string addr = std::string(argv[1]) + ":" + std::string(argv[2]); 62 | 63 | test_client(addr); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /imgs/main-sub-reactor.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/rocket/0228310396a90c57b32a95fdae9a40a6dc2e5fce/imgs/main-sub-reactor.drawio.png -------------------------------------------------------------------------------- /imgs/multiple_definition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/rocket/0228310396a90c57b32a95fdae9a40a6dc2e5fce/imgs/multiple_definition.jpg -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/bash 2 | 3 | function create_dir() { 4 | if [ ! -d $1 ]; then 5 | mkdir $1 6 | fi 7 | } 8 | 9 | create_dir 'bin' 10 | create_dir 'log' 11 | create_dir 'obj' 12 | create_dir 'lib' 13 | 14 | make clean && make -j4 15 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ################################## 2 | # makefile 3 | # ikerli 4 | # 2022-05-23 5 | ################################## 6 | 7 | PATH_BIN = bin 8 | PATH_LIB = lib 9 | PATH_OBJ = obj 10 | 11 | PATH_ROCKET = rocket 12 | PATH_COMM = $(PATH_ROCKET)/common 13 | PATH_NET = $(PATH_ROCKET)/net 14 | PATH_TCP = $(PATH_ROCKET)/net/tcp 15 | PATH_CODER = $(PATH_ROCKET)/net/coder 16 | PATH_RPC = $(PATH_ROCKET)/net/rpc 17 | 18 | PATH_TESTCASES = testcases 19 | 20 | # will install lib to /usr/lib/librocket.a 21 | PATH_INSTALL_LIB_ROOT = /usr/lib 22 | 23 | # will install all header file to /usr/include/rocket 24 | PATH_INSTALL_INC_ROOT = /usr/include 25 | 26 | PATH_INSTALL_INC_COMM = $(PATH_INSTALL_INC_ROOT)/$(PATH_COMM) 27 | PATH_INSTALL_INC_NET = $(PATH_INSTALL_INC_ROOT)/$(PATH_NET) 28 | PATH_INSTALL_INC_TCP = $(PATH_INSTALL_INC_ROOT)/$(PATH_TCP) 29 | PATH_INSTALL_INC_CODER = $(PATH_INSTALL_INC_ROOT)/$(PATH_CODER) 30 | PATH_INSTALL_INC_RPC = $(PATH_INSTALL_INC_ROOT)/$(PATH_RPC) 31 | 32 | 33 | # PATH_PROTOBUF = /usr/include/google 34 | # PATH_TINYXML = /usr/include/tinyxml 35 | 36 | CXX := g++ 37 | 38 | CXXFLAGS += -g -O0 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable 39 | 40 | CXXFLAGS += -I./ -I$(PATH_ROCKET) -I$(PATH_COMM) -I$(PATH_NET) -I$(PATH_TCP) -I$(PATH_CODER) -I$(PATH_RPC) 41 | 42 | LIBS += /usr/lib/libprotobuf.a /usr/lib/libtinyxml.a 43 | 44 | 45 | COMM_OBJ := $(patsubst $(PATH_COMM)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_COMM)/*.cc)) 46 | NET_OBJ := $(patsubst $(PATH_NET)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_NET)/*.cc)) 47 | TCP_OBJ := $(patsubst $(PATH_TCP)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_TCP)/*.cc)) 48 | CODER_OBJ := $(patsubst $(PATH_CODER)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_CODER)/*.cc)) 49 | RPC_OBJ := $(patsubst $(PATH_RPC)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_RPC)/*.cc)) 50 | 51 | ALL_TESTS : $(PATH_BIN)/test_log $(PATH_BIN)/test_eventloop $(PATH_BIN)/test_tcp $(PATH_BIN)/test_client $(PATH_BIN)/test_rpc_client $(PATH_BIN)/test_rpc_server 52 | # ALL_TESTS : $(PATH_BIN)/test_log 53 | 54 | TEST_CASE_OUT := $(PATH_BIN)/test_log $(PATH_BIN)/test_eventloop $(PATH_BIN)/test_tcp $(PATH_BIN)/test_client $(PATH_BIN)/test_rpc_client $(PATH_BIN)/test_rpc_server 55 | 56 | LIB_OUT := $(PATH_LIB)/librocket.a 57 | 58 | $(PATH_BIN)/test_log: $(LIB_OUT) 59 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_log.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 60 | 61 | $(PATH_BIN)/test_eventloop: $(LIB_OUT) 62 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_eventloop.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 63 | 64 | $(PATH_BIN)/test_tcp: $(LIB_OUT) 65 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_tcp.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 66 | 67 | $(PATH_BIN)/test_client: $(LIB_OUT) 68 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_client.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 69 | 70 | $(PATH_BIN)/test_rpc_client: $(LIB_OUT) 71 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_rpc_client.cc $(PATH_TESTCASES)/order.pb.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 72 | 73 | $(PATH_BIN)/test_rpc_server: $(LIB_OUT) 74 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_rpc_server.cc $(PATH_TESTCASES)/order.pb.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread 75 | 76 | 77 | $(LIB_OUT): $(COMM_OBJ) $(NET_OBJ) $(TCP_OBJ) $(CODER_OBJ) $(RPC_OBJ) 78 | cd $(PATH_OBJ) && ar rcv librocket.a *.o && cp librocket.a ../lib/ 79 | 80 | $(PATH_OBJ)/%.o : $(PATH_COMM)/%.cc 81 | $(CXX) $(CXXFLAGS) -c $< -o $@ 82 | 83 | 84 | $(PATH_OBJ)/%.o : $(PATH_NET)/%.cc 85 | $(CXX) $(CXXFLAGS) -c $< -o $@ 86 | 87 | $(PATH_OBJ)/%.o : $(PATH_TCP)/%.cc 88 | $(CXX) $(CXXFLAGS) -c $< -o $@ 89 | 90 | $(PATH_OBJ)/%.o : $(PATH_CODER)/%.cc 91 | $(CXX) $(CXXFLAGS) -c $< -o $@ 92 | 93 | $(PATH_OBJ)/%.o : $(PATH_RPC)/%.cc 94 | $(CXX) $(CXXFLAGS) -c $< -o $@ 95 | 96 | # print something test 97 | # like this: make PRINT-PATH_BIN, and then will print variable PATH_BIN 98 | PRINT-% : ; @echo $* = $($*) 99 | 100 | 101 | # to clean 102 | clean : 103 | rm -f $(COMM_OBJ) $(NET_OBJ) $(TESTCASES) $(TEST_CASE_OUT) $(PATH_LIB)/librocket.a $(PATH_OBJ)/librocket.a $(PATH_OBJ)/*.o 104 | 105 | # install 106 | install: 107 | mkdir -p $(PATH_INSTALL_INC_COMM) $(PATH_INSTALL_INC_NET) $(PATH_INSTALL_INC_TCP) $(PATH_INSTALL_INC_CODER) $(PATH_INSTALL_INC_RPC)\ 108 | && cp $(PATH_COMM)/*.h $(PATH_INSTALL_INC_COMM) \ 109 | && cp $(PATH_NET)/*.h $(PATH_INSTALL_INC_NET) \ 110 | && cp $(PATH_TCP)/*.h $(PATH_INSTALL_INC_TCP) \ 111 | && cp $(PATH_CODER)/*.h $(PATH_INSTALL_INC_CODER) \ 112 | && cp $(PATH_RPC)/*.h $(PATH_INSTALL_INC_RPC) \ 113 | && cp $(LIB_OUT) $(PATH_INSTALL_LIB_ROOT)/ 114 | 115 | 116 | # uninstall 117 | uninstall: 118 | rm -rf $(PATH_INSTALL_INC_ROOT)/rocket && rm -f $(PATH_INSTALL_LIB_ROOT)/librocket.a -------------------------------------------------------------------------------- /rocket/common/config.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rocket/common/config.h" 3 | 4 | 5 | 6 | #define READ_XML_NODE(name, parent) \ 7 | TiXmlElement* name##_node = parent->FirstChildElement(#name); \ 8 | if (!name##_node) { \ 9 | printf("Start rocket server error, failed to read node [%s]\n", #name); \ 10 | exit(0); \ 11 | } \ 12 | 13 | 14 | 15 | #define READ_STR_FROM_XML_NODE(name, parent) \ 16 | TiXmlElement* name##_node = parent->FirstChildElement(#name); \ 17 | if (!name##_node|| !name##_node->GetText()) { \ 18 | printf("Start rocket server error, failed to read config file %s\n", #name); \ 19 | exit(0); \ 20 | } \ 21 | std::string name##_str = std::string(name##_node->GetText()); \ 22 | 23 | 24 | 25 | namespace rocket { 26 | 27 | 28 | static Config* g_config = NULL; 29 | 30 | 31 | Config* Config::GetGlobalConfig() { 32 | return g_config; 33 | } 34 | 35 | void Config::SetGlobalConfig(const char* xmlfile) { 36 | if (g_config == NULL) { 37 | if (xmlfile != NULL) { 38 | g_config = new Config(xmlfile); 39 | } else { 40 | g_config = new Config(); 41 | } 42 | 43 | } 44 | } 45 | 46 | Config::~Config() { 47 | if (m_xml_document) { 48 | delete m_xml_document; 49 | m_xml_document = NULL; 50 | } 51 | } 52 | 53 | Config::Config() { 54 | m_log_level = "DEBUG"; 55 | 56 | } 57 | 58 | Config::Config(const char* xmlfile) { 59 | m_xml_document = new TiXmlDocument(); 60 | 61 | bool rt = m_xml_document->LoadFile(xmlfile); 62 | if (!rt) { 63 | printf("Start rocket server error, failed to read config file %s, error info[%s] \n", xmlfile, m_xml_document->ErrorDesc()); 64 | exit(0); 65 | } 66 | 67 | READ_XML_NODE(root, m_xml_document); 68 | READ_XML_NODE(log, root_node); 69 | READ_XML_NODE(server, root_node); 70 | 71 | READ_STR_FROM_XML_NODE(log_level, log_node); 72 | READ_STR_FROM_XML_NODE(log_file_name, log_node); 73 | READ_STR_FROM_XML_NODE(log_file_path, log_node); 74 | READ_STR_FROM_XML_NODE(log_max_file_size, log_node); 75 | READ_STR_FROM_XML_NODE(log_sync_interval, log_node); 76 | 77 | m_log_level = log_level_str; 78 | m_log_file_name = log_file_name_str; 79 | m_log_file_path = log_file_path_str; 80 | m_log_max_file_size = std::atoi(log_max_file_size_str.c_str()) ; 81 | m_log_sync_inteval = std::atoi(log_sync_interval_str.c_str()); 82 | 83 | printf("LOG -- CONFIG LEVEL[%s], FILE_NAME[%s],FILE_PATH[%s] MAX_FILE_SIZE[%d B], SYNC_INTEVAL[%d ms]\n", 84 | m_log_level.c_str(), m_log_file_name.c_str(), m_log_file_path.c_str(), m_log_max_file_size, m_log_sync_inteval); 85 | 86 | READ_STR_FROM_XML_NODE(port, server_node); 87 | READ_STR_FROM_XML_NODE(io_threads, server_node); 88 | 89 | m_port = std::atoi(port_str.c_str()); 90 | m_io_threads = std::atoi(io_threads_str.c_str()); 91 | 92 | 93 | TiXmlElement* stubs_node = root_node->FirstChildElement("stubs"); 94 | 95 | if (stubs_node) { 96 | for (TiXmlElement* node = stubs_node->FirstChildElement("rpc_server"); node; node = node->NextSiblingElement("rpc_server")) { 97 | RpcStub stub; 98 | stub.name = std::string(node->FirstChildElement("name")->GetText()); 99 | stub.timeout = std::atoi(node->FirstChildElement("timeout")->GetText()); 100 | 101 | std::string ip = std::string(node->FirstChildElement("ip")->GetText()); 102 | uint16_t port = std::atoi(node->FirstChildElement("port")->GetText()); 103 | stub.addr = std::make_shared(ip, port); 104 | 105 | m_rpc_stubs.insert(std::make_pair(stub.name, stub)); 106 | } 107 | } 108 | 109 | 110 | 111 | printf("Server -- PORT[%d], IO Threads[%d]\n", m_port, m_io_threads); 112 | 113 | } 114 | 115 | 116 | } -------------------------------------------------------------------------------- /rocket/common/config.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_CONFIG_H 2 | #define ROCKET_COMMON_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include "rocket/net/tcp/net_addr.h" 7 | 8 | 9 | namespace rocket { 10 | 11 | struct RpcStub { 12 | std::string name; 13 | NetAddr::s_ptr addr; 14 | int timeout {2000}; 15 | }; 16 | 17 | class Config { 18 | public: 19 | 20 | Config(const char* xmlfile); 21 | 22 | Config(); 23 | 24 | ~Config(); 25 | 26 | public: 27 | static Config* GetGlobalConfig(); 28 | static void SetGlobalConfig(const char* xmlfile); 29 | 30 | public: 31 | std::string m_log_level; 32 | std::string m_log_file_name; 33 | std::string m_log_file_path; 34 | int m_log_max_file_size {0}; 35 | int m_log_sync_inteval {0}; // 日志同步间隔,ms 36 | 37 | int m_port {0}; 38 | int m_io_threads {0}; 39 | 40 | TiXmlDocument* m_xml_document{NULL}; 41 | 42 | std::map m_rpc_stubs; 43 | 44 | }; 45 | 46 | 47 | } 48 | 49 | 50 | #endif -------------------------------------------------------------------------------- /rocket/common/error_code.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_ERROR_CODER_H 2 | #define ROCKET_COMMON_ERROR_CODER_H 3 | 4 | #ifndef SYS_ERROR_PREFIX 5 | #define SYS_ERROR_PREFIX(xx) 1000##xx 6 | #endif 7 | 8 | 9 | const int ERROR_PEER_CLOSED = SYS_ERROR_PREFIX(0000); // 连接时对端关闭 10 | const int ERROR_FAILED_CONNECT = SYS_ERROR_PREFIX(0001); // 连接失败 11 | const int ERROR_FAILED_GET_REPLY = SYS_ERROR_PREFIX(0002); // 获取回包失败 12 | const int ERROR_FAILED_DESERIALIZE = SYS_ERROR_PREFIX(0003); // 反序列化失败 13 | const int ERROR_FAILED_SERIALIZE = SYS_ERROR_PREFIX(0004); // 序列化 failed 14 | 15 | const int ERROR_FAILED_ENCODE = SYS_ERROR_PREFIX(0005); // encode failed 16 | const int ERROR_FAILED_DECODE = SYS_ERROR_PREFIX(0006); // decode failed 17 | 18 | const int ERROR_RPC_CALL_TIMEOUT = SYS_ERROR_PREFIX(0007); // rpc 调用超时 19 | 20 | const int ERROR_SERVICE_NOT_FOUND = SYS_ERROR_PREFIX(0008); // service 不存在 21 | const int ERROR_METHOD_NOT_FOUND = SYS_ERROR_PREFIX(0009); // method 不存在 method 22 | const int ERROR_PARSE_SERVICE_NAME = SYS_ERROR_PREFIX(0010); // service name 解析失败 23 | const int ERROR_RPC_CHANNEL_INIT = SYS_ERROR_PREFIX(0011); // rpc channel 初始化失败 24 | const int ERROR_RPC_PEER_ADDR = SYS_ERROR_PREFIX(0012); // rpc 调用时候对端地址异常 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /rocket/common/exception.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_EXCEPTION_H 2 | #define ROCKET_COMMON_EXCEPTION_H 3 | 4 | #include 5 | #include 6 | 7 | namespace rocket { 8 | 9 | class RocketException : public std::exception { 10 | public: 11 | 12 | RocketException(int error_code, const std::string& error_info) : m_error_code(error_code), m_error_info(error_info) {} 13 | 14 | // 异常处理 15 | // 当捕获到 RocketException 及其子类对象的异常时,会执行该函数 16 | virtual void handle() = 0; 17 | 18 | virtual ~RocketException() {}; 19 | 20 | int errorCode() { 21 | return m_error_code; 22 | } 23 | 24 | std::string errorInfo() { 25 | return m_error_info; 26 | } 27 | 28 | protected: 29 | int m_error_code {0}; 30 | 31 | std::string m_error_info; 32 | 33 | }; 34 | 35 | 36 | } 37 | 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /rocket/common/log.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "rocket/common/log.h" 7 | #include "rocket/common/util.h" 8 | #include "rocket/common/config.h" 9 | #include "rocket/net/eventloop.h" 10 | #include "rocket/common/run_time.h" 11 | 12 | 13 | 14 | 15 | namespace rocket { 16 | 17 | static Logger* g_logger = NULL; 18 | 19 | void CoredumpHandler(int signal_no) { 20 | ERRORLOG("progress received invalid signal, will exit"); 21 | g_logger->flush(); 22 | pthread_join(g_logger->getAsyncLopger()->m_thread, NULL); 23 | pthread_join(g_logger->getAsyncAppLopger()->m_thread, NULL); 24 | 25 | signal(signal_no, SIG_DFL); 26 | raise(signal_no); 27 | } 28 | 29 | Logger* Logger::GetGlobalLogger() { 30 | return g_logger; 31 | } 32 | 33 | 34 | Logger::Logger(LogLevel level, int type /*=1*/) : m_set_level(level), m_type(type) { 35 | 36 | if (m_type == 0) { 37 | return; 38 | } 39 | m_asnyc_logger = std::make_shared( 40 | Config::GetGlobalConfig()->m_log_file_name + "_rpc", 41 | Config::GetGlobalConfig()->m_log_file_path, 42 | Config::GetGlobalConfig()->m_log_max_file_size); 43 | 44 | m_asnyc_app_logger = std::make_shared( 45 | Config::GetGlobalConfig()->m_log_file_name + "_app", 46 | Config::GetGlobalConfig()->m_log_file_path, 47 | Config::GetGlobalConfig()->m_log_max_file_size); 48 | } 49 | 50 | void Logger::flush() { 51 | syncLoop(); 52 | m_asnyc_logger->stop(); 53 | m_asnyc_logger->flush(); 54 | 55 | m_asnyc_app_logger->stop(); 56 | m_asnyc_app_logger->flush(); 57 | } 58 | 59 | 60 | void Logger::init() { 61 | if (m_type == 0) { 62 | return; 63 | } 64 | m_timer_event = std::make_shared(Config::GetGlobalConfig()->m_log_sync_inteval, true, std::bind(&Logger::syncLoop, this)); 65 | EventLoop::GetCurrentEventLoop()->addTimerEvent(m_timer_event); 66 | signal(SIGSEGV, CoredumpHandler); 67 | signal(SIGABRT, CoredumpHandler); 68 | signal(SIGTERM, CoredumpHandler); 69 | signal(SIGKILL, CoredumpHandler); 70 | signal(SIGINT, CoredumpHandler); 71 | signal(SIGSTKFLT, CoredumpHandler); 72 | 73 | } 74 | 75 | 76 | void Logger::syncLoop() { 77 | // 同步 m_buffer 到 async_logger 的buffer队尾 78 | // printf("sync to async logger\n"); 79 | std::vector tmp_vec; 80 | ScopeMutex lock(m_mutex); 81 | tmp_vec.swap(m_buffer); 82 | lock.unlock(); 83 | 84 | if (!tmp_vec.empty()) { 85 | m_asnyc_logger->pushLogBuffer(tmp_vec); 86 | } 87 | tmp_vec.clear(); 88 | 89 | // 同步 m_app_buffer 到 app_async_logger 的buffer队尾 90 | std::vector tmp_vec2; 91 | ScopeMutex lock2(m_app_mutex); 92 | tmp_vec2.swap(m_app_buffer); 93 | lock.unlock(); 94 | 95 | if (!tmp_vec2.empty()) { 96 | m_asnyc_app_logger->pushLogBuffer(tmp_vec2); 97 | } 98 | 99 | } 100 | 101 | 102 | void Logger::InitGlobalLogger(int type /*=1*/) { 103 | 104 | LogLevel global_log_level = StringToLogLevel(Config::GetGlobalConfig()->m_log_level); 105 | printf("Init log level [%s]\n", LogLevelToString(global_log_level).c_str()); 106 | g_logger = new Logger(global_log_level, type); 107 | g_logger->init(); 108 | 109 | } 110 | 111 | 112 | 113 | std::string LogLevelToString(LogLevel level) { 114 | switch (level) { 115 | case Debug: 116 | return "DEBUG"; 117 | 118 | case Info: 119 | return "INFO"; 120 | 121 | case Error: 122 | return "ERROR"; 123 | default: 124 | return "UNKNOWN"; 125 | } 126 | } 127 | 128 | 129 | LogLevel StringToLogLevel(const std::string& log_level) { 130 | if (log_level == "DEBUG") { 131 | return Debug; 132 | } else if (log_level == "INFO") { 133 | return Info; 134 | } else if (log_level == "ERROR") { 135 | return Error; 136 | } else { 137 | return Unknown; 138 | } 139 | } 140 | 141 | std::string LogEvent::toString() { 142 | struct timeval now_time; 143 | 144 | gettimeofday(&now_time, nullptr); 145 | 146 | struct tm now_time_t; 147 | localtime_r(&(now_time.tv_sec), &now_time_t); 148 | 149 | char buf[128]; 150 | strftime(&buf[0], 128, "%y-%m-%d %H:%M:%S", &now_time_t); 151 | std::string time_str(buf); 152 | int ms = now_time.tv_usec / 1000; 153 | time_str = time_str + "." + std::to_string(ms); 154 | 155 | 156 | m_pid = getPid(); 157 | m_thread_id = getThreadId(); 158 | 159 | std::stringstream ss; 160 | 161 | ss << "[" << LogLevelToString(m_level) << "]\t" 162 | << "[" << time_str << "]\t" 163 | << "[" << m_pid << ":" << m_thread_id << "]\t"; 164 | 165 | // 获取当前线程处理的请求的 msgid 166 | 167 | std::string msgid = RunTime::GetRunTime()->m_msgid; 168 | std::string method_name = RunTime::GetRunTime()->m_method_name; 169 | if (!msgid.empty()) { 170 | ss << "[" << msgid << "]\t"; 171 | } 172 | 173 | if (!method_name.empty()) { 174 | ss << "[" << method_name << "]\t"; 175 | } 176 | return ss.str(); 177 | } 178 | 179 | 180 | 181 | void Logger::pushLog(const std::string& msg) { 182 | if (m_type == 0) { 183 | printf((msg + "\n").c_str()); 184 | return; 185 | } 186 | ScopeMutex lock(m_mutex); 187 | m_buffer.push_back(msg); 188 | lock.unlock(); 189 | } 190 | 191 | void Logger::pushAppLog(const std::string& msg) { 192 | ScopeMutex lock(m_app_mutex); 193 | m_app_buffer.push_back(msg); 194 | lock.unlock(); 195 | } 196 | 197 | 198 | void Logger::log() { 199 | 200 | } 201 | 202 | 203 | AsyncLogger::AsyncLogger(const std::string& file_name, const std::string& file_path, int max_size) 204 | : m_file_name(file_name), m_file_path(file_path), m_max_file_size(max_size) { 205 | 206 | sem_init(&m_sempahore, 0, 0); 207 | 208 | assert(pthread_create(&m_thread, NULL, &AsyncLogger::Loop, this) == 0); 209 | 210 | // assert(pthread_cond_init(&m_condtion, NULL) == 0); 211 | 212 | sem_wait(&m_sempahore); 213 | 214 | } 215 | 216 | 217 | void* AsyncLogger::Loop(void* arg) { 218 | // 将 buffer 里面的全部数据打印到文件中,然后线程睡眠,直到有新的数据再重复这个过程 219 | 220 | AsyncLogger* logger = reinterpret_cast(arg); 221 | 222 | assert(pthread_cond_init(&logger->m_condtion, NULL) == 0); 223 | 224 | sem_post(&logger->m_sempahore); 225 | 226 | while(1) { 227 | ScopeMutex lock(logger->m_mutex); 228 | while(logger->m_buffer.empty()) { 229 | // printf("begin pthread_cond_wait back \n"); 230 | pthread_cond_wait(&(logger->m_condtion), logger->m_mutex.getMutex()); 231 | } 232 | // printf("pthread_cond_wait back \n"); 233 | 234 | std::vector tmp; 235 | tmp.swap(logger->m_buffer.front()); 236 | logger->m_buffer.pop(); 237 | 238 | lock.unlock(); 239 | 240 | timeval now; 241 | gettimeofday(&now, NULL); 242 | 243 | struct tm now_time; 244 | localtime_r(&(now.tv_sec), &now_time); 245 | 246 | const char* format = "%Y%m%d"; 247 | char date[32]; 248 | strftime(date, sizeof(date), format, &now_time); 249 | 250 | if (std::string(date) != logger->m_date) { 251 | logger->m_no = 0; 252 | logger->m_reopen_flag = true; 253 | logger->m_date = std::string(date); 254 | } 255 | if (logger->m_file_hanlder == NULL) { 256 | logger->m_reopen_flag = true; 257 | } 258 | 259 | std::stringstream ss; 260 | ss << logger->m_file_path << logger->m_file_name << "_" 261 | << std::string(date) << "_log."; 262 | std::string log_file_name = ss.str() + std::to_string(logger->m_no); 263 | 264 | if (logger->m_reopen_flag) { 265 | if (logger->m_file_hanlder) { 266 | fclose(logger->m_file_hanlder); 267 | } 268 | logger->m_file_hanlder = fopen(log_file_name.c_str(), "a"); 269 | logger->m_reopen_flag = false; 270 | } 271 | 272 | if (ftell(logger->m_file_hanlder) > logger->m_max_file_size) { 273 | fclose(logger->m_file_hanlder); 274 | 275 | log_file_name = ss.str() + std::to_string(logger->m_no++); 276 | logger->m_file_hanlder = fopen(log_file_name.c_str(), "a"); 277 | logger->m_reopen_flag = false; 278 | 279 | } 280 | 281 | for (auto& i : tmp) { 282 | if (!i.empty()) { 283 | fwrite(i.c_str(), 1, i.length(), logger->m_file_hanlder); 284 | } 285 | } 286 | fflush(logger->m_file_hanlder); 287 | 288 | if (logger->m_stop_flag) { 289 | return NULL; 290 | } 291 | } 292 | 293 | return NULL; 294 | } 295 | 296 | 297 | void AsyncLogger::stop() { 298 | m_stop_flag = true; 299 | } 300 | 301 | void AsyncLogger::flush() { 302 | if (m_file_hanlder) { 303 | fflush(m_file_hanlder); 304 | } 305 | } 306 | 307 | void AsyncLogger::pushLogBuffer(std::vector& vec) { 308 | ScopeMutex lock(m_mutex); 309 | m_buffer.push(vec); 310 | pthread_cond_signal(&m_condtion); 311 | 312 | lock.unlock(); 313 | 314 | // 这时候需要唤醒异步日志线程 315 | // printf("pthread_cond_signal\n"); 316 | } 317 | 318 | } -------------------------------------------------------------------------------- /rocket/common/log.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_LOG_H 2 | #define ROCKET_COMMON_LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "rocket/common/config.h" 10 | #include "rocket/common/mutex.h" 11 | #include "rocket/net/timer_event.h" 12 | 13 | namespace rocket { 14 | 15 | 16 | template 17 | std::string formatString(const char* str, Args&&... args) { 18 | 19 | int size = snprintf(nullptr, 0, str, args...); 20 | 21 | std::string result; 22 | if (size > 0) { 23 | result.resize(size); 24 | snprintf(&result[0], size + 1, str, args...); 25 | } 26 | 27 | return result; 28 | } 29 | 30 | 31 | #define DEBUGLOG(str, ...) \ 32 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() && rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Debug) \ 33 | { \ 34 | rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Debug).toString() \ 35 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 36 | } \ 37 | 38 | 39 | #define INFOLOG(str, ...) \ 40 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Info) \ 41 | { \ 42 | rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Info).toString() \ 43 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 44 | } \ 45 | 46 | #define ERRORLOG(str, ...) \ 47 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Error) \ 48 | { \ 49 | rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Error).toString() \ 50 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 51 | } \ 52 | 53 | 54 | #define APPDEBUGLOG(str, ...) \ 55 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Debug) \ 56 | { \ 57 | rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Debug).toString() \ 58 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 59 | } \ 60 | 61 | 62 | #define APPINFOLOG(str, ...) \ 63 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Info) \ 64 | { \ 65 | rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Info).toString() \ 66 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 67 | } \ 68 | 69 | #define APPERRORLOG(str, ...) \ 70 | if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Error) \ 71 | { \ 72 | rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Error).toString() \ 73 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\ 74 | } \ 75 | 76 | 77 | 78 | enum LogLevel { 79 | Unknown = 0, 80 | Debug = 1, 81 | Info = 2, 82 | Error = 3 83 | }; 84 | 85 | 86 | std::string LogLevelToString(LogLevel level); 87 | 88 | LogLevel StringToLogLevel(const std::string& log_level); 89 | 90 | class AsyncLogger { 91 | 92 | public: 93 | typedef std::shared_ptr s_ptr; 94 | AsyncLogger(const std::string& file_name, const std::string& file_path, int max_size); 95 | 96 | void stop(); 97 | 98 | // 刷新到磁盘 99 | void flush(); 100 | 101 | void pushLogBuffer(std::vector& vec); 102 | 103 | 104 | public: 105 | static void* Loop(void*); 106 | 107 | public: 108 | pthread_t m_thread; 109 | 110 | private: 111 | // m_file_path/m_file_name_yyyymmdd.0 112 | 113 | std::queue> m_buffer; 114 | 115 | std::string m_file_name; // 日志输出文件名字 116 | std::string m_file_path; // 日志输出路径 117 | int m_max_file_size {0}; // 日志单个文件最大大小, 单位为字节 118 | 119 | sem_t m_sempahore; 120 | 121 | pthread_cond_t m_condtion; // 条件变量 122 | Mutex m_mutex; 123 | 124 | std::string m_date; // 当前打印日志的文件日期 125 | FILE* m_file_hanlder {NULL}; // 当前打开的日志文件句柄 126 | 127 | bool m_reopen_flag {false}; 128 | 129 | int m_no {0}; // 日志文件序号 130 | 131 | bool m_stop_flag {false}; 132 | 133 | }; 134 | 135 | class Logger { 136 | public: 137 | typedef std::shared_ptr s_ptr; 138 | 139 | Logger(LogLevel level, int type = 1); 140 | 141 | void pushLog(const std::string& msg); 142 | 143 | void pushAppLog(const std::string& msg); 144 | 145 | void init(); 146 | 147 | void log(); 148 | 149 | LogLevel getLogLevel() const { 150 | return m_set_level; 151 | } 152 | 153 | AsyncLogger::s_ptr getAsyncAppLopger() { 154 | return m_asnyc_app_logger; 155 | } 156 | 157 | AsyncLogger::s_ptr getAsyncLopger() { 158 | return m_asnyc_logger; 159 | } 160 | 161 | void syncLoop(); 162 | 163 | void flush(); 164 | 165 | public: 166 | static Logger* GetGlobalLogger(); 167 | 168 | static void InitGlobalLogger(int type = 1); 169 | 170 | private: 171 | LogLevel m_set_level; 172 | std::vector m_buffer; 173 | 174 | std::vector m_app_buffer; 175 | 176 | Mutex m_mutex; 177 | 178 | Mutex m_app_mutex; 179 | 180 | // m_file_path/m_file_name_yyyymmdd.1 181 | 182 | std::string m_file_name; // 日志输出文件名字 183 | std::string m_file_path; // 日志输出路径 184 | int m_max_file_size {0}; // 日志单个文件最大大小 185 | 186 | AsyncLogger::s_ptr m_asnyc_logger; 187 | 188 | AsyncLogger::s_ptr m_asnyc_app_logger; 189 | 190 | TimerEvent::s_ptr m_timer_event; 191 | 192 | int m_type {0}; 193 | 194 | }; 195 | 196 | 197 | class LogEvent { 198 | public: 199 | 200 | LogEvent(LogLevel level) : m_level(level) {} 201 | 202 | std::string getFileName() const { 203 | return m_file_name; 204 | } 205 | 206 | LogLevel getLogLevel() const { 207 | return m_level; 208 | } 209 | 210 | std::string toString(); 211 | 212 | 213 | private: 214 | std::string m_file_name; // 文件名 215 | int32_t m_file_line; // 行号 216 | int32_t m_pid; // 进程号 217 | int32_t m_thread_id; // 线程号 218 | 219 | LogLevel m_level; //日志级别 220 | 221 | }; 222 | 223 | 224 | 225 | } 226 | 227 | #endif -------------------------------------------------------------------------------- /rocket/common/msg_id_util.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rocket/common/msg_id_util.h" 5 | #include "rocket/common/log.h" 6 | 7 | namespace rocket { 8 | 9 | 10 | static int g_msg_id_length = 20; 11 | static int g_random_fd = -1; 12 | 13 | static thread_local std::string t_msg_id_no; 14 | static thread_local std::string t_max_msg_id_no; 15 | 16 | std::string MsgIDUtil::GenMsgID() { 17 | if (t_msg_id_no.empty() || t_msg_id_no == t_max_msg_id_no) { 18 | if (g_random_fd == -1) { 19 | g_random_fd = open("/dev/urandom", O_RDONLY); 20 | } 21 | std::string res(g_msg_id_length, 0); 22 | if ((read(g_random_fd, &res[0], g_msg_id_length)) != g_msg_id_length) { 23 | ERRORLOG("read form /dev/urandom error"); 24 | return ""; 25 | } 26 | for (int i = 0; i < g_msg_id_length; ++i) { 27 | uint8_t x = ((uint8_t)(res[i])) % 10; 28 | res[i] = x + '0'; 29 | t_max_msg_id_no += "9"; 30 | } 31 | t_msg_id_no = res; 32 | } else { 33 | size_t i = t_msg_id_no.length() - 1; 34 | while (t_msg_id_no[i] == '9' && i >= 0) { 35 | i--; 36 | } 37 | if (i >= 0) { 38 | t_msg_id_no[i] += 1; 39 | for (size_t j = i + 1; j < t_msg_id_no.length(); ++j) { 40 | t_msg_id_no[j] = '0'; 41 | } 42 | } 43 | } 44 | 45 | return t_msg_id_no; 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /rocket/common/msg_id_util.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_MSGID_UTIL_H 2 | #define ROCKET_COMMON_MSGID_UTIL_H 3 | 4 | #include 5 | 6 | 7 | namespace rocket { 8 | 9 | class MsgIDUtil { 10 | 11 | public: 12 | static std::string GenMsgID(); 13 | 14 | }; 15 | 16 | } 17 | 18 | 19 | #endif -------------------------------------------------------------------------------- /rocket/common/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_MUTEX_H 2 | #define ROCKET_COMMON_MUTEX_H 3 | 4 | #include 5 | 6 | 7 | namespace rocket { 8 | 9 | template 10 | class ScopeMutex { 11 | 12 | public: 13 | ScopeMutex(T& mutex) : m_mutex(mutex) { 14 | m_mutex.lock(); 15 | m_is_lock = true; 16 | } 17 | 18 | ~ScopeMutex() { 19 | m_mutex.unlock(); 20 | m_is_lock = false; 21 | } 22 | 23 | void lock() { 24 | if (!m_is_lock) { 25 | m_mutex.lock(); 26 | } 27 | } 28 | 29 | void unlock() { 30 | if (m_is_lock) { 31 | m_mutex.unlock(); 32 | } 33 | } 34 | 35 | private: 36 | 37 | T& m_mutex; 38 | 39 | bool m_is_lock {false}; 40 | 41 | }; 42 | 43 | 44 | class Mutex { 45 | public: 46 | Mutex() { 47 | pthread_mutex_init(&m_mutex, NULL); 48 | } 49 | 50 | ~Mutex() { 51 | pthread_mutex_destroy(&m_mutex); 52 | } 53 | 54 | void lock() { 55 | pthread_mutex_lock(&m_mutex); 56 | } 57 | 58 | void unlock() { 59 | pthread_mutex_unlock(&m_mutex); 60 | } 61 | 62 | pthread_mutex_t* getMutex() { 63 | return &m_mutex; 64 | } 65 | 66 | private: 67 | pthread_mutex_t m_mutex; 68 | 69 | }; 70 | 71 | } 72 | 73 | #endif -------------------------------------------------------------------------------- /rocket/common/run_time.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "rocket/common/run_time.h" 3 | 4 | namespace rocket { 5 | 6 | 7 | thread_local RunTime* t_run_time = NULL; 8 | 9 | RunTime* RunTime::GetRunTime() { 10 | if (t_run_time) { 11 | return t_run_time; 12 | } 13 | t_run_time = new RunTime(); 14 | return t_run_time; 15 | } 16 | 17 | 18 | RpcInterface* RunTime::getRpcInterface() { 19 | return m_rpc_interface; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /rocket/common/run_time.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_RUN_TIME_H 2 | #define ROCKET_COMMON_RUN_TIME_H 3 | 4 | 5 | #include 6 | 7 | namespace rocket { 8 | 9 | class RpcInterface; 10 | 11 | class RunTime { 12 | public: 13 | RpcInterface* getRpcInterface(); 14 | 15 | public: 16 | static RunTime* GetRunTime(); 17 | 18 | 19 | public: 20 | std::string m_msgid; 21 | std::string m_method_name; 22 | RpcInterface* m_rpc_interface {NULL}; 23 | 24 | }; 25 | 26 | } 27 | 28 | 29 | #endif -------------------------------------------------------------------------------- /rocket/common/util.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "rocket/common/util.h" 8 | 9 | 10 | namespace rocket { 11 | 12 | static int g_pid = 0; 13 | 14 | static thread_local int t_thread_id = 0; 15 | 16 | pid_t getPid() { 17 | if (g_pid != 0) { 18 | return g_pid; 19 | } 20 | return getpid(); 21 | } 22 | 23 | pid_t getThreadId() { 24 | if (t_thread_id != 0) { 25 | return t_thread_id; 26 | } 27 | return syscall(SYS_gettid); 28 | } 29 | 30 | 31 | int64_t getNowMs() { 32 | timeval val; 33 | gettimeofday(&val, NULL); 34 | 35 | return val.tv_sec * 1000 + val.tv_usec / 1000; 36 | 37 | } 38 | 39 | 40 | int32_t getInt32FromNetByte(const char* buf) { 41 | int32_t re; 42 | memcpy(&re, buf, sizeof(re)); 43 | return ntohl(re); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /rocket/common/util.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_COMMON_UTIL_H 2 | #define ROCKET_COMMON_UTIL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace rocket { 8 | 9 | pid_t getPid(); 10 | 11 | pid_t getThreadId(); 12 | 13 | int64_t getNowMs(); 14 | 15 | int32_t getInt32FromNetByte(const char* buf); 16 | 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /rocket/net/coder/abstract_coder.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_ABSTRACT_CODER_H 2 | #define ROCKET_NET_ABSTRACT_CODER_H 3 | 4 | #include 5 | #include "rocket/net/tcp/tcp_buffer.h" 6 | #include "rocket/net/coder/abstract_protocol.h" 7 | 8 | namespace rocket { 9 | 10 | class AbstractCoder { 11 | public: 12 | 13 | // 将 message 对象转化为字节流,写入到 buffer 14 | virtual void encode(std::vector& messages, TcpBuffer::s_ptr out_buffer) = 0; 15 | 16 | // 将 buffer 里面的字节流转换为 message 对象 17 | virtual void decode(std::vector& out_messages, TcpBuffer::s_ptr buffer) = 0; 18 | 19 | virtual ~AbstractCoder() {} 20 | 21 | }; 22 | 23 | 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /rocket/net/coder/abstract_protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_ABSTRACT_PROTOCOL_H 2 | #define ROCKET_NET_ABSTRACT_PROTOCOL_H 3 | 4 | #include 5 | 6 | 7 | namespace rocket { 8 | 9 | struct AbstractProtocol : public std::enable_shared_from_this { 10 | public: 11 | typedef std::shared_ptr s_ptr; 12 | 13 | virtual ~AbstractProtocol() {} 14 | 15 | public: 16 | std::string m_msg_id; // 请求号,唯一标识一个请求或者响应 17 | 18 | 19 | }; 20 | 21 | } 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /rocket/net/coder/string_coder.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKERT_NET_STRING_CODER_H 2 | #define ROCKERT_NET_STRING_CODER_H 3 | 4 | #include "rocket/net/coder/abstract_coder.h" 5 | #include "rocket/net/coder/abstract_protocol.h" 6 | 7 | namespace rocket { 8 | 9 | class StringProtocol : public AbstractProtocol { 10 | 11 | public: 12 | std::string info; 13 | 14 | }; 15 | 16 | class StringCoder : public AbstractCoder { 17 | // 将 message 对象转化为字节流,写入到 buffer 18 | void encode(std::vector& messages, TcpBuffer::s_ptr out_buffer) { 19 | for (size_t i = 0; i < messages.size(); ++i) { 20 | std::shared_ptr msg = std::dynamic_pointer_cast(messages[i]); 21 | out_buffer->writeToBuffer(msg->info.c_str(), msg->info.length()); 22 | } 23 | } 24 | 25 | // 将 buffer 里面的字节流转换为 message 对象 26 | void decode(std::vector& out_messages, TcpBuffer::s_ptr buffer) { 27 | std::vector re; 28 | buffer->readFromBuffer(re, buffer->readAble()); 29 | std::string info; 30 | for (size_t i = 0; i < re.size(); ++i) { 31 | info += re[i]; 32 | } 33 | 34 | std::shared_ptr msg = std::make_shared(); 35 | msg->info = info; 36 | msg->m_msg_id = "123456"; 37 | out_messages.push_back(msg); 38 | } 39 | 40 | }; 41 | 42 | } 43 | 44 | #endif -------------------------------------------------------------------------------- /rocket/net/coder/tinypb_coder.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rocket/net/coder/tinypb_coder.h" 5 | #include "rocket/net/coder/tinypb_protocol.h" 6 | #include "rocket/common/util.h" 7 | #include "rocket/common/log.h" 8 | 9 | namespace rocket { 10 | 11 | // 将 message 对象转化为字节流,写入到 buffer 12 | void TinyPBCoder::encode(std::vector& messages, TcpBuffer::s_ptr out_buffer) { 13 | for (auto &i : messages) { 14 | std::shared_ptr msg = std::dynamic_pointer_cast(i); 15 | int len = 0; 16 | const char* buf = encodeTinyPB(msg, len); 17 | if (buf != NULL && len != 0) { 18 | out_buffer->writeToBuffer(buf, len); 19 | } 20 | if (buf) { 21 | free((void*)buf); 22 | buf = NULL; 23 | } 24 | 25 | } 26 | } 27 | 28 | // 将 buffer 里面的字节流转换为 message 对象 29 | void TinyPBCoder::decode(std::vector& out_messages, TcpBuffer::s_ptr buffer) { 30 | while(1) { 31 | // 遍历 buffer,找到 PB_START,找到之后,解析出整包的长度。然后得到结束符的位置,判断是否为 PB_END 32 | std::vector tmp = buffer->m_buffer; 33 | int start_index = buffer->readIndex(); 34 | int end_index = -1; 35 | 36 | int pk_len = 0; 37 | bool parse_success = false; 38 | int i = 0; 39 | for (i = start_index; i < buffer->writeIndex(); ++i) { 40 | if (tmp[i] == TinyPBProtocol::PB_START) { 41 | // 读下去四个字节。由于是网络字节序,需要转为主机字节序 42 | if (i + 1 < buffer->writeIndex()) { 43 | pk_len = getInt32FromNetByte(&tmp[i+1]); 44 | DEBUGLOG("get pk_len = %d", pk_len); 45 | 46 | // 结束符的索引 47 | int j = i + pk_len - 1; 48 | if (j >= buffer->writeIndex()) { 49 | continue; 50 | } 51 | if (tmp[j] == TinyPBProtocol::PB_END) { 52 | start_index = i; 53 | end_index = j; 54 | parse_success = true; 55 | break; 56 | } 57 | 58 | } 59 | } 60 | } 61 | 62 | if (i >= buffer->writeIndex()) { 63 | DEBUGLOG("decode end, read all buffer data"); 64 | return; 65 | } 66 | 67 | if (parse_success) { 68 | buffer->moveReadIndex(end_index - start_index + 1); 69 | std::shared_ptr message = std::make_shared(); 70 | message->m_pk_len = pk_len; 71 | 72 | int msg_id_len_index = start_index + sizeof(char) + sizeof(message->m_pk_len); 73 | if (msg_id_len_index >= end_index) { 74 | message->parse_success = false; 75 | ERRORLOG("parse error, msg_id_len_index[%d] >= end_index[%d]", msg_id_len_index, end_index); 76 | continue; 77 | } 78 | message->m_msg_id_len = getInt32FromNetByte(&tmp[msg_id_len_index]); 79 | DEBUGLOG("parse msg_id_len=%d", message->m_msg_id_len); 80 | 81 | int msg_id_index = msg_id_len_index + sizeof(message->m_msg_id_len); 82 | 83 | char msg_id[100] = {0}; 84 | memcpy(&msg_id[0], &tmp[msg_id_index], message->m_msg_id_len); 85 | message->m_msg_id = std::string(msg_id); 86 | DEBUGLOG("parse msg_id=%s", message->m_msg_id.c_str()); 87 | 88 | int method_name_len_index = msg_id_index + message->m_msg_id_len; 89 | if (method_name_len_index >= end_index) { 90 | message->parse_success = false; 91 | ERRORLOG("parse error, method_name_len_index[%d] >= end_index[%d]", method_name_len_index, end_index); 92 | continue; 93 | } 94 | message->m_method_name_len = getInt32FromNetByte(&tmp[method_name_len_index]); 95 | 96 | int method_name_index = method_name_len_index + sizeof(message->m_method_name_len); 97 | char method_name[512] = {0}; 98 | memcpy(&method_name[0], &tmp[method_name_index], message->m_method_name_len); 99 | message->m_method_name = std::string(method_name); 100 | DEBUGLOG("parse method_name=%s", message->m_method_name.c_str()); 101 | 102 | int err_code_index = method_name_index + message->m_method_name_len; 103 | if (err_code_index >= end_index) { 104 | message->parse_success = false; 105 | ERRORLOG("parse error, err_code_index[%d] >= end_index[%d]", err_code_index, end_index); 106 | continue; 107 | } 108 | message->m_err_code = getInt32FromNetByte(&tmp[err_code_index]); 109 | 110 | 111 | int error_info_len_index = err_code_index + sizeof(message->m_err_code); 112 | if (error_info_len_index >= end_index) { 113 | message->parse_success = false; 114 | ERRORLOG("parse error, error_info_len_index[%d] >= end_index[%d]", error_info_len_index, end_index); 115 | continue; 116 | } 117 | message->m_err_info_len = getInt32FromNetByte(&tmp[error_info_len_index]); 118 | 119 | int err_info_index = error_info_len_index + sizeof(message->m_err_info_len); 120 | char error_info[512] = {0}; 121 | memcpy(&error_info[0], &tmp[err_info_index], message->m_err_info_len); 122 | message->m_err_info = std::string(error_info); 123 | DEBUGLOG("parse error_info=%s", message->m_err_info.c_str()); 124 | 125 | int pb_data_len = message->m_pk_len - message->m_method_name_len - message->m_msg_id_len - message->m_err_info_len - 2 - 24; 126 | 127 | int pd_data_index = err_info_index + message->m_err_info_len; 128 | message->m_pb_data = std::string(&tmp[pd_data_index], pb_data_len); 129 | 130 | // 这里校验和去解析 131 | message->parse_success = true; 132 | 133 | out_messages.push_back(message); 134 | } 135 | 136 | } 137 | 138 | 139 | } 140 | 141 | 142 | const char* TinyPBCoder::encodeTinyPB(std::shared_ptr message, int& len) { 143 | if (message->m_msg_id.empty()) { 144 | message->m_msg_id = "123456789"; 145 | } 146 | DEBUGLOG("msg_id = %s", message->m_msg_id.c_str()); 147 | int pk_len = 2 + 24 + message->m_msg_id.length() + message->m_method_name.length() + message->m_err_info.length() + message->m_pb_data.length(); 148 | DEBUGLOG("pk_len = %", pk_len); 149 | 150 | char* buf = reinterpret_cast(malloc(pk_len)); 151 | char* tmp = buf; 152 | 153 | *tmp = TinyPBProtocol::PB_START; 154 | tmp++; 155 | 156 | int32_t pk_len_net = htonl(pk_len); 157 | memcpy(tmp, &pk_len_net, sizeof(pk_len_net)); 158 | tmp += sizeof(pk_len_net); 159 | 160 | int msg_id_len = message->m_msg_id.length(); 161 | int32_t msg_id_len_net = htonl(msg_id_len); 162 | memcpy(tmp, &msg_id_len_net, sizeof(msg_id_len_net)); 163 | tmp += sizeof(msg_id_len_net); 164 | 165 | if (!message->m_msg_id.empty()) { 166 | memcpy(tmp, &(message->m_msg_id[0]), msg_id_len); 167 | tmp += msg_id_len; 168 | } 169 | 170 | int method_name_len = message->m_method_name.length(); 171 | int32_t method_name_len_net = htonl(method_name_len); 172 | memcpy(tmp, &method_name_len_net, sizeof(method_name_len_net)); 173 | tmp += sizeof(method_name_len_net); 174 | 175 | if (!message->m_method_name.empty()) { 176 | memcpy(tmp, &(message->m_method_name[0]), method_name_len); 177 | tmp += method_name_len; 178 | } 179 | 180 | int32_t err_code_net = htonl(message->m_err_code); 181 | memcpy(tmp, &err_code_net, sizeof(err_code_net)); 182 | tmp += sizeof(err_code_net); 183 | 184 | int err_info_len = message->m_err_info.length(); 185 | int32_t err_info_len_net = htonl(err_info_len); 186 | memcpy(tmp, &err_info_len_net, sizeof(err_info_len_net)); 187 | tmp += sizeof(err_info_len_net); 188 | 189 | if (!message->m_err_info.empty()) { 190 | memcpy(tmp, &(message->m_err_info[0]), err_info_len); 191 | tmp += err_info_len; 192 | } 193 | 194 | if (!message->m_pb_data.empty()) { 195 | memcpy(tmp, &(message->m_pb_data[0]), message->m_pb_data.length()); 196 | tmp += message->m_pb_data.length(); 197 | } 198 | 199 | int32_t check_sum_net = htonl(1); 200 | memcpy(tmp, &check_sum_net, sizeof(check_sum_net)); 201 | tmp += sizeof(check_sum_net); 202 | 203 | *tmp = TinyPBProtocol::PB_END; 204 | 205 | message->m_pk_len = pk_len; 206 | message->m_msg_id_len = msg_id_len; 207 | message->m_method_name_len = method_name_len; 208 | message->m_err_info_len = err_info_len; 209 | message->parse_success = true; 210 | len = pk_len; 211 | 212 | DEBUGLOG("encode message[%s] success", message->m_msg_id.c_str()); 213 | 214 | return buf; 215 | } 216 | 217 | 218 | } -------------------------------------------------------------------------------- /rocket/net/coder/tinypb_coder.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_CODER_TINYPB_CODER_H 2 | #define ROCKET_NET_CODER_TINYPB_CODER_H 3 | 4 | #include "rocket/net/coder/abstract_coder.h" 5 | #include "rocket/net/coder/tinypb_protocol.h" 6 | 7 | namespace rocket { 8 | 9 | class TinyPBCoder : public AbstractCoder { 10 | 11 | public: 12 | 13 | TinyPBCoder() {} 14 | ~TinyPBCoder() {} 15 | 16 | // 将 message 对象转化为字节流,写入到 buffer 17 | void encode(std::vector& messages, TcpBuffer::s_ptr out_buffer); 18 | 19 | // 将 buffer 里面的字节流转换为 message 对象 20 | void decode(std::vector& out_messages, TcpBuffer::s_ptr buffer); 21 | 22 | 23 | private: 24 | const char* encodeTinyPB(std::shared_ptr message, int& len); 25 | 26 | }; 27 | 28 | 29 | } 30 | 31 | 32 | #endif -------------------------------------------------------------------------------- /rocket/net/coder/tinypb_protocol.cc: -------------------------------------------------------------------------------- 1 | #include "rocket/net/coder/tinypb_protocol.h" 2 | 3 | namespace rocket { 4 | 5 | char TinyPBProtocol::PB_START = 0x02; 6 | char TinyPBProtocol::PB_END = 0x03; 7 | 8 | } -------------------------------------------------------------------------------- /rocket/net/coder/tinypb_protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_CODER_TINYPB_PROTOCOL_H 2 | #define ROCKET_NET_CODER_TINYPB_PROTOCOL_H 3 | 4 | #include 5 | #include "rocket/net/coder/abstract_protocol.h" 6 | 7 | namespace rocket { 8 | 9 | struct TinyPBProtocol : public AbstractProtocol { 10 | public: 11 | TinyPBProtocol(){} 12 | ~TinyPBProtocol() {} 13 | 14 | public: 15 | static char PB_START; 16 | static char PB_END; 17 | 18 | public: 19 | int32_t m_pk_len {0}; 20 | int32_t m_msg_id_len {0}; 21 | // msg_id 继承父类 22 | 23 | int32_t m_method_name_len {0}; 24 | std::string m_method_name; 25 | int32_t m_err_code {0}; 26 | int32_t m_err_info_len {0}; 27 | std::string m_err_info; 28 | std::string m_pb_data; 29 | int32_t m_check_sum {0}; 30 | 31 | bool parse_success {false}; 32 | 33 | }; 34 | 35 | 36 | 37 | } 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /rocket/net/eventloop.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rocket/net/eventloop.h" 6 | #include "rocket/common/log.h" 7 | #include "rocket/common/util.h" 8 | 9 | 10 | #define ADD_TO_EPOLL() \ 11 | auto it = m_listen_fds.find(event->getFd()); \ 12 | int op = EPOLL_CTL_ADD; \ 13 | if (it != m_listen_fds.end()) { \ 14 | op = EPOLL_CTL_MOD; \ 15 | } \ 16 | epoll_event tmp = event->getEpollEvent(); \ 17 | INFOLOG("epoll_event.events = %d", (int)tmp.events); \ 18 | int rt = epoll_ctl(m_epoll_fd, op, event->getFd(), &tmp); \ 19 | if (rt == -1) { \ 20 | ERRORLOG("failed epoll_ctl when add fd, errno=%d, error=%s", errno, strerror(errno)); \ 21 | } \ 22 | m_listen_fds.insert(event->getFd()); \ 23 | DEBUGLOG("add event success, fd[%d]", event->getFd()) \ 24 | 25 | 26 | #define DELETE_TO_EPOLL() \ 27 | auto it = m_listen_fds.find(event->getFd()); \ 28 | if (it == m_listen_fds.end()) { \ 29 | return; \ 30 | } \ 31 | int op = EPOLL_CTL_DEL; \ 32 | epoll_event tmp = event->getEpollEvent(); \ 33 | int rt = epoll_ctl(m_epoll_fd, op, event->getFd(), NULL); \ 34 | if (rt == -1) { \ 35 | ERRORLOG("failed epoll_ctl when add fd, errno=%d, error=%s", errno, strerror(errno)); \ 36 | } \ 37 | m_listen_fds.erase(event->getFd()); \ 38 | DEBUGLOG("delete event success, fd[%d]", event->getFd()); \ 39 | 40 | namespace rocket { 41 | 42 | static thread_local EventLoop* t_current_eventloop = NULL; 43 | static int g_epoll_max_timeout = 10000; 44 | static int g_epoll_max_events = 10; 45 | 46 | EventLoop::EventLoop() { 47 | if (t_current_eventloop != NULL) { 48 | ERRORLOG("failed to create event loop, this thread has created event loop"); 49 | exit(0); 50 | } 51 | m_thread_id = getThreadId(); 52 | 53 | m_epoll_fd = epoll_create(10); 54 | 55 | if (m_epoll_fd == -1) { 56 | ERRORLOG("failed to create event loop, epoll_create error, error info[%d]", errno); 57 | exit(0); 58 | } 59 | 60 | initWakeUpFdEevent(); 61 | initTimer(); 62 | 63 | INFOLOG("succ create event loop in thread %d", m_thread_id); 64 | t_current_eventloop = this; 65 | } 66 | 67 | EventLoop::~EventLoop() { 68 | close(m_epoll_fd); 69 | if (m_wakeup_fd_event) { 70 | delete m_wakeup_fd_event; 71 | m_wakeup_fd_event = NULL; 72 | } 73 | if (m_timer) { 74 | delete m_timer; 75 | m_timer = NULL; 76 | } 77 | } 78 | 79 | 80 | void EventLoop::initTimer() { 81 | m_timer = new Timer(); 82 | addEpollEvent(m_timer); 83 | } 84 | 85 | void EventLoop::addTimerEvent(TimerEvent::s_ptr event) { 86 | m_timer->addTimerEvent(event); 87 | } 88 | 89 | void EventLoop::initWakeUpFdEevent() { 90 | m_wakeup_fd = eventfd(0, EFD_NONBLOCK); 91 | if (m_wakeup_fd < 0) { 92 | ERRORLOG("failed to create event loop, eventfd create error, error info[%d]", errno); 93 | exit(0); 94 | } 95 | INFOLOG("wakeup fd = %d", m_wakeup_fd); 96 | 97 | m_wakeup_fd_event = new WakeUpFdEvent(m_wakeup_fd); 98 | 99 | m_wakeup_fd_event->listen(FdEvent::IN_EVENT, [this]() { 100 | char buf[8]; 101 | while(read(m_wakeup_fd, buf, 8) != -1 && errno != EAGAIN) { 102 | } 103 | DEBUGLOG("read full bytes from wakeup fd[%d]", m_wakeup_fd); 104 | }); 105 | 106 | addEpollEvent(m_wakeup_fd_event); 107 | 108 | } 109 | 110 | 111 | void EventLoop::loop() { 112 | m_is_looping = true; 113 | while(!m_stop_flag) { 114 | ScopeMutex lock(m_mutex); 115 | std::queue> tmp_tasks; 116 | m_pending_tasks.swap(tmp_tasks); 117 | lock.unlock(); 118 | 119 | while (!tmp_tasks.empty()) { 120 | std::function cb = tmp_tasks.front(); 121 | tmp_tasks.pop(); 122 | if (cb) { 123 | cb(); 124 | } 125 | } 126 | 127 | // 如果有定时任务需要执行,那么执行 128 | // 1. 怎么判断一个定时任务需要执行? (now() > TimerEvent.arrtive_time) 129 | // 2. arrtive_time 如何让 eventloop 监听 130 | 131 | int timeout = g_epoll_max_timeout; 132 | epoll_event result_events[g_epoll_max_events]; 133 | // DEBUGLOG("now begin to epoll_wait"); 134 | int rt = epoll_wait(m_epoll_fd, result_events, g_epoll_max_events, timeout); 135 | // DEBUGLOG("now end epoll_wait, rt = %d", rt); 136 | 137 | if (rt < 0) { 138 | ERRORLOG("epoll_wait error, errno=%d, error=%s", errno, strerror(errno)); 139 | } else { 140 | for (int i = 0; i < rt; ++i) { 141 | epoll_event trigger_event = result_events[i]; 142 | FdEvent* fd_event = static_cast(trigger_event.data.ptr); 143 | if (fd_event == NULL) { 144 | ERRORLOG("fd_event = NULL, continue"); 145 | continue; 146 | } 147 | 148 | // int event = (int)(trigger_event.events); 149 | // DEBUGLOG("unkonow event = %d", event); 150 | 151 | if (trigger_event.events & EPOLLIN) { 152 | 153 | // DEBUGLOG("fd %d trigger EPOLLIN event", fd_event->getFd()) 154 | addTask(fd_event->handler(FdEvent::IN_EVENT)); 155 | } 156 | if (trigger_event.events & EPOLLOUT) { 157 | // DEBUGLOG("fd %d trigger EPOLLOUT event", fd_event->getFd()) 158 | addTask(fd_event->handler(FdEvent::OUT_EVENT)); 159 | } 160 | 161 | // EPOLLHUP EPOLLERR 162 | if (trigger_event.events & EPOLLERR) { 163 | DEBUGLOG("fd %d trigger EPOLLERROR event", fd_event->getFd()) 164 | // 删除出错的套接字 165 | deleteEpollEvent(fd_event); 166 | if (fd_event->handler(FdEvent::ERROR_EVENT) != nullptr) { 167 | DEBUGLOG("fd %d add error callback", fd_event->getFd()) 168 | addTask(fd_event->handler(FdEvent::OUT_EVENT)); 169 | } 170 | } 171 | } 172 | } 173 | 174 | } 175 | 176 | } 177 | 178 | void EventLoop::wakeup() { 179 | INFOLOG("WAKE UP"); 180 | m_wakeup_fd_event->wakeup(); 181 | } 182 | 183 | void EventLoop::stop() { 184 | m_stop_flag = true; 185 | wakeup(); 186 | } 187 | 188 | void EventLoop::dealWakeup() { 189 | 190 | } 191 | 192 | void EventLoop::addEpollEvent(FdEvent* event) { 193 | if (isInLoopThread()) { 194 | ADD_TO_EPOLL(); 195 | } else { 196 | auto cb = [this, event]() { 197 | ADD_TO_EPOLL(); 198 | }; 199 | addTask(cb, true); 200 | } 201 | 202 | } 203 | 204 | void EventLoop::deleteEpollEvent(FdEvent* event) { 205 | if (isInLoopThread()) { 206 | DELETE_TO_EPOLL(); 207 | } else { 208 | 209 | auto cb = [this, event]() { 210 | DELETE_TO_EPOLL(); 211 | }; 212 | addTask(cb, true); 213 | } 214 | 215 | } 216 | 217 | void EventLoop::addTask(std::function cb, bool is_wake_up /*=false*/) { 218 | ScopeMutex lock(m_mutex); 219 | m_pending_tasks.push(cb); 220 | lock.unlock(); 221 | 222 | if (is_wake_up) { 223 | wakeup(); 224 | } 225 | } 226 | 227 | bool EventLoop::isInLoopThread() { 228 | return getThreadId() == m_thread_id; 229 | } 230 | 231 | 232 | EventLoop* EventLoop::GetCurrentEventLoop() { 233 | if (t_current_eventloop) { 234 | return t_current_eventloop; 235 | } 236 | t_current_eventloop = new EventLoop(); 237 | return t_current_eventloop; 238 | } 239 | 240 | 241 | bool EventLoop::isLooping() { 242 | return m_is_looping; 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /rocket/net/eventloop.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_EVENTLOOP_H 2 | #define ROCKET_NET_EVENTLOOP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "rocket/common/mutex.h" 9 | #include "rocket/net/fd_event.h" 10 | #include "rocket/net/wakeup_fd_event.h" 11 | #include "rocket/net/timer.h" 12 | 13 | namespace rocket { 14 | class EventLoop { 15 | public: 16 | EventLoop(); 17 | 18 | ~EventLoop(); 19 | 20 | void loop(); 21 | 22 | void wakeup(); 23 | 24 | void stop(); 25 | 26 | void addEpollEvent(FdEvent* event); 27 | 28 | void deleteEpollEvent(FdEvent* event); 29 | 30 | bool isInLoopThread(); 31 | 32 | void addTask(std::function cb, bool is_wake_up = false); 33 | 34 | void addTimerEvent(TimerEvent::s_ptr event); 35 | 36 | bool isLooping(); 37 | 38 | public: 39 | static EventLoop* GetCurrentEventLoop(); 40 | 41 | 42 | private: 43 | void dealWakeup(); 44 | 45 | void initWakeUpFdEevent(); 46 | 47 | void initTimer(); 48 | 49 | private: 50 | pid_t m_thread_id {0}; 51 | 52 | int m_epoll_fd {0}; 53 | 54 | int m_wakeup_fd {0}; 55 | 56 | WakeUpFdEvent* m_wakeup_fd_event {NULL}; 57 | 58 | bool m_stop_flag {false}; 59 | 60 | std::set m_listen_fds; 61 | 62 | std::queue> m_pending_tasks; 63 | 64 | Mutex m_mutex; 65 | 66 | Timer* m_timer {NULL}; 67 | 68 | bool m_is_looping {false}; 69 | 70 | }; 71 | 72 | } 73 | 74 | 75 | #endif -------------------------------------------------------------------------------- /rocket/net/fd_event.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rocket/net/fd_event.h" 4 | #include "rocket/common/log.h" 5 | 6 | namespace rocket { 7 | 8 | FdEvent::FdEvent(int fd) : m_fd(fd) { 9 | memset(&m_listen_events, 0, sizeof(m_listen_events)); 10 | } 11 | 12 | 13 | FdEvent::FdEvent() { 14 | memset(&m_listen_events, 0, sizeof(m_listen_events)); 15 | } 16 | 17 | 18 | 19 | FdEvent::~FdEvent() { 20 | 21 | } 22 | 23 | 24 | std::function FdEvent::handler(TriggerEvent event) { 25 | if (event == TriggerEvent::IN_EVENT) { 26 | return m_read_callback; 27 | } else if (event == TriggerEvent::OUT_EVENT) { 28 | return m_write_callback; 29 | } else if (event == TriggerEvent::ERROR_EVENT) { 30 | return m_error_callback; 31 | } 32 | return nullptr; 33 | } 34 | 35 | 36 | void FdEvent::listen(TriggerEvent event_type, std::function callback, std::function error_callback /*= nullptr*/) { 37 | if (event_type == TriggerEvent::IN_EVENT) { 38 | m_listen_events.events |= EPOLLIN; 39 | m_read_callback = callback; 40 | } else { 41 | m_listen_events.events |= EPOLLOUT; 42 | m_write_callback = callback; 43 | } 44 | 45 | if (m_error_callback == nullptr) { 46 | m_error_callback = error_callback; 47 | } else { 48 | m_error_callback = nullptr; 49 | } 50 | 51 | m_listen_events.data.ptr = this; 52 | } 53 | 54 | 55 | void FdEvent::cancle(TriggerEvent event_type) { 56 | if (event_type == TriggerEvent::IN_EVENT) { 57 | m_listen_events.events &= (~EPOLLIN); 58 | } else { 59 | m_listen_events.events &= (~EPOLLOUT); 60 | } 61 | } 62 | 63 | 64 | void FdEvent::setNonBlock() { 65 | 66 | int flag = fcntl(m_fd, F_GETFL, 0); 67 | if (flag & O_NONBLOCK) { 68 | return; 69 | } 70 | 71 | fcntl(m_fd, F_SETFL, flag | O_NONBLOCK); 72 | } 73 | 74 | 75 | } -------------------------------------------------------------------------------- /rocket/net/fd_event.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ROCKET_NET_FDEVENT_H 3 | #define ROCKET_NET_FDEVENT_H 4 | 5 | #include 6 | #include 7 | 8 | namespace rocket { 9 | class FdEvent { 10 | public: 11 | enum TriggerEvent { 12 | IN_EVENT = EPOLLIN, 13 | OUT_EVENT = EPOLLOUT, 14 | ERROR_EVENT = EPOLLERR, 15 | }; 16 | 17 | FdEvent(int fd); 18 | 19 | FdEvent(); 20 | 21 | ~FdEvent(); 22 | 23 | void setNonBlock(); 24 | 25 | std::function handler(TriggerEvent event_type); 26 | 27 | void listen(TriggerEvent event_type, std::function callback, std::function error_callback = nullptr); 28 | 29 | // 取消监听 30 | void cancle(TriggerEvent event_type); 31 | 32 | int getFd() const { 33 | return m_fd; 34 | } 35 | 36 | epoll_event getEpollEvent() { 37 | return m_listen_events; 38 | } 39 | 40 | 41 | protected: 42 | int m_fd {-1}; 43 | 44 | epoll_event m_listen_events; 45 | 46 | std::function m_read_callback {nullptr}; 47 | std::function m_write_callback {nullptr}; 48 | std::function m_error_callback {nullptr}; 49 | 50 | }; 51 | 52 | } 53 | 54 | #endif -------------------------------------------------------------------------------- /rocket/net/fd_event_group.cc: -------------------------------------------------------------------------------- 1 | #include "rocket/net/fd_event_group.h" 2 | #include "rocket/common/mutex.h" 3 | #include "rocket/common/log.h" 4 | 5 | namespace rocket { 6 | 7 | 8 | static FdEventGroup* g_fd_event_group = NULL; 9 | 10 | FdEventGroup* FdEventGroup::GetFdEventGroup() { 11 | if (g_fd_event_group != NULL) { 12 | return g_fd_event_group; 13 | } 14 | 15 | g_fd_event_group = new FdEventGroup(128); 16 | return g_fd_event_group; 17 | } 18 | 19 | FdEventGroup::FdEventGroup(int size) :m_size(size) { 20 | for (int i = 0; i < m_size; i++) { 21 | m_fd_group.push_back(new FdEvent(i)); 22 | } 23 | } 24 | 25 | FdEventGroup::~FdEventGroup() { 26 | for (int i = 0; i < m_size; ++i) { 27 | if (m_fd_group[i] != NULL) { 28 | delete m_fd_group[i]; 29 | m_fd_group[i] = NULL; 30 | } 31 | } 32 | } 33 | 34 | FdEvent* FdEventGroup::getFdEvent(int fd) { 35 | ScopeMutex lock(m_mutex); 36 | if ((size_t) fd < m_fd_group.size()) { 37 | return m_fd_group[fd]; 38 | } 39 | 40 | int new_size = int(fd * 1.5); 41 | for (int i = m_fd_group.size(); i < new_size; ++i) { 42 | m_fd_group.push_back(new FdEvent(i)); 43 | } 44 | return m_fd_group[fd]; 45 | 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /rocket/net/fd_event_group.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_FD_EVENT_GROUP_H 2 | #define ROCKET_NET_FD_EVENT_GROUP_H 3 | 4 | #include 5 | #include "rocket/common/mutex.h" 6 | #include "rocket/net/fd_event.h" 7 | 8 | namespace rocket { 9 | 10 | class FdEventGroup { 11 | 12 | public: 13 | 14 | FdEventGroup(int size); 15 | 16 | ~FdEventGroup(); 17 | FdEvent* getFdEvent(int fd); 18 | 19 | public: 20 | static FdEventGroup* GetFdEventGroup(); 21 | 22 | private: 23 | int m_size {0}; 24 | std::vector m_fd_group; 25 | Mutex m_mutex; 26 | 27 | }; 28 | 29 | } 30 | 31 | #endif -------------------------------------------------------------------------------- /rocket/net/io_thread.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "rocket/net/io_thread.h" 5 | #include "rocket/common/log.h" 6 | #include "rocket/common/util.h" 7 | 8 | 9 | namespace rocket { 10 | 11 | IOThread::IOThread() { 12 | 13 | int rt = sem_init(&m_init_semaphore, 0, 0); 14 | assert(rt == 0); 15 | 16 | rt = sem_init(&m_start_semaphore, 0, 0); 17 | assert(rt == 0); 18 | 19 | pthread_create(&m_thread, NULL, &IOThread::Main, this); 20 | 21 | // wait, 直到新线程执行完 Main 函数的前置 22 | sem_wait(&m_init_semaphore); 23 | 24 | DEBUGLOG("IOThread [%d] create success", m_thread_id); 25 | } 26 | 27 | IOThread::~IOThread() { 28 | 29 | m_event_loop->stop(); 30 | sem_destroy(&m_init_semaphore); 31 | sem_destroy(&m_start_semaphore); 32 | 33 | pthread_join(m_thread, NULL); 34 | 35 | if (m_event_loop) { 36 | delete m_event_loop; 37 | m_event_loop = NULL; 38 | } 39 | } 40 | 41 | 42 | void* IOThread::Main(void* arg) { 43 | IOThread* thread = static_cast (arg); 44 | 45 | thread->m_event_loop = new EventLoop(); 46 | thread->m_thread_id = getThreadId(); 47 | 48 | 49 | // 唤醒等待的线程 50 | sem_post(&thread->m_init_semaphore); 51 | 52 | // 让IO 线程等待,直到我们主动的启动 53 | 54 | DEBUGLOG("IOThread %d created, wait start semaphore", thread->m_thread_id); 55 | 56 | sem_wait(&thread->m_start_semaphore); 57 | DEBUGLOG("IOThread %d start loop ", thread->m_thread_id); 58 | thread->m_event_loop->loop(); 59 | 60 | DEBUGLOG("IOThread %d end loop ", thread->m_thread_id); 61 | 62 | return NULL; 63 | 64 | } 65 | 66 | 67 | EventLoop* IOThread::getEventLoop() { 68 | return m_event_loop; 69 | } 70 | 71 | void IOThread::start() { 72 | DEBUGLOG("Now invoke IOThread %d", m_thread_id); 73 | sem_post(&m_start_semaphore); 74 | } 75 | 76 | 77 | void IOThread::join() { 78 | pthread_join(m_thread, NULL); 79 | } 80 | 81 | 82 | 83 | } -------------------------------------------------------------------------------- /rocket/net/io_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_IO_THREAD_H 2 | #define ROCKET_NET_IO_THREAD_H 3 | 4 | #include 5 | #include 6 | #include "rocket/net/eventloop.h" 7 | 8 | namespace rocket { 9 | 10 | class IOThread { 11 | public: 12 | IOThread(); 13 | 14 | ~IOThread(); 15 | 16 | EventLoop* getEventLoop(); 17 | 18 | void start(); 19 | 20 | void join(); 21 | 22 | public: 23 | static void* Main(void* arg); 24 | 25 | 26 | private: 27 | pid_t m_thread_id {-1}; // 线程号 28 | pthread_t m_thread {0}; // 线程句柄 29 | 30 | EventLoop* m_event_loop {NULL}; // 当前 io 线程的 loop 对象 31 | 32 | sem_t m_init_semaphore; 33 | 34 | sem_t m_start_semaphore; 35 | 36 | }; 37 | 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /rocket/net/io_thread_group.cc: -------------------------------------------------------------------------------- 1 | #include "rocket/net/io_thread_group.h" 2 | #include "rocket/common/log.h" 3 | 4 | 5 | namespace rocket { 6 | 7 | 8 | IOThreadGroup::IOThreadGroup(int size) : m_size(size) { 9 | m_io_thread_groups.resize(size); 10 | for (size_t i = 0; (int)i < size; ++i) { 11 | m_io_thread_groups[i] = new IOThread(); 12 | } 13 | } 14 | 15 | IOThreadGroup::~IOThreadGroup() { 16 | 17 | } 18 | 19 | void IOThreadGroup::start() { 20 | for (size_t i = 0; i < m_io_thread_groups.size(); ++i) { 21 | m_io_thread_groups[i]->start(); 22 | } 23 | } 24 | 25 | void IOThreadGroup::join() { 26 | for (size_t i = 0; i < m_io_thread_groups.size(); ++i) { 27 | m_io_thread_groups[i]->join(); 28 | } 29 | } 30 | 31 | IOThread* IOThreadGroup::getIOThread() { 32 | if (m_index == (int)m_io_thread_groups.size() || m_index == -1) { 33 | m_index = 0; 34 | } 35 | return m_io_thread_groups[m_index++]; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /rocket/net/io_thread_group.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_IO_THREAD_GROUP_H 2 | #define ROCKET_NET_IO_THREAD_GROUP_H 3 | 4 | #include 5 | #include "rocket/common/log.h" 6 | #include "rocket/net/io_thread.h" 7 | 8 | 9 | 10 | namespace rocket { 11 | 12 | class IOThreadGroup { 13 | 14 | public: 15 | IOThreadGroup(int size); 16 | 17 | ~IOThreadGroup(); 18 | 19 | void start(); 20 | 21 | void join(); 22 | 23 | IOThread* getIOThread(); 24 | 25 | private: 26 | 27 | int m_size {0}; 28 | std::vector m_io_thread_groups; 29 | 30 | int m_index {0}; 31 | 32 | }; 33 | 34 | } 35 | 36 | 37 | #endif -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rocket/net/rpc/rpc_channel.h" 5 | #include "rocket/net/rpc/rpc_controller.h" 6 | #include "rocket/net/coder/tinypb_protocol.h" 7 | #include "rocket/net/tcp/tcp_client.h" 8 | #include "rocket/common/log.h" 9 | #include "rocket/common/msg_id_util.h" 10 | #include "rocket/common/error_code.h" 11 | #include "rocket/common/run_time.h" 12 | #include "rocket/net/timer_event.h" 13 | 14 | namespace rocket { 15 | 16 | RpcChannel::RpcChannel(NetAddr::s_ptr peer_addr) : m_peer_addr(peer_addr) { 17 | INFOLOG("RpcChannel"); 18 | } 19 | 20 | RpcChannel::~RpcChannel() { 21 | INFOLOG("~RpcChannel"); 22 | } 23 | 24 | 25 | void RpcChannel::callBack() { 26 | RpcController* my_controller = dynamic_cast(getController()); 27 | if (my_controller->Finished()) { 28 | return; 29 | } 30 | 31 | if (m_closure) { 32 | m_closure->Run(); 33 | if (my_controller) { 34 | my_controller->SetFinished(true); 35 | } 36 | } 37 | } 38 | 39 | void RpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method, 40 | google::protobuf::RpcController* controller, const google::protobuf::Message* request, 41 | google::protobuf::Message* response, google::protobuf::Closure* done) { 42 | 43 | 44 | std::shared_ptr req_protocol = std::make_shared(); 45 | 46 | RpcController* my_controller = dynamic_cast(controller); 47 | if (my_controller == NULL || request == NULL || response == NULL) { 48 | ERRORLOG("failed callmethod, RpcController convert error"); 49 | my_controller->SetError(ERROR_RPC_CHANNEL_INIT, "controller or request or response NULL"); 50 | callBack(); 51 | return; 52 | } 53 | 54 | if (m_peer_addr == nullptr) { 55 | ERRORLOG("failed get peer addr"); 56 | my_controller->SetError(ERROR_RPC_PEER_ADDR, "peer addr nullptr"); 57 | callBack(); 58 | return; 59 | } 60 | 61 | m_client = std::make_shared(m_peer_addr); 62 | 63 | if (my_controller->GetMsgId().empty()) { 64 | // 先从 runtime 里面取, 取不到再生成一个 65 | // 这样的目的是为了实现 msg_id 的透传,假设服务 A 调用了 B,那么同一个 msgid 可以在服务 A 和 B 之间串起来,方便日志追踪 66 | std::string msg_id = RunTime::GetRunTime()->m_msgid; 67 | if (!msg_id.empty()) { 68 | req_protocol->m_msg_id = msg_id; 69 | my_controller->SetMsgId(msg_id); 70 | } else { 71 | req_protocol->m_msg_id = MsgIDUtil::GenMsgID(); 72 | my_controller->SetMsgId(req_protocol->m_msg_id); 73 | } 74 | 75 | } else { 76 | // 如果 controller 指定了 msgno, 直接使用 77 | req_protocol->m_msg_id = my_controller->GetMsgId(); 78 | } 79 | 80 | req_protocol->m_method_name = method->full_name(); 81 | INFOLOG("%s | call method name [%s]", req_protocol->m_msg_id.c_str(), req_protocol->m_method_name.c_str()); 82 | 83 | if (!m_is_init) { 84 | std::string err_info = "RpcChannel not call init()"; 85 | my_controller->SetError(ERROR_RPC_CHANNEL_INIT, err_info); 86 | ERRORLOG("%s | %s, RpcChannel not init ", req_protocol->m_msg_id.c_str(), err_info.c_str()); 87 | callBack(); 88 | return; 89 | } 90 | 91 | // requeset 的序列化 92 | if (!request->SerializeToString(&(req_protocol->m_pb_data))) { 93 | std::string err_info = "failde to serialize"; 94 | my_controller->SetError(ERROR_FAILED_SERIALIZE, err_info); 95 | ERRORLOG("%s | %s, origin requeset [%s] ", req_protocol->m_msg_id.c_str(), err_info.c_str(), request->ShortDebugString().c_str()); 96 | callBack(); 97 | return; 98 | } 99 | 100 | s_ptr channel = shared_from_this(); 101 | 102 | TimerEvent::s_ptr timer_event = std::make_shared(my_controller->GetTimeout(), false, [my_controller, channel]() mutable { 103 | INFOLOG("%s | call rpc timeout arrive", my_controller->GetMsgId().c_str()); 104 | if (my_controller->Finished()) { 105 | channel.reset(); 106 | return; 107 | } 108 | 109 | my_controller->StartCancel(); 110 | my_controller->SetError(ERROR_RPC_CALL_TIMEOUT, "rpc call timeout " + std::to_string(my_controller->GetTimeout())); 111 | 112 | channel->callBack(); 113 | channel.reset(); 114 | }); 115 | 116 | m_client->addTimerEvent(timer_event); 117 | 118 | m_client->connect([req_protocol, this]() mutable { 119 | 120 | RpcController* my_controller = dynamic_cast(getController()); 121 | 122 | if (getTcpClient()->getConnectErrorCode() != 0) { 123 | my_controller->SetError(getTcpClient()->getConnectErrorCode(), getTcpClient()->getConnectErrorInfo()); 124 | ERRORLOG("%s | connect error, error coode[%d], error info[%s], peer addr[%s]", 125 | req_protocol->m_msg_id.c_str(), my_controller->GetErrorCode(), 126 | my_controller->GetErrorInfo().c_str(), getTcpClient()->getPeerAddr()->toString().c_str()); 127 | 128 | callBack(); 129 | 130 | return; 131 | } 132 | 133 | INFOLOG("%s | connect success, peer addr[%s], local addr[%s]", 134 | req_protocol->m_msg_id.c_str(), 135 | getTcpClient()->getPeerAddr()->toString().c_str(), 136 | getTcpClient()->getLocalAddr()->toString().c_str()); 137 | 138 | getTcpClient()->writeMessage(req_protocol, [req_protocol, this, my_controller](AbstractProtocol::s_ptr) mutable { 139 | INFOLOG("%s | send rpc request success. call method name[%s], peer addr[%s], local addr[%s]", 140 | req_protocol->m_msg_id.c_str(), req_protocol->m_method_name.c_str(), 141 | getTcpClient()->getPeerAddr()->toString().c_str(), getTcpClient()->getLocalAddr()->toString().c_str()); 142 | 143 | getTcpClient()->readMessage(req_protocol->m_msg_id, [this, my_controller](AbstractProtocol::s_ptr msg) mutable { 144 | std::shared_ptr rsp_protocol = std::dynamic_pointer_cast(msg); 145 | INFOLOG("%s | success get rpc response, call method name[%s], peer addr[%s], local addr[%s]", 146 | rsp_protocol->m_msg_id.c_str(), rsp_protocol->m_method_name.c_str(), 147 | getTcpClient()->getPeerAddr()->toString().c_str(), getTcpClient()->getLocalAddr()->toString().c_str()); 148 | 149 | if (!(getResponse()->ParseFromString(rsp_protocol->m_pb_data))){ 150 | ERRORLOG("%s | serialize error", rsp_protocol->m_msg_id.c_str()); 151 | my_controller->SetError(ERROR_FAILED_SERIALIZE, "serialize error"); 152 | callBack(); 153 | return; 154 | } 155 | 156 | if (rsp_protocol->m_err_code != 0) { 157 | ERRORLOG("%s | call rpc methood[%s] failed, error code[%d], error info[%s]", 158 | rsp_protocol->m_msg_id.c_str(), rsp_protocol->m_method_name.c_str(), 159 | rsp_protocol->m_err_code, rsp_protocol->m_err_info.c_str()); 160 | 161 | my_controller->SetError(rsp_protocol->m_err_code, rsp_protocol->m_err_info); 162 | callBack(); 163 | return; 164 | } 165 | 166 | INFOLOG("%s | call rpc success, call method name[%s], peer addr[%s], local addr[%s]", 167 | rsp_protocol->m_msg_id.c_str(), rsp_protocol->m_method_name.c_str(), 168 | getTcpClient()->getPeerAddr()->toString().c_str(), getTcpClient()->getLocalAddr()->toString().c_str()) 169 | 170 | callBack(); 171 | 172 | }); 173 | 174 | }); 175 | 176 | }); 177 | 178 | } 179 | 180 | 181 | void RpcChannel::Init(controller_s_ptr controller, message_s_ptr req, message_s_ptr res, closure_s_ptr done) { 182 | if (m_is_init) { 183 | return; 184 | } 185 | m_controller = controller; 186 | m_request = req; 187 | m_response = res; 188 | m_closure = done; 189 | m_is_init = true; 190 | } 191 | 192 | google::protobuf::RpcController* RpcChannel::getController() { 193 | return m_controller.get(); 194 | } 195 | 196 | google::protobuf::Message* RpcChannel::getRequest() { 197 | return m_request.get(); 198 | } 199 | 200 | google::protobuf::Message* RpcChannel::getResponse() { 201 | return m_response.get(); 202 | } 203 | 204 | google::protobuf::Closure* RpcChannel::getClosure() { 205 | return m_closure.get(); 206 | } 207 | 208 | 209 | TcpClient* RpcChannel::getTcpClient() { 210 | return m_client.get(); 211 | } 212 | 213 | 214 | NetAddr::s_ptr RpcChannel::FindAddr(const std::string& str) { 215 | if (IPNetAddr::CheckValid(str)) { 216 | return std::make_shared(str); 217 | } else { 218 | auto it = Config::GetGlobalConfig()->m_rpc_stubs.find(str); 219 | if (it != Config::GetGlobalConfig()->m_rpc_stubs.end()) { 220 | INFOLOG("find addr [%s] in global config of str[%s]", (*it).second.addr->toString().c_str(), str.c_str()); 221 | return (*it).second.addr; 222 | } else { 223 | INFOLOG("can not find addr in global config of str[%s]", str.c_str()); 224 | return nullptr; 225 | } 226 | } 227 | } 228 | 229 | 230 | } -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_channel.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_RPC_RPC_CHANNEL_H 2 | #define ROCKET_NET_RPC_RPC_CHANNEL_H 3 | 4 | #include 5 | #include 6 | #include "rocket/net/tcp/net_addr.h" 7 | #include "rocket/net/tcp/tcp_client.h" 8 | #include "rocket/net/timer_event.h" 9 | 10 | namespace rocket { 11 | 12 | 13 | #define NEWMESSAGE(type, var_name) \ 14 | std::shared_ptr var_name = std::make_shared(); \ 15 | 16 | #define NEWRPCCONTROLLER(var_name) \ 17 | std::shared_ptr var_name = std::make_shared(); \ 18 | 19 | #define NEWRPCCHANNEL(addr, var_name) \ 20 | std::shared_ptr var_name = std::make_shared(rocket::RpcChannel::FindAddr(addr)); \ 21 | 22 | #define CALLRPRC(addr, stub_name, method_name, controller, request, response, closure) \ 23 | { \ 24 | NEWRPCCHANNEL(addr, channel); \ 25 | channel->Init(controller, request, response, closure); \ 26 | stub_name(channel.get()).method_name(controller.get(), request.get(), response.get(), closure.get()); \ 27 | } \ 28 | 29 | 30 | 31 | class RpcChannel : public google::protobuf::RpcChannel, public std::enable_shared_from_this { 32 | 33 | public: 34 | typedef std::shared_ptr s_ptr; 35 | typedef std::shared_ptr controller_s_ptr; 36 | typedef std::shared_ptr message_s_ptr; 37 | typedef std::shared_ptr closure_s_ptr; 38 | 39 | public: 40 | // 获取 addr 41 | // 若 str 是 ip:port, 直接返回 42 | // 否则认为是 rpc 服务名,尝试从配置文件里面获取对应的 ip:port(后期会加上服务发现) 43 | static NetAddr::s_ptr FindAddr(const std::string& str); 44 | 45 | public: 46 | RpcChannel(NetAddr::s_ptr peer_addr); 47 | 48 | ~RpcChannel(); 49 | 50 | void Init(controller_s_ptr controller, message_s_ptr req, message_s_ptr res, closure_s_ptr done); 51 | 52 | void CallMethod(const google::protobuf::MethodDescriptor* method, 53 | google::protobuf::RpcController* controller, const google::protobuf::Message* request, 54 | google::protobuf::Message* response, google::protobuf::Closure* done); 55 | 56 | 57 | google::protobuf::RpcController* getController(); 58 | 59 | google::protobuf::Message* getRequest(); 60 | 61 | google::protobuf::Message* getResponse(); 62 | 63 | google::protobuf::Closure* getClosure(); 64 | 65 | TcpClient* getTcpClient(); 66 | 67 | private: 68 | void callBack(); 69 | 70 | private: 71 | NetAddr::s_ptr m_peer_addr {nullptr}; 72 | NetAddr::s_ptr m_local_addr {nullptr}; 73 | 74 | controller_s_ptr m_controller {nullptr}; 75 | message_s_ptr m_request {nullptr}; 76 | message_s_ptr m_response {nullptr}; 77 | closure_s_ptr m_closure {nullptr}; 78 | 79 | bool m_is_init {false}; 80 | 81 | TcpClient::s_ptr m_client {nullptr}; 82 | 83 | }; 84 | 85 | } 86 | 87 | 88 | #endif -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_closure.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_RPC_RPC_CLOSURE_H 2 | #define ROCKET_NET_RPC_RPC_CLOSURE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "rocket/common/run_time.h" 8 | #include "rocket/common/log.h" 9 | #include "rocket/common/exception.h" 10 | #include "rocket/net/rpc/rpc_interface.h" 11 | 12 | namespace rocket { 13 | 14 | class RpcClosure : public google::protobuf::Closure { 15 | public: 16 | typedef std::shared_ptr it_s_ptr; 17 | 18 | RpcClosure(it_s_ptr interface, std::function cb) : m_rpc_interface(interface), m_cb(cb) { 19 | INFOLOG("RpcClosure"); 20 | } 21 | 22 | ~RpcClosure() { 23 | INFOLOG("~RpcClosure"); 24 | } 25 | 26 | void Run() override { 27 | 28 | // 更新 runtime 的 RpcInterFace, 这里在执行 cb 的时候,都会以 RpcInterface 找到对应的接口,实现打印 app 日志等 29 | if (!m_rpc_interface) { 30 | RunTime::GetRunTime()->m_rpc_interface = m_rpc_interface.get(); 31 | } 32 | 33 | try { 34 | if (m_cb != nullptr) { 35 | m_cb(); 36 | } 37 | if (m_rpc_interface) { 38 | m_rpc_interface.reset(); 39 | } 40 | } catch (RocketException& e) { 41 | ERRORLOG("RocketException exception[%s], deal handle", e.what()); 42 | e.handle(); 43 | if (m_rpc_interface) { 44 | m_rpc_interface->setError(e.errorCode(), e.errorInfo()); 45 | m_rpc_interface.reset(); 46 | } 47 | } catch (std::exception& e) { 48 | ERRORLOG("std::exception[%s]", e.what()); 49 | if (m_rpc_interface) { 50 | m_rpc_interface->setError(-1, "unkonwn std::exception"); 51 | m_rpc_interface.reset(); 52 | } 53 | } catch (...) { 54 | ERRORLOG("Unkonwn exception"); 55 | if (m_rpc_interface) { 56 | m_rpc_interface->setError(-1, "unkonwn exception"); 57 | m_rpc_interface.reset(); 58 | } 59 | } 60 | 61 | } 62 | 63 | private: 64 | it_s_ptr m_rpc_interface {nullptr}; 65 | std::function m_cb {nullptr}; 66 | 67 | }; 68 | 69 | } 70 | #endif -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_controller.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "rocket/net/rpc/rpc_controller.h" 3 | 4 | namespace rocket { 5 | 6 | void RpcController::Reset() { 7 | m_error_code = 0; 8 | m_error_info = ""; 9 | m_msg_id = ""; 10 | m_is_failed = false; 11 | m_is_cancled = false; 12 | m_is_finished = false; 13 | m_local_addr = nullptr; 14 | m_peer_addr = nullptr; 15 | m_timeout = 1000; // ms 16 | } 17 | 18 | bool RpcController::Failed() const { 19 | return m_is_failed; 20 | } 21 | 22 | std::string RpcController::ErrorText() const { 23 | return m_error_info; 24 | } 25 | 26 | void RpcController::StartCancel() { 27 | m_is_cancled = true; 28 | m_is_failed = true; 29 | SetFinished(true); 30 | } 31 | 32 | void RpcController::SetFailed(const std::string& reason) { 33 | m_error_info = reason; 34 | m_is_failed = true; 35 | } 36 | 37 | bool RpcController::IsCanceled() const { 38 | return m_is_cancled; 39 | } 40 | 41 | void RpcController::NotifyOnCancel(google::protobuf::Closure* callback) { 42 | 43 | } 44 | 45 | 46 | void RpcController::SetError(int32_t error_code, const std::string error_info) { 47 | m_error_code = error_code; 48 | m_error_info = error_info; 49 | m_is_failed = true; 50 | } 51 | 52 | int32_t RpcController::GetErrorCode() { 53 | return m_error_code; 54 | } 55 | 56 | std::string RpcController::GetErrorInfo() { 57 | return m_error_info; 58 | } 59 | 60 | void RpcController::SetMsgId(const std::string& msg_id) { 61 | m_msg_id = msg_id; 62 | } 63 | 64 | std::string RpcController::GetMsgId() { 65 | return m_msg_id; 66 | } 67 | 68 | void RpcController::SetLocalAddr(NetAddr::s_ptr addr) { 69 | m_local_addr = addr; 70 | } 71 | 72 | void RpcController::SetPeerAddr(NetAddr::s_ptr addr) { 73 | m_peer_addr = addr; 74 | } 75 | 76 | NetAddr::s_ptr RpcController::GetLocalAddr() { 77 | return m_local_addr; 78 | } 79 | 80 | NetAddr::s_ptr RpcController::GetPeerAddr() { 81 | return m_peer_addr; 82 | } 83 | 84 | void RpcController::SetTimeout(int timeout) { 85 | m_timeout = timeout; 86 | } 87 | 88 | int RpcController::GetTimeout() { 89 | return m_timeout; 90 | } 91 | 92 | bool RpcController::Finished() { 93 | return m_is_finished; 94 | } 95 | 96 | void RpcController::SetFinished(bool value) { 97 | m_is_finished = value; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKER_NET_RPC_RPC_CONTROLLER_H 2 | #define ROCKER_NET_RPC_RPC_CONTROLLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rocket/net/tcp/net_addr.h" 9 | #include "rocket/common/log.h" 10 | 11 | namespace rocket { 12 | 13 | class RpcController : public google::protobuf::RpcController { 14 | 15 | public: 16 | RpcController() { INFOLOG("RpcController"); } 17 | ~RpcController() { INFOLOG("~RpcController"); } 18 | 19 | void Reset(); 20 | 21 | bool Failed() const; 22 | 23 | std::string ErrorText() const; 24 | 25 | void StartCancel(); 26 | 27 | void SetFailed(const std::string& reason); 28 | 29 | bool IsCanceled() const; 30 | 31 | void NotifyOnCancel(google::protobuf::Closure* callback); 32 | 33 | void SetError(int32_t error_code, const std::string error_info); 34 | 35 | int32_t GetErrorCode(); 36 | 37 | std::string GetErrorInfo(); 38 | 39 | void SetMsgId(const std::string& msg_id); 40 | 41 | std::string GetMsgId(); 42 | 43 | void SetLocalAddr(NetAddr::s_ptr addr); 44 | 45 | void SetPeerAddr(NetAddr::s_ptr addr); 46 | 47 | NetAddr::s_ptr GetLocalAddr(); 48 | 49 | NetAddr::s_ptr GetPeerAddr(); 50 | 51 | void SetTimeout(int timeout); 52 | 53 | int GetTimeout(); 54 | 55 | bool Finished(); 56 | 57 | void SetFinished(bool value); 58 | 59 | private: 60 | int32_t m_error_code {0}; 61 | std::string m_error_info; 62 | std::string m_msg_id; 63 | 64 | bool m_is_failed {false}; 65 | bool m_is_cancled {false}; 66 | bool m_is_finished {false}; 67 | 68 | NetAddr::s_ptr m_local_addr; 69 | NetAddr::s_ptr m_peer_addr; 70 | 71 | int m_timeout {1000}; // ms 72 | 73 | }; 74 | 75 | } 76 | 77 | 78 | #endif -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_dispatcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "rocket/net/rpc/rpc_dispatcher.h" 6 | #include "rocket/net/coder/tinypb_protocol.h" 7 | #include "rocket/common/log.h" 8 | #include "rocket/common/error_code.h" 9 | #include "rocket/net/rpc/rpc_controller.h" 10 | #include "rocket/net/rpc/rpc_closure.h" 11 | #include "rocket/net/tcp/net_addr.h" 12 | #include "rocket/net/tcp/tcp_connection.h" 13 | #include "rocket/common/run_time.h" 14 | 15 | namespace rocket { 16 | 17 | #define DELETE_RESOURCE(XX) \ 18 | if (XX != NULL) { \ 19 | delete XX; \ 20 | XX = NULL; \ 21 | } \ 22 | 23 | static RpcDispatcher* g_rpc_dispatcher = NULL; 24 | 25 | RpcDispatcher* RpcDispatcher::GetRpcDispatcher() { 26 | if (g_rpc_dispatcher != NULL) { 27 | return g_rpc_dispatcher; 28 | } 29 | g_rpc_dispatcher = new RpcDispatcher; 30 | return g_rpc_dispatcher; 31 | } 32 | 33 | 34 | void RpcDispatcher::dispatch(AbstractProtocol::s_ptr request, AbstractProtocol::s_ptr response, TcpConnection* connection) { 35 | 36 | std::shared_ptr req_protocol = std::dynamic_pointer_cast(request); 37 | std::shared_ptr rsp_protocol = std::dynamic_pointer_cast(response); 38 | 39 | std::string method_full_name = req_protocol->m_method_name; 40 | std::string service_name; 41 | std::string method_name; 42 | 43 | rsp_protocol->m_msg_id = req_protocol->m_msg_id; 44 | rsp_protocol->m_method_name = req_protocol->m_method_name; 45 | 46 | if (!parseServiceFullName(method_full_name, service_name, method_name)) { 47 | setTinyPBError(rsp_protocol, ERROR_PARSE_SERVICE_NAME, "parse service name error"); 48 | return; 49 | } 50 | 51 | auto it = m_service_map.find(service_name); 52 | if (it == m_service_map.end()) { 53 | ERRORLOG("%s | sericve neame[%s] not found", req_protocol->m_msg_id.c_str(), service_name.c_str()); 54 | setTinyPBError(rsp_protocol, ERROR_SERVICE_NOT_FOUND, "service not found"); 55 | return; 56 | } 57 | 58 | service_s_ptr service = (*it).second; 59 | 60 | const google::protobuf::MethodDescriptor* method = service->GetDescriptor()->FindMethodByName(method_name); 61 | if (method == NULL) { 62 | ERRORLOG("%s | method neame[%s] not found in service[%s]", req_protocol->m_msg_id.c_str(), method_name.c_str(), service_name.c_str()); 63 | setTinyPBError(rsp_protocol, ERROR_SERVICE_NOT_FOUND, "method not found"); 64 | return; 65 | } 66 | 67 | google::protobuf::Message* req_msg = service->GetRequestPrototype(method).New(); 68 | 69 | // 反序列化,将 pb_data 反序列化为 req_msg 70 | if (!req_msg->ParseFromString(req_protocol->m_pb_data)) { 71 | ERRORLOG("%s | deserilize error", req_protocol->m_msg_id.c_str(), method_name.c_str(), service_name.c_str()); 72 | setTinyPBError(rsp_protocol, ERROR_FAILED_DESERIALIZE, "deserilize error"); 73 | DELETE_RESOURCE(req_msg); 74 | return; 75 | } 76 | 77 | INFOLOG("%s | get rpc request[%s]", req_protocol->m_msg_id.c_str(), req_msg->ShortDebugString().c_str()); 78 | 79 | google::protobuf::Message* rsp_msg = service->GetResponsePrototype(method).New(); 80 | 81 | RpcController* rpc_controller = new RpcController(); 82 | rpc_controller->SetLocalAddr(connection->getLocalAddr()); 83 | rpc_controller->SetPeerAddr(connection->getPeerAddr()); 84 | rpc_controller->SetMsgId(req_protocol->m_msg_id); 85 | 86 | RunTime::GetRunTime()->m_msgid = req_protocol->m_msg_id; 87 | RunTime::GetRunTime()->m_method_name = method_name; 88 | 89 | RpcClosure* closure = new RpcClosure(nullptr, [req_msg, rsp_msg, req_protocol, rsp_protocol, connection, rpc_controller, this]() mutable { 90 | if (!rsp_msg->SerializeToString(&(rsp_protocol->m_pb_data))) { 91 | ERRORLOG("%s | serilize error, origin message [%s]", req_protocol->m_msg_id.c_str(), rsp_msg->ShortDebugString().c_str()); 92 | setTinyPBError(rsp_protocol, ERROR_FAILED_SERIALIZE, "serilize error"); 93 | } else { 94 | rsp_protocol->m_err_code = 0; 95 | rsp_protocol->m_err_info = ""; 96 | INFOLOG("%s | dispatch success, requesut[%s], response[%s]", req_protocol->m_msg_id.c_str(), req_msg->ShortDebugString().c_str(), rsp_msg->ShortDebugString().c_str()); 97 | } 98 | 99 | std::vector replay_messages; 100 | replay_messages.emplace_back(rsp_protocol); 101 | connection->reply(replay_messages); 102 | 103 | }); 104 | 105 | service->CallMethod(method, rpc_controller, req_msg, rsp_msg, closure); 106 | 107 | } 108 | 109 | 110 | bool RpcDispatcher::parseServiceFullName(const std::string& full_name, std::string& service_name, std::string& method_name) { 111 | if (full_name.empty()) { 112 | ERRORLOG("full name empty"); 113 | return false; 114 | } 115 | size_t i = full_name.find_first_of("."); 116 | if (i == full_name.npos) { 117 | ERRORLOG("not find . in full name [%s]", full_name.c_str()); 118 | return false; 119 | } 120 | service_name = full_name.substr(0, i); 121 | method_name = full_name.substr(i + 1, full_name.length() - i - 1); 122 | 123 | INFOLOG("parse sericve_name[%s] and method_name[%s] from full name [%s]", service_name.c_str(), method_name.c_str(),full_name.c_str()); 124 | 125 | return true; 126 | 127 | } 128 | 129 | 130 | void RpcDispatcher::registerService(service_s_ptr service) { 131 | std::string service_name = service->GetDescriptor()->full_name(); 132 | m_service_map[service_name] = service; 133 | 134 | } 135 | 136 | void RpcDispatcher::setTinyPBError(std::shared_ptr msg, int32_t err_code, const std::string err_info) { 137 | msg->m_err_code = err_code; 138 | msg->m_err_info = err_info; 139 | msg->m_err_info_len = err_info.length(); 140 | } 141 | 142 | } -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_RPC_RPC_DISPATCHER_H 2 | #define ROCKET_NET_RPC_RPC_DISPATCHER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rocket/net/coder/abstract_protocol.h" 9 | #include "rocket/net/coder/tinypb_protocol.h" 10 | 11 | namespace rocket { 12 | 13 | class TcpConnection; 14 | 15 | class RpcDispatcher { 16 | 17 | public: 18 | 19 | static RpcDispatcher* GetRpcDispatcher(); 20 | 21 | public: 22 | 23 | typedef std::shared_ptr service_s_ptr; 24 | 25 | void dispatch(AbstractProtocol::s_ptr request, AbstractProtocol::s_ptr response, TcpConnection* connection); 26 | 27 | void registerService(service_s_ptr service); 28 | 29 | void setTinyPBError(std::shared_ptr msg, int32_t err_code, const std::string err_info); 30 | 31 | private: 32 | bool parseServiceFullName(const std::string& full_name, std::string& service_name, std::string& method_name); 33 | 34 | private: 35 | std::map m_service_map; 36 | }; 37 | 38 | 39 | } 40 | 41 | #endif -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_interface.cc: -------------------------------------------------------------------------------- 1 | #include "rocket/common/log.h" 2 | #include "rocket/net/rpc/rpc_closure.h" 3 | #include "rocket/net/rpc/rpc_closure.h" 4 | #include "rocket/net/rpc/rpc_controller.h" 5 | #include "rocket/net/rpc/rpc_interface.h" 6 | 7 | namespace rocket { 8 | 9 | RpcInterface::RpcInterface(const google::protobuf::Message* req, google::protobuf::Message* rsp, RpcClosure* done, RpcController* controller) 10 | : m_req_base(req), m_rsp_base(rsp), m_done(done) , m_controller(controller) { 11 | INFOLOG("RpcInterface"); 12 | } 13 | 14 | RpcInterface::~RpcInterface() { 15 | INFOLOG("~RpcInterface"); 16 | 17 | reply(); 18 | 19 | destroy(); 20 | 21 | } 22 | 23 | void RpcInterface::reply() { 24 | // reply to client 25 | // you should call is when you wan to set response back 26 | // it means this rpc method done 27 | if (m_done) { 28 | m_done->Run(); 29 | } 30 | 31 | } 32 | 33 | std::shared_ptr RpcInterface::newRpcClosure(std::function& cb) { 34 | return std::make_shared(shared_from_this(), cb); 35 | } 36 | 37 | 38 | void RpcInterface::destroy() { 39 | if (m_req_base) { 40 | delete m_req_base; 41 | m_req_base = NULL; 42 | } 43 | 44 | if (m_rsp_base) { 45 | delete m_rsp_base; 46 | m_rsp_base = NULL; 47 | } 48 | 49 | if (m_done) { 50 | delete m_done; 51 | m_done = NULL; 52 | } 53 | 54 | if (m_controller) { 55 | delete m_controller; 56 | m_controller = NULL; 57 | } 58 | 59 | } 60 | 61 | 62 | } -------------------------------------------------------------------------------- /rocket/net/rpc/rpc_interface.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_RPC_RPC_INTERFACE_H 2 | #define ROCKET_NET_RPC_RPC_INTERFACE_H 3 | 4 | #include 5 | #include 6 | #include "rocket/net/rpc/rpc_controller.h" 7 | 8 | namespace rocket { 9 | 10 | class RpcClosure; 11 | 12 | /* 13 | * Rpc Interface Base Class 14 | * All interface should extend this abstract class 15 | */ 16 | 17 | class RpcInterface : public std::enable_shared_from_this { 18 | public: 19 | 20 | RpcInterface(const google::protobuf::Message* req, google::protobuf::Message* rsp, RpcClosure* done, RpcController* controller); 21 | 22 | virtual ~RpcInterface(); 23 | 24 | // reply to client 25 | void reply(); 26 | 27 | // free resourse 28 | void destroy(); 29 | 30 | // alloc a closure object which handle by this interface 31 | std::shared_ptr newRpcClosure(std::function& cb); 32 | 33 | // core business deal method 34 | virtual void run() = 0; 35 | 36 | // set error code and error into to response message 37 | virtual void setError(int code, const std::string& err_info) = 0; 38 | 39 | protected: 40 | 41 | const google::protobuf::Message* m_req_base {NULL}; 42 | 43 | google::protobuf::Message* m_rsp_base {NULL}; 44 | 45 | RpcClosure* m_done {NULL}; // callback 46 | 47 | RpcController* m_controller {NULL}; 48 | 49 | 50 | }; 51 | 52 | 53 | } 54 | 55 | 56 | #endif -------------------------------------------------------------------------------- /rocket/net/tcp/net_addr.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rocket/common/log.h" 3 | #include "rocket/net/tcp/net_addr.h" 4 | 5 | 6 | namespace rocket { 7 | 8 | 9 | bool IPNetAddr::CheckValid(const std::string& addr) { 10 | size_t i = addr.find_first_of(":"); 11 | if (i == addr.npos) { 12 | return false; 13 | } 14 | std::string ip = addr.substr(0, i); 15 | std::string port = addr.substr(i + 1, addr.size() - i - 1); 16 | if (ip.empty() || port.empty()) { 17 | return false; 18 | } 19 | 20 | int iport = std::atoi(port.c_str()); 21 | if (iport <= 0 || iport > 65536) { 22 | return false; 23 | } 24 | 25 | return true; 26 | 27 | } 28 | 29 | IPNetAddr::IPNetAddr(const std::string& ip, uint16_t port) : m_ip(ip), m_port(port) { 30 | memset(&m_addr, 0, sizeof(m_addr)); 31 | 32 | m_addr.sin_family = AF_INET; 33 | m_addr.sin_addr.s_addr = inet_addr(m_ip.c_str()); 34 | m_addr.sin_port = htons(m_port); 35 | } 36 | 37 | IPNetAddr::IPNetAddr(const std::string& addr) { 38 | size_t i = addr.find_first_of(":"); 39 | if (i == addr.npos) { 40 | ERRORLOG("invalid ipv4 addr %s", addr.c_str()); 41 | return; 42 | } 43 | m_ip = addr.substr(0, i); 44 | m_port = std::atoi(addr.substr(i + 1, addr.size() - i - 1).c_str()); 45 | 46 | memset(&m_addr, 0, sizeof(m_addr)); 47 | m_addr.sin_family = AF_INET; 48 | m_addr.sin_addr.s_addr = inet_addr(m_ip.c_str()); 49 | m_addr.sin_port = htons(m_port); 50 | 51 | } 52 | 53 | IPNetAddr::IPNetAddr(sockaddr_in addr) : m_addr(addr) { 54 | m_ip = std::string(inet_ntoa(m_addr.sin_addr)); 55 | m_port = ntohs(m_addr.sin_port); 56 | 57 | } 58 | 59 | sockaddr* IPNetAddr::getSockAddr() { 60 | return reinterpret_cast(&m_addr); 61 | } 62 | 63 | socklen_t IPNetAddr::getSockLen() { 64 | return sizeof(m_addr); 65 | } 66 | 67 | int IPNetAddr::getFamily() { 68 | return AF_INET; 69 | } 70 | 71 | std::string IPNetAddr::toString() { 72 | std::string re; 73 | re = m_ip + ":" + std::to_string(m_port); 74 | return re; 75 | } 76 | 77 | bool IPNetAddr::checkValid() { 78 | if (m_ip.empty()) { 79 | return false; 80 | } 81 | 82 | if (m_port < 0 || m_port > 65536) { 83 | return false; 84 | } 85 | 86 | if (inet_addr(m_ip.c_str()) == INADDR_NONE) { 87 | return false; 88 | } 89 | return true; 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /rocket/net/tcp/net_addr.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_NET_ADDR_H 2 | #define ROCKET_NET_TCP_NET_ADDR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace rocket { 10 | 11 | class NetAddr { 12 | public: 13 | typedef std::shared_ptr s_ptr; 14 | 15 | virtual sockaddr* getSockAddr() = 0; 16 | 17 | virtual socklen_t getSockLen() = 0; 18 | 19 | virtual int getFamily() = 0; 20 | 21 | virtual std::string toString() = 0; 22 | 23 | virtual bool checkValid() = 0; 24 | 25 | }; 26 | 27 | 28 | class IPNetAddr : public NetAddr { 29 | 30 | public: 31 | static bool CheckValid(const std::string& addr); 32 | 33 | public: 34 | 35 | IPNetAddr(const std::string& ip, uint16_t port); 36 | 37 | IPNetAddr(const std::string& addr); 38 | 39 | IPNetAddr(sockaddr_in addr); 40 | 41 | sockaddr* getSockAddr(); 42 | 43 | socklen_t getSockLen(); 44 | 45 | int getFamily(); 46 | 47 | std::string toString(); 48 | 49 | bool checkValid(); 50 | 51 | private: 52 | std::string m_ip; 53 | uint16_t m_port {0}; 54 | 55 | sockaddr_in m_addr; 56 | 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_acceptor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rocket/common/log.h" 6 | #include "rocket/net/tcp/net_addr.h" 7 | #include "rocket/net/tcp/tcp_acceptor.h" 8 | 9 | 10 | namespace rocket { 11 | 12 | TcpAcceptor::TcpAcceptor(NetAddr::s_ptr local_addr) : m_local_addr(local_addr) { 13 | if (!local_addr->checkValid()) { 14 | ERRORLOG("invalid local addr %s", local_addr->toString().c_str()); 15 | exit(0); 16 | } 17 | 18 | m_family = m_local_addr->getFamily(); 19 | 20 | m_listenfd = socket(m_family, SOCK_STREAM, 0); 21 | 22 | if (m_listenfd < 0) { 23 | ERRORLOG("invalid listenfd %d", m_listenfd); 24 | exit(0); 25 | } 26 | 27 | int val = 1; 28 | if (setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0) { 29 | ERRORLOG("setsockopt REUSEADDR error, errno=%d, error=%s", errno, strerror(errno)); 30 | } 31 | 32 | socklen_t len = m_local_addr->getSockLen(); 33 | if(bind(m_listenfd, m_local_addr->getSockAddr(), len) != 0) { 34 | ERRORLOG("bind error, errno=%d, error=%s", errno, strerror(errno)); 35 | exit(0); 36 | } 37 | 38 | if(listen(m_listenfd, 1000) != 0) { 39 | ERRORLOG("listen error, errno=%d, error=%s", errno, strerror(errno)); 40 | exit(0); 41 | } 42 | } 43 | 44 | TcpAcceptor::~TcpAcceptor() { 45 | } 46 | 47 | 48 | int TcpAcceptor::getListenFd() { 49 | return m_listenfd; 50 | } 51 | 52 | 53 | std::pair TcpAcceptor::accept() { 54 | if (m_family == AF_INET) { 55 | sockaddr_in client_addr; 56 | memset(&client_addr, 0, sizeof(client_addr)); 57 | socklen_t clien_addr_len = sizeof(clien_addr_len); 58 | 59 | int client_fd = ::accept(m_listenfd, reinterpret_cast(&client_addr), &clien_addr_len); 60 | if (client_fd < 0) { 61 | ERRORLOG("accept error, errno=%d, error=%s", errno, strerror(errno)); 62 | } 63 | IPNetAddr::s_ptr peer_addr = std::make_shared(client_addr); 64 | INFOLOG("A client have accpeted succ, peer addr [%s]", peer_addr->toString().c_str()); 65 | 66 | return std::make_pair(client_fd, peer_addr); 67 | } else { 68 | // ... 69 | return std::make_pair(-1, nullptr); 70 | } 71 | 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_acceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_TCP_ACCEPTOR_H 2 | #define ROCKET_NET_TCP_TCP_ACCEPTOR_H 3 | 4 | #include 5 | #include "rocket/net/tcp/net_addr.h" 6 | 7 | namespace rocket { 8 | 9 | class TcpAcceptor { 10 | public: 11 | typedef std::shared_ptr s_ptr; 12 | 13 | TcpAcceptor(NetAddr::s_ptr local_addr); 14 | 15 | ~TcpAcceptor(); 16 | 17 | std::pair accept(); 18 | 19 | int getListenFd(); 20 | 21 | private: 22 | NetAddr::s_ptr m_local_addr; // 服务端监听的地址,addr -> ip:port 23 | 24 | int m_family {-1}; 25 | 26 | int m_listenfd {-1}; // 监听套接字 27 | 28 | }; 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_buffer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rocket/common/log.h" 4 | #include "rocket/net/tcp/tcp_buffer.h" 5 | 6 | namespace rocket { 7 | 8 | 9 | 10 | TcpBuffer::TcpBuffer(int size) : m_size(size) { 11 | m_buffer.resize(size); 12 | } 13 | 14 | TcpBuffer::~TcpBuffer() { 15 | 16 | } 17 | 18 | // 返回可读字节数 19 | int TcpBuffer::readAble() { 20 | return m_write_index - m_read_index; 21 | } 22 | 23 | // 返回可写的字节数 24 | int TcpBuffer::writeAble() { 25 | return m_buffer.size() - m_write_index; 26 | } 27 | 28 | int TcpBuffer::readIndex() { 29 | return m_read_index; 30 | } 31 | 32 | int TcpBuffer::writeIndex() { 33 | return m_write_index; 34 | } 35 | 36 | void TcpBuffer::writeToBuffer(const char* buf, int size) { 37 | if (size > writeAble()) { 38 | // 调整 buffer 的大小,扩容 39 | int new_size = (int)(1.5 * (m_write_index + size)); 40 | resizeBuffer(new_size); 41 | } 42 | memcpy(&m_buffer[m_write_index], buf, size); 43 | m_write_index += size; 44 | } 45 | 46 | 47 | void TcpBuffer::readFromBuffer(std::vector& re, int size) { 48 | if (readAble() == 0) { 49 | return; 50 | } 51 | 52 | int read_size = readAble() > size ? size : readAble(); 53 | 54 | std::vector tmp(read_size); 55 | memcpy(&tmp[0], &m_buffer[m_read_index], read_size); 56 | 57 | re.swap(tmp); 58 | m_read_index += read_size; 59 | 60 | adjustBuffer(); 61 | } 62 | 63 | 64 | void TcpBuffer::resizeBuffer(int new_size) { 65 | std::vector tmp(new_size); 66 | int count = std::min(new_size, readAble()); 67 | 68 | memcpy(&tmp[0], &m_buffer[m_read_index], count); 69 | m_buffer.swap(tmp); 70 | 71 | m_read_index = 0; 72 | m_write_index = m_read_index + count; 73 | 74 | } 75 | 76 | 77 | void TcpBuffer::adjustBuffer() { 78 | if (m_read_index < int(m_buffer.size() / 3)) { 79 | return; 80 | } 81 | std::vector buffer(m_buffer.size()); 82 | int count = readAble(); 83 | 84 | memcpy(&buffer[0], &m_buffer[m_read_index], count); 85 | m_buffer.swap(buffer); 86 | m_read_index = 0; 87 | m_write_index = m_read_index + count; 88 | 89 | buffer.clear(); 90 | } 91 | 92 | void TcpBuffer::moveReadIndex(int size) { 93 | size_t j = m_read_index + size; 94 | if (j >= m_buffer.size()) { 95 | ERRORLOG("moveReadIndex error, invalid size %d, old_read_index %d, buffer size %d", size, m_read_index, m_buffer.size()); 96 | return; 97 | } 98 | m_read_index = j; 99 | adjustBuffer(); 100 | } 101 | 102 | void TcpBuffer::moveWriteIndex(int size) { 103 | size_t j = m_write_index + size; 104 | if (j >= m_buffer.size()) { 105 | ERRORLOG("moveWriteIndex error, invalid size %d, old_read_index %d, buffer size %d", size, m_read_index, m_buffer.size()); 106 | return; 107 | } 108 | m_write_index = j; 109 | adjustBuffer(); 110 | 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_TCP_BUFFER_H 2 | #define ROCKET_NET_TCP_TCP_BUFFER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace rocket { 8 | 9 | class TcpBuffer { 10 | 11 | public: 12 | 13 | typedef std::shared_ptr s_ptr; 14 | 15 | TcpBuffer(int size); 16 | 17 | ~TcpBuffer(); 18 | 19 | // 返回可读字节数 20 | int readAble(); 21 | 22 | // 返回可写的字节数 23 | int writeAble(); 24 | 25 | int readIndex(); 26 | 27 | int writeIndex(); 28 | 29 | void writeToBuffer(const char* buf, int size); 30 | 31 | void readFromBuffer(std::vector& re, int size); 32 | 33 | void resizeBuffer(int new_size); 34 | 35 | void adjustBuffer(); 36 | 37 | void moveReadIndex(int size); 38 | 39 | void moveWriteIndex(int size); 40 | 41 | private: 42 | int m_read_index {0}; 43 | int m_write_index {0}; 44 | int m_size {0}; 45 | 46 | public: 47 | std::vector m_buffer; 48 | 49 | }; 50 | 51 | 52 | } 53 | 54 | 55 | #endif -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "rocket/common/log.h" 5 | #include "rocket/net/tcp/tcp_client.h" 6 | #include "rocket/net/eventloop.h" 7 | #include "rocket/net/fd_event_group.h" 8 | #include "rocket/common/error_code.h" 9 | #include "rocket/net/tcp/net_addr.h" 10 | 11 | namespace rocket { 12 | 13 | TcpClient::TcpClient(NetAddr::s_ptr peer_addr) : m_peer_addr(peer_addr) { 14 | m_event_loop = EventLoop::GetCurrentEventLoop(); 15 | m_fd = socket(peer_addr->getFamily(), SOCK_STREAM, 0); 16 | 17 | if (m_fd < 0) { 18 | ERRORLOG("TcpClient::TcpClient() error, failed to create fd"); 19 | return; 20 | } 21 | 22 | m_fd_event = FdEventGroup::GetFdEventGroup()->getFdEvent(m_fd); 23 | m_fd_event->setNonBlock(); 24 | 25 | m_connection = std::make_shared(m_event_loop, m_fd, 128, peer_addr, nullptr, TcpConnectionByClient); 26 | m_connection->setConnectionType(TcpConnectionByClient); 27 | 28 | } 29 | 30 | TcpClient::~TcpClient() { 31 | DEBUGLOG("TcpClient::~TcpClient()"); 32 | if (m_fd > 0) { 33 | close(m_fd); 34 | } 35 | } 36 | 37 | // 异步的进行 conenct 38 | // 如果connect 成功,done 会被执行 39 | void TcpClient::connect(std::function done) { 40 | int rt = ::connect(m_fd, m_peer_addr->getSockAddr(), m_peer_addr->getSockLen()); 41 | if (rt == 0) { 42 | DEBUGLOG("connect [%s] sussess", m_peer_addr->toString().c_str()); 43 | m_connection->setState(Connected); 44 | initLocalAddr(); 45 | if (done) { 46 | done(); 47 | } 48 | } else if (rt == -1) { 49 | if (errno == EINPROGRESS) { 50 | // epoll 监听可写事件,然后判断错误码 51 | m_fd_event->listen(FdEvent::OUT_EVENT, 52 | [this, done]() { 53 | int rt = ::connect(m_fd, m_peer_addr->getSockAddr(), m_peer_addr->getSockLen()); 54 | if ((rt < 0 && errno == EISCONN) || (rt == 0)) { 55 | DEBUGLOG("connect [%s] sussess", m_peer_addr->toString().c_str()); 56 | initLocalAddr(); 57 | m_connection->setState(Connected); 58 | } else { 59 | if (errno == ECONNREFUSED) { 60 | m_connect_error_code = ERROR_PEER_CLOSED; 61 | m_connect_error_info = "connect refused, sys error = " + std::string(strerror(errno)); 62 | } else { 63 | m_connect_error_code = ERROR_FAILED_CONNECT; 64 | m_connect_error_info = "connect unkonwn error, sys error = " + std::string(strerror(errno)); 65 | } 66 | ERRORLOG("connect errror, errno=%d, error=%s", errno, strerror(errno)); 67 | close(m_fd); 68 | m_fd = socket(m_peer_addr->getFamily(), SOCK_STREAM, 0); 69 | } 70 | 71 | // 连接完后需要去掉可写事件的监听,不然会一直触发 72 | m_event_loop->deleteEpollEvent(m_fd_event); 73 | DEBUGLOG("now begin to done"); 74 | // 如果连接完成,才会执行回调函数 75 | if (done) { 76 | done(); 77 | } 78 | } 79 | ); 80 | m_event_loop->addEpollEvent(m_fd_event); 81 | 82 | if (!m_event_loop->isLooping()) { 83 | m_event_loop->loop(); 84 | } 85 | } else { 86 | ERRORLOG("connect errror, errno=%d, error=%s", errno, strerror(errno)); 87 | m_connect_error_code = ERROR_FAILED_CONNECT; 88 | m_connect_error_info = "connect error, sys error = " + std::string(strerror(errno)); 89 | if (done) { 90 | done(); 91 | } 92 | } 93 | } 94 | 95 | } 96 | 97 | 98 | void TcpClient::stop() { 99 | if (m_event_loop->isLooping()) { 100 | m_event_loop->stop(); 101 | } 102 | } 103 | 104 | // 异步的发送 message 105 | // 如果发送 message 成功,会调用 done 函数, 函数的入参就是 message 对象 106 | void TcpClient::writeMessage(AbstractProtocol::s_ptr message, std::function done) { 107 | // 1. 把 message 对象写入到 Connection 的 buffer, done 也写入 108 | // 2. 启动 connection 可写事件 109 | m_connection->pushSendMessage(message, done); 110 | m_connection->listenWrite(); 111 | 112 | } 113 | 114 | 115 | // 异步的读取 message 116 | // 如果读取 message 成功,会调用 done 函数, 函数的入参就是 message 对象 117 | void TcpClient::readMessage(const std::string& msg_id, std::function done) { 118 | // 1. 监听可读事件 119 | // 2. 从 buffer 里 decode 得到 message 对象, 判断是否 msg_id 相等,相等则读成功,执行其回调 120 | m_connection->pushReadMessage(msg_id, done); 121 | m_connection->listenRead(); 122 | } 123 | 124 | int TcpClient::getConnectErrorCode() { 125 | return m_connect_error_code; 126 | } 127 | 128 | std::string TcpClient::getConnectErrorInfo() { 129 | return m_connect_error_info; 130 | 131 | } 132 | 133 | NetAddr::s_ptr TcpClient::getPeerAddr() { 134 | return m_peer_addr; 135 | } 136 | 137 | NetAddr::s_ptr TcpClient::getLocalAddr() { 138 | return m_local_addr; 139 | } 140 | 141 | void TcpClient::initLocalAddr() { 142 | sockaddr_in local_addr; 143 | socklen_t len = sizeof(local_addr); 144 | 145 | int ret = getsockname(m_fd, reinterpret_cast(&local_addr), &len); 146 | if (ret != 0) { 147 | ERRORLOG("initLocalAddr error, getsockname error. errno=%d, error=%s", errno, strerror(errno)); 148 | return; 149 | } 150 | 151 | m_local_addr = std::make_shared(local_addr); 152 | 153 | } 154 | 155 | 156 | void TcpClient::addTimerEvent(TimerEvent::s_ptr timer_event) { 157 | m_event_loop->addTimerEvent(timer_event); 158 | } 159 | 160 | } -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_client.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_TCP_CLIENT_H 2 | #define ROCKET_NET_TCP_TCP_CLIENT_H 3 | 4 | #include 5 | #include "rocket/net/tcp/net_addr.h" 6 | #include "rocket/net/eventloop.h" 7 | #include "rocket/net/tcp/tcp_connection.h" 8 | #include "rocket/net/coder/abstract_protocol.h" 9 | #include "rocket/net/timer_event.h" 10 | 11 | 12 | namespace rocket { 13 | 14 | class TcpClient { 15 | public: 16 | typedef std::shared_ptr s_ptr; 17 | 18 | TcpClient(NetAddr::s_ptr peer_addr); 19 | 20 | ~TcpClient(); 21 | 22 | // 异步的进行 conenct 23 | // 如果 connect 完成,done 会被执行 24 | void connect(std::function done); 25 | 26 | // 异步的发送 message 27 | // 如果发送 message 成功,会调用 done 函数, 函数的入参就是 message 对象 28 | void writeMessage(AbstractProtocol::s_ptr message, std::function done); 29 | 30 | 31 | // 异步的读取 message 32 | // 如果读取 message 成功,会调用 done 函数, 函数的入参就是 message 对象 33 | void readMessage(const std::string& msg_id, std::function done); 34 | 35 | void stop(); 36 | 37 | int getConnectErrorCode(); 38 | 39 | std::string getConnectErrorInfo(); 40 | 41 | NetAddr::s_ptr getPeerAddr(); 42 | 43 | NetAddr::s_ptr getLocalAddr(); 44 | 45 | void initLocalAddr(); 46 | 47 | void addTimerEvent(TimerEvent::s_ptr timer_event); 48 | 49 | 50 | private: 51 | NetAddr::s_ptr m_peer_addr; 52 | NetAddr::s_ptr m_local_addr; 53 | 54 | EventLoop* m_event_loop {NULL}; 55 | 56 | int m_fd {-1}; 57 | FdEvent* m_fd_event {NULL}; 58 | 59 | TcpConnection::s_ptr m_connection; 60 | 61 | int m_connect_error_code {0}; 62 | std::string m_connect_error_info; 63 | 64 | }; 65 | } 66 | 67 | #endif -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_connection.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rocket/common/log.h" 3 | #include "rocket/net/fd_event_group.h" 4 | #include "rocket/net/tcp/tcp_connection.h" 5 | #include "rocket/net/coder/string_coder.h" 6 | #include "rocket/net/coder/tinypb_coder.h" 7 | 8 | namespace rocket { 9 | 10 | TcpConnection::TcpConnection(EventLoop* event_loop, int fd, int buffer_size, NetAddr::s_ptr peer_addr, NetAddr::s_ptr local_addr, TcpConnectionType type /*= TcpConnectionByServer*/) 11 | : m_event_loop(event_loop), m_local_addr(local_addr), m_peer_addr(peer_addr), m_state(NotConnected), m_fd(fd), m_connection_type(type) { 12 | 13 | m_in_buffer = std::make_shared(buffer_size); 14 | m_out_buffer = std::make_shared(buffer_size); 15 | 16 | m_fd_event = FdEventGroup::GetFdEventGroup()->getFdEvent(fd); 17 | m_fd_event->setNonBlock(); 18 | 19 | m_coder = new TinyPBCoder(); 20 | 21 | if (m_connection_type == TcpConnectionByServer) { 22 | listenRead(); 23 | } 24 | 25 | } 26 | 27 | TcpConnection::~TcpConnection() { 28 | DEBUGLOG("~TcpConnection"); 29 | if (m_coder) { 30 | delete m_coder; 31 | m_coder = NULL; 32 | } 33 | } 34 | 35 | void TcpConnection::onRead() { 36 | // 1. 从 socket 缓冲区,调用 系统的 read 函数读取字节 in_buffer 里面 37 | 38 | if (m_state != Connected) { 39 | ERRORLOG("onRead error, client has already disconneced, addr[%s], clientfd[%d]", m_peer_addr->toString().c_str(), m_fd); 40 | return; 41 | } 42 | 43 | bool is_read_all = false; 44 | bool is_close = false; 45 | while(!is_read_all) { 46 | if (m_in_buffer->writeAble() == 0) { 47 | m_in_buffer->resizeBuffer(2 * m_in_buffer->m_buffer.size()); 48 | } 49 | int read_count = m_in_buffer->writeAble(); 50 | int write_index = m_in_buffer->writeIndex(); 51 | 52 | int rt = read(m_fd, &(m_in_buffer->m_buffer[write_index]), read_count); 53 | DEBUGLOG("success read %d bytes from addr[%s], client fd[%d]", rt, m_peer_addr->toString().c_str(), m_fd); 54 | if (rt > 0) { 55 | m_in_buffer->moveWriteIndex(rt); 56 | if (rt == read_count) { 57 | continue; 58 | } else if (rt < read_count) { 59 | is_read_all = true; 60 | break; 61 | } 62 | } else if (rt == 0) { 63 | is_close = true; 64 | break; 65 | } else if (rt == -1 && errno == EAGAIN) { 66 | is_read_all = true; 67 | break; 68 | } 69 | } 70 | 71 | if (is_close) { 72 | //TODO: 73 | INFOLOG("peer closed, peer addr [%s], clientfd [%d]", m_peer_addr->toString().c_str(), m_fd); 74 | clear(); 75 | return; 76 | } 77 | 78 | if (!is_read_all) { 79 | ERRORLOG("not read all data"); 80 | } 81 | 82 | // TODO: 简单的 echo, 后面补充 RPC 协议解析 83 | excute(); 84 | 85 | } 86 | 87 | void TcpConnection::excute() { 88 | if (m_connection_type == TcpConnectionByServer) { 89 | // 将 RPC 请求执行业务逻辑,获取 RPC 响应, 再把 RPC 响应发送回去 90 | std::vector result; 91 | m_coder->decode(result, m_in_buffer); 92 | for (size_t i = 0; i < result.size(); ++i) { 93 | // 1. 针对每一个请求,调用 rpc 方法,获取响应 message 94 | // 2. 将响应 message 放入到发送缓冲区,监听可写事件回包 95 | INFOLOG("success get request[%s] from client[%s]", result[i]->m_msg_id.c_str(), m_peer_addr->toString().c_str()); 96 | 97 | std::shared_ptr message = std::make_shared(); 98 | // message->m_pb_data = "hello. this is rocket rpc test data"; 99 | // message->m_msg_id = result[i]->m_msg_id; 100 | 101 | RpcDispatcher::GetRpcDispatcher()->dispatch(result[i], message, this); 102 | } 103 | 104 | } else { 105 | // 从 buffer 里 decode 得到 message 对象, 执行其回调 106 | std::vector result; 107 | m_coder->decode(result, m_in_buffer); 108 | 109 | for (size_t i = 0; i < result.size(); ++i) { 110 | std::string msg_id = result[i]->m_msg_id; 111 | auto it = m_read_dones.find(msg_id); 112 | if (it != m_read_dones.end()) { 113 | it->second(result[i]); 114 | m_read_dones.erase(it); 115 | } 116 | } 117 | 118 | } 119 | 120 | } 121 | 122 | 123 | void TcpConnection::reply(std::vector& replay_messages) { 124 | m_coder->encode(replay_messages, m_out_buffer); 125 | listenWrite(); 126 | } 127 | 128 | void TcpConnection::onWrite() { 129 | // 将当前 out_buffer 里面的数据全部发送给 client 130 | 131 | if (m_state != Connected) { 132 | ERRORLOG("onWrite error, client has already disconneced, addr[%s], clientfd[%d]", m_peer_addr->toString().c_str(), m_fd); 133 | return; 134 | } 135 | 136 | if (m_connection_type == TcpConnectionByClient) { 137 | // 1. 将 message encode 得到字节流 138 | // 2. 将字节流入到 buffer 里面,然后全部发送 139 | 140 | std::vector messages; 141 | 142 | for (size_t i = 0; i< m_write_dones.size(); ++i) { 143 | messages.push_back(m_write_dones[i].first); 144 | } 145 | 146 | m_coder->encode(messages, m_out_buffer); 147 | } 148 | 149 | bool is_write_all = false; 150 | while(true) { 151 | if (m_out_buffer->readAble() == 0) { 152 | DEBUGLOG("no data need to send to client [%s]", m_peer_addr->toString().c_str()); 153 | is_write_all = true; 154 | break; 155 | } 156 | int write_size = m_out_buffer->readAble(); 157 | int read_index = m_out_buffer->readIndex(); 158 | 159 | int rt = write(m_fd, &(m_out_buffer->m_buffer[read_index]), write_size); 160 | 161 | if (rt >= write_size) { 162 | DEBUGLOG("no data need to send to client [%s]", m_peer_addr->toString().c_str()); 163 | is_write_all = true; 164 | break; 165 | } if (rt == -1 && errno == EAGAIN) { 166 | // 发送缓冲区已满,不能再发送了。 167 | // 这种情况我们等下次 fd 可写的时候再次发送数据即可 168 | ERRORLOG("write data error, errno==EAGIN and rt == -1"); 169 | break; 170 | } 171 | } 172 | if (is_write_all) { 173 | m_fd_event->cancle(FdEvent::OUT_EVENT); 174 | m_event_loop->addEpollEvent(m_fd_event); 175 | } 176 | 177 | if (m_connection_type == TcpConnectionByClient) { 178 | for (size_t i = 0; i < m_write_dones.size(); ++i) { 179 | m_write_dones[i].second(m_write_dones[i].first); 180 | } 181 | m_write_dones.clear(); 182 | } 183 | } 184 | 185 | void TcpConnection::setState(const TcpState state) { 186 | m_state = Connected; 187 | } 188 | 189 | TcpState TcpConnection::getState() { 190 | return m_state; 191 | } 192 | 193 | void TcpConnection::clear() { 194 | // 处理一些关闭连接后的清理动作 195 | if (m_state == Closed) { 196 | return; 197 | } 198 | m_fd_event->cancle(FdEvent::IN_EVENT); 199 | m_fd_event->cancle(FdEvent::OUT_EVENT); 200 | 201 | m_event_loop->deleteEpollEvent(m_fd_event); 202 | 203 | m_state = Closed; 204 | 205 | } 206 | 207 | void TcpConnection::shutdown() { 208 | if (m_state == Closed || m_state == NotConnected) { 209 | return; 210 | } 211 | 212 | // 处于半关闭 213 | m_state = HalfClosing; 214 | 215 | // 调用 shutdown 关闭读写,意味着服务器不会再对这个 fd 进行读写操作了 216 | // 发送 FIN 报文, 触发了四次挥手的第一个阶段 217 | // 当 fd 发生可读事件,但是可读的数据为0,即 对端发送了 FIN 218 | ::shutdown(m_fd, SHUT_RDWR); 219 | 220 | } 221 | 222 | 223 | void TcpConnection::setConnectionType(TcpConnectionType type) { 224 | m_connection_type = type; 225 | } 226 | 227 | 228 | void TcpConnection::listenWrite() { 229 | 230 | m_fd_event->listen(FdEvent::OUT_EVENT, std::bind(&TcpConnection::onWrite, this)); 231 | m_event_loop->addEpollEvent(m_fd_event); 232 | } 233 | 234 | 235 | void TcpConnection::listenRead() { 236 | 237 | m_fd_event->listen(FdEvent::IN_EVENT, std::bind(&TcpConnection::onRead, this)); 238 | m_event_loop->addEpollEvent(m_fd_event); 239 | } 240 | 241 | 242 | void TcpConnection::pushSendMessage(AbstractProtocol::s_ptr message, std::function done) { 243 | m_write_dones.push_back(std::make_pair(message, done)); 244 | } 245 | 246 | void TcpConnection::pushReadMessage(const std::string& msg_id, std::function done) { 247 | m_read_dones.insert(std::make_pair(msg_id, done)); 248 | } 249 | 250 | 251 | NetAddr::s_ptr TcpConnection::getLocalAddr() { 252 | return m_local_addr; 253 | } 254 | 255 | NetAddr::s_ptr TcpConnection::getPeerAddr() { 256 | return m_peer_addr; 257 | } 258 | 259 | 260 | int TcpConnection::getFd() { 261 | return m_fd; 262 | } 263 | 264 | } -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_TCP_CONNECTION_H 2 | #define ROCKET_NET_TCP_TCP_CONNECTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "rocket/net/tcp/net_addr.h" 8 | #include "rocket/net/tcp/tcp_buffer.h" 9 | #include "rocket/net/io_thread.h" 10 | #include "rocket/net/coder/abstract_coder.h" 11 | #include "rocket/net/rpc/rpc_dispatcher.h" 12 | 13 | namespace rocket { 14 | 15 | enum TcpState { 16 | NotConnected = 1, 17 | Connected = 2, 18 | HalfClosing = 3, 19 | Closed = 4, 20 | }; 21 | 22 | enum TcpConnectionType { 23 | TcpConnectionByServer = 1, // 作为服务端使用,代表跟对端客户端的连接 24 | TcpConnectionByClient = 2, // 作为客户端使用,代表跟对赌服务端的连接 25 | }; 26 | 27 | class TcpConnection { 28 | public: 29 | 30 | typedef std::shared_ptr s_ptr; 31 | 32 | 33 | public: 34 | TcpConnection(EventLoop* event_loop, int fd, int buffer_size, NetAddr::s_ptr peer_addr, NetAddr::s_ptr local_addr, TcpConnectionType type = TcpConnectionByServer); 35 | 36 | ~TcpConnection(); 37 | 38 | void onRead(); 39 | 40 | void excute(); 41 | 42 | void onWrite(); 43 | 44 | void setState(const TcpState state); 45 | 46 | TcpState getState(); 47 | 48 | void clear(); 49 | 50 | int getFd(); 51 | 52 | // 服务器主动关闭连接 53 | void shutdown(); 54 | 55 | void setConnectionType(TcpConnectionType type); 56 | 57 | // 启动监听可写事件 58 | void listenWrite(); 59 | 60 | // 启动监听可读事件 61 | void listenRead(); 62 | 63 | void pushSendMessage(AbstractProtocol::s_ptr message, std::function done); 64 | 65 | void pushReadMessage(const std::string& msg_id, std::function done); 66 | 67 | NetAddr::s_ptr getLocalAddr(); 68 | 69 | NetAddr::s_ptr getPeerAddr(); 70 | 71 | void reply(std::vector& replay_messages); 72 | 73 | private: 74 | 75 | EventLoop* m_event_loop {NULL}; // 代表持有该连接的 IO 线程 76 | 77 | NetAddr::s_ptr m_local_addr; 78 | NetAddr::s_ptr m_peer_addr; 79 | 80 | TcpBuffer::s_ptr m_in_buffer; // 接收缓冲区 81 | TcpBuffer::s_ptr m_out_buffer; // 发送缓冲区 82 | 83 | FdEvent* m_fd_event {NULL}; 84 | 85 | AbstractCoder* m_coder {NULL}; 86 | 87 | TcpState m_state; 88 | 89 | int m_fd {0}; 90 | 91 | TcpConnectionType m_connection_type {TcpConnectionByServer}; 92 | 93 | // std::pair> 94 | std::vector>> m_write_dones; 95 | 96 | // key 为 msg_id 97 | std::map> m_read_dones; 98 | 99 | }; 100 | 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_server.cc: -------------------------------------------------------------------------------- 1 | #include "rocket/net/tcp/tcp_server.h" 2 | #include "rocket/net/eventloop.h" 3 | #include "rocket/net/tcp/tcp_connection.h" 4 | #include "rocket/common/log.h" 5 | #include "rocket/common/config.h" 6 | 7 | 8 | 9 | namespace rocket { 10 | 11 | TcpServer::TcpServer(NetAddr::s_ptr local_addr) : m_local_addr(local_addr) { 12 | 13 | init(); 14 | 15 | INFOLOG("rocket TcpServer listen sucess on [%s]", m_local_addr->toString().c_str()); 16 | } 17 | 18 | TcpServer::~TcpServer() { 19 | if (m_main_event_loop) { 20 | delete m_main_event_loop; 21 | m_main_event_loop = NULL; 22 | } 23 | if (m_io_thread_group) { 24 | delete m_io_thread_group; 25 | m_io_thread_group = NULL; 26 | } 27 | if (m_listen_fd_event) { 28 | delete m_listen_fd_event; 29 | m_listen_fd_event = NULL; 30 | } 31 | } 32 | 33 | 34 | void TcpServer::init() { 35 | 36 | m_acceptor = std::make_shared(m_local_addr); 37 | 38 | m_main_event_loop = EventLoop::GetCurrentEventLoop(); 39 | m_io_thread_group = new IOThreadGroup(Config::GetGlobalConfig()->m_io_threads); 40 | 41 | m_listen_fd_event = new FdEvent(m_acceptor->getListenFd()); 42 | m_listen_fd_event->listen(FdEvent::IN_EVENT, std::bind(&TcpServer::onAccept, this)); 43 | 44 | m_main_event_loop->addEpollEvent(m_listen_fd_event); 45 | 46 | m_clear_client_timer_event = std::make_shared(5000, true, std::bind(&TcpServer::ClearClientTimerFunc, this)); 47 | m_main_event_loop->addTimerEvent(m_clear_client_timer_event); 48 | 49 | } 50 | 51 | 52 | void TcpServer::onAccept() { 53 | auto re = m_acceptor->accept(); 54 | int client_fd = re.first; 55 | NetAddr::s_ptr peer_addr = re.second; 56 | 57 | m_client_counts++; 58 | 59 | // 把 cleintfd 添加到任意 IO 线程里面 60 | IOThread* io_thread = m_io_thread_group->getIOThread(); 61 | TcpConnection::s_ptr connetion = std::make_shared(io_thread->getEventLoop(), client_fd, 128, peer_addr, m_local_addr); 62 | connetion->setState(Connected); 63 | 64 | m_client.insert(connetion); 65 | 66 | INFOLOG("TcpServer succ get client, fd=%d", client_fd); 67 | } 68 | 69 | void TcpServer::start() { 70 | m_io_thread_group->start(); 71 | m_main_event_loop->loop(); 72 | } 73 | 74 | 75 | void TcpServer::ClearClientTimerFunc() { 76 | auto it = m_client.begin(); 77 | for (it = m_client.begin(); it != m_client.end(); ) { 78 | // TcpConnection::ptr s_conn = i.second; 79 | // DebugLog << "state = " << s_conn->getState(); 80 | if ((*it) != nullptr && (*it).use_count() > 0 && (*it)->getState() == Closed) { 81 | // need to delete TcpConnection 82 | DEBUGLOG("TcpConection [fd:%d] will delete, state=%d", (*it)->getFd(), (*it)->getState()); 83 | it = m_client.erase(it); 84 | } else { 85 | it++; 86 | } 87 | 88 | } 89 | 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /rocket/net/tcp/tcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TCP_SERVER_H 2 | #define ROCKET_NET_TCP_SERVER_H 3 | 4 | #include 5 | #include "rocket/net/tcp/tcp_acceptor.h" 6 | #include "rocket/net/tcp/tcp_connection.h" 7 | #include "rocket/net/tcp/net_addr.h" 8 | #include "rocket/net/eventloop.h" 9 | #include "rocket/net/io_thread_group.h" 10 | 11 | namespace rocket { 12 | 13 | class TcpServer { 14 | public: 15 | TcpServer(NetAddr::s_ptr local_addr); 16 | 17 | ~TcpServer(); 18 | 19 | void start(); 20 | 21 | 22 | private: 23 | void init(); 24 | 25 | // 当有新客户端连接之后需要执行 26 | void onAccept(); 27 | 28 | // 清除 closed 的连接 29 | void ClearClientTimerFunc(); 30 | 31 | 32 | private: 33 | TcpAcceptor::s_ptr m_acceptor; 34 | 35 | NetAddr::s_ptr m_local_addr; // 本地监听地址 36 | 37 | EventLoop* m_main_event_loop {NULL}; // mainReactor 38 | 39 | IOThreadGroup* m_io_thread_group {NULL}; // subReactor 组 40 | 41 | FdEvent* m_listen_fd_event; 42 | 43 | int m_client_counts {0}; 44 | 45 | std::set m_client; 46 | 47 | TimerEvent::s_ptr m_clear_client_timer_event; 48 | 49 | }; 50 | 51 | } 52 | 53 | 54 | #endif -------------------------------------------------------------------------------- /rocket/net/timer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rocket/net/timer.h" 4 | #include "rocket/common/log.h" 5 | #include "rocket/common/util.h" 6 | 7 | namespace rocket { 8 | 9 | 10 | Timer::Timer() : FdEvent() { 11 | 12 | 13 | m_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); 14 | DEBUGLOG("timer fd=%d", m_fd); 15 | 16 | // 把 fd 可读事件放到了 eventloop 上监听 17 | listen(FdEvent::IN_EVENT, std::bind(&Timer::onTimer, this)); 18 | } 19 | 20 | Timer::~Timer() { 21 | } 22 | 23 | 24 | void Timer::onTimer() { 25 | // 处理缓冲区数据,防止下一次继续触发可读事件 26 | // DEBUGLOG("ontimer"); 27 | char buf[8]; 28 | while(1) { 29 | if ((read(m_fd, buf, 8) == -1) && errno == EAGAIN) { 30 | break; 31 | } 32 | } 33 | 34 | // 执行定时任务 35 | int64_t now = getNowMs(); 36 | 37 | std::vector tmps; 38 | std::vector>> tasks; 39 | 40 | ScopeMutex lock(m_mutex); 41 | auto it = m_pending_events.begin(); 42 | 43 | for (it = m_pending_events.begin(); it != m_pending_events.end(); ++it) { 44 | if ((*it).first <= now) { 45 | if (!(*it).second->isCancled()) { 46 | tmps.push_back((*it).second); 47 | tasks.push_back(std::make_pair((*it).second->getArriveTime(), (*it).second->getCallBack())); 48 | } 49 | } else { 50 | break; 51 | } 52 | } 53 | 54 | m_pending_events.erase(m_pending_events.begin(), it); 55 | lock.unlock(); 56 | 57 | 58 | // 需要把重复的Event 再次添加进去 59 | for (auto i = tmps.begin(); i != tmps.end(); ++i) { 60 | if ((*i)->isRepeated()) { 61 | // 调整 arriveTime 62 | (*i)->resetArriveTime(); 63 | addTimerEvent(*i); 64 | } 65 | } 66 | 67 | resetArriveTime(); 68 | 69 | for (auto i: tasks) { 70 | if (i.second) { 71 | i.second(); 72 | } 73 | } 74 | 75 | } 76 | 77 | void Timer::resetArriveTime() { 78 | ScopeMutex lock(m_mutex); 79 | auto tmp = m_pending_events; 80 | lock.unlock(); 81 | 82 | if (tmp.size() == 0) { 83 | return; 84 | } 85 | 86 | int64_t now = getNowMs(); 87 | 88 | auto it = tmp.begin(); 89 | int64_t inteval = 0; 90 | if (it->second->getArriveTime() > now) { 91 | inteval = it->second->getArriveTime() - now; 92 | } else { 93 | inteval = 100; 94 | } 95 | 96 | timespec ts; 97 | memset(&ts, 0, sizeof(ts)); 98 | ts.tv_sec = inteval / 1000; 99 | ts.tv_nsec = (inteval % 1000) * 1000000; 100 | 101 | itimerspec value; 102 | memset(&value, 0, sizeof(value)); 103 | value.it_value = ts; 104 | 105 | int rt = timerfd_settime(m_fd, 0, &value, NULL); 106 | if (rt != 0) { 107 | ERRORLOG("timerfd_settime error, errno=%d, error=%s", errno, strerror(errno)); 108 | } 109 | // DEBUGLOG("timer reset to %lld", now + inteval); 110 | 111 | } 112 | 113 | void Timer::addTimerEvent(TimerEvent::s_ptr event) { 114 | bool is_reset_timerfd = false; 115 | 116 | ScopeMutex lock(m_mutex); 117 | if (m_pending_events.empty()) { 118 | is_reset_timerfd = true; 119 | } else { 120 | auto it = m_pending_events.begin(); 121 | if ((*it).second->getArriveTime() > event->getArriveTime()) { 122 | is_reset_timerfd = true; 123 | } 124 | } 125 | m_pending_events.emplace(event->getArriveTime(), event); 126 | lock.unlock(); 127 | 128 | if (is_reset_timerfd) { 129 | resetArriveTime(); 130 | } 131 | 132 | 133 | } 134 | 135 | void Timer::deleteTimerEvent(TimerEvent::s_ptr event) { 136 | event->setCancled(true); 137 | 138 | ScopeMutex lock(m_mutex); 139 | 140 | auto begin = m_pending_events.lower_bound(event->getArriveTime()); 141 | auto end = m_pending_events.upper_bound(event->getArriveTime()); 142 | 143 | auto it = begin; 144 | for (it = begin; it != end; ++it) { 145 | if (it->second == event) { 146 | break; 147 | } 148 | } 149 | 150 | if (it != end) { 151 | m_pending_events.erase(it); 152 | } 153 | lock.unlock(); 154 | 155 | DEBUGLOG("success delete TimerEvent at arrive time %lld", event->getArriveTime()); 156 | 157 | } 158 | 159 | 160 | 161 | 162 | 163 | } -------------------------------------------------------------------------------- /rocket/net/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TIMER_H 2 | #define ROCKET_NET_TIMER_H 3 | 4 | #include 5 | #include "rocket/common/mutex.h" 6 | #include "rocket/net/fd_event.h" 7 | #include "rocket/net/timer_event.h" 8 | 9 | namespace rocket { 10 | 11 | class Timer : public FdEvent { 12 | public: 13 | 14 | Timer(); 15 | 16 | ~Timer(); 17 | 18 | void addTimerEvent(TimerEvent::s_ptr event); 19 | 20 | void deleteTimerEvent(TimerEvent::s_ptr event); 21 | 22 | void onTimer(); // 当发送了 IO 事件后,eventloop 会执行这个回调函数 23 | 24 | private: 25 | void resetArriveTime(); 26 | 27 | private: 28 | std::multimap m_pending_events; 29 | Mutex m_mutex; 30 | 31 | }; 32 | 33 | 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /rocket/net/timer_event.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "rocket/net/timer_event.h" 3 | #include "rocket/common/log.h" 4 | #include "rocket/common/util.h" 5 | 6 | namespace rocket { 7 | 8 | TimerEvent::TimerEvent(int interval, bool is_repeated, std::function cb) 9 | : m_interval(interval), m_is_repeated(is_repeated), m_task(cb) { 10 | resetArriveTime(); 11 | } 12 | 13 | 14 | void TimerEvent::resetArriveTime() { 15 | 16 | m_arrive_time = getNowMs() + m_interval; 17 | // DEBUGLOG("success create timer event, will excute at [%lld]", m_arrive_time); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /rocket/net/timer_event.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_TIMEREVENT 2 | #define ROCKET_NET_TIMEREVENT 3 | 4 | #include 5 | #include 6 | 7 | namespace rocket { 8 | 9 | class TimerEvent { 10 | 11 | public: 12 | typedef std::shared_ptr s_ptr; 13 | 14 | TimerEvent(int interval, bool is_repeated, std::function cb); 15 | 16 | int64_t getArriveTime() const { 17 | return m_arrive_time; 18 | } 19 | 20 | void setCancled(bool value) { 21 | m_is_cancled = value; 22 | } 23 | 24 | bool isCancled() { 25 | return m_is_cancled; 26 | } 27 | 28 | bool isRepeated() { 29 | return m_is_repeated; 30 | } 31 | 32 | std::function getCallBack() { 33 | return m_task; 34 | } 35 | 36 | void resetArriveTime(); 37 | 38 | private: 39 | int64_t m_arrive_time; // ms 40 | int64_t m_interval; // ms 41 | bool m_is_repeated {false}; 42 | bool m_is_cancled {false}; 43 | 44 | std::function m_task; 45 | 46 | 47 | 48 | }; 49 | 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /rocket/net/wakeup_fd_event.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rocket/net/wakeup_fd_event.h" 3 | #include "rocket/common/log.h" 4 | 5 | 6 | namespace rocket { 7 | 8 | WakeUpFdEvent::WakeUpFdEvent(int fd) : FdEvent(fd) { 9 | } 10 | 11 | WakeUpFdEvent::~WakeUpFdEvent() { 12 | 13 | } 14 | 15 | void WakeUpFdEvent::wakeup() { 16 | char buf[8] = {'a'}; 17 | int rt = write(m_fd, buf, 8); 18 | if (rt != 8) { 19 | ERRORLOG("write to wakeup fd less than 8 bytes, fd[%d]", m_fd); 20 | } 21 | DEBUGLOG("success read 8 bytes"); 22 | } 23 | 24 | 25 | } -------------------------------------------------------------------------------- /rocket/net/wakeup_fd_event.h: -------------------------------------------------------------------------------- 1 | #ifndef ROCKET_NET_WAKEUP_FDEVENT_H 2 | #define ROCKET_NET_WAKEUP_FDEVENT_H 3 | 4 | #include "rocket/net/fd_event.h" 5 | 6 | namespace rocket { 7 | 8 | class WakeUpFdEvent : public FdEvent { 9 | public: 10 | WakeUpFdEvent(int fd); 11 | 12 | ~WakeUpFdEvent(); 13 | 14 | void wakeup(); 15 | 16 | private: 17 | 18 | }; 19 | 20 | 21 | 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /testcases/order.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_generic_services = true; 3 | 4 | message makeOrderRequest { 5 | int32 price = 1; 6 | string goods = 2; 7 | } 8 | 9 | message makeOrderResponse { 10 | int32 ret_code = 1; 11 | string res_info = 2; 12 | string order_id = 3; 13 | } 14 | 15 | service Order { 16 | rpc makeOrder(makeOrderRequest) returns (makeOrderResponse); 17 | } -------------------------------------------------------------------------------- /testcases/test_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "rocket/common/log.h" 12 | #include "rocket/common/config.h" 13 | #include "rocket/common/log.h" 14 | #include "rocket/net/tcp/tcp_client.h" 15 | #include "rocket/net/tcp/net_addr.h" 16 | #include "rocket/net/coder/string_coder.h" 17 | #include "rocket/net/coder/abstract_protocol.h" 18 | #include "rocket/net/coder/tinypb_coder.h" 19 | #include "rocket/net/coder/tinypb_protocol.h" 20 | 21 | void test_connect() { 22 | 23 | // 调用 conenct 连接 server 24 | // wirte 一个字符串 25 | // 等待 read 返回结果 26 | 27 | int fd = socket(AF_INET, SOCK_STREAM, 0); 28 | 29 | if (fd < 0) { 30 | ERRORLOG("invalid fd %d", fd); 31 | exit(0); 32 | } 33 | 34 | sockaddr_in server_addr; 35 | memset(&server_addr, 0, sizeof(server_addr)); 36 | server_addr.sin_family = AF_INET; 37 | server_addr.sin_port = htons(12346); 38 | inet_aton("127.0.0.1", &server_addr.sin_addr); 39 | 40 | int rt = connect(fd, reinterpret_cast(&server_addr), sizeof(server_addr)); 41 | 42 | DEBUGLOG("connect success"); 43 | 44 | std::string msg = "hello rocket!"; 45 | 46 | rt = write(fd, msg.c_str(), msg.length()); 47 | 48 | DEBUGLOG("success write %d bytes, [%s]", rt, msg.c_str()); 49 | 50 | char buf[100]; 51 | rt = read(fd, buf, 100); 52 | DEBUGLOG("success read %d bytes, [%s]", rt, std::string(buf).c_str()); 53 | 54 | } 55 | 56 | void test_tcp_client() { 57 | 58 | rocket::IPNetAddr::s_ptr addr = std::make_shared("127.0.0.1", 12346); 59 | rocket::TcpClient client(addr); 60 | client.connect([addr, &client]() { 61 | DEBUGLOG("conenct to [%s] success", addr->toString().c_str()); 62 | std::shared_ptr message = std::make_shared(); 63 | message->m_msg_id = "123456789"; 64 | message->m_pb_data = "test pb data"; 65 | client.writeMessage(message, [](rocket::AbstractProtocol::s_ptr msg_ptr) { 66 | DEBUGLOG("send message success"); 67 | }); 68 | 69 | client.readMessage("123456789", [](rocket::AbstractProtocol::s_ptr msg_ptr) { 70 | std::shared_ptr message = std::dynamic_pointer_cast(msg_ptr); 71 | DEBUGLOG("msg_id[%s], get response %s", message->m_msg_id.c_str(), message->m_pb_data.c_str()); 72 | }); 73 | }); 74 | } 75 | 76 | int main() { 77 | 78 | rocket::Config::SetGlobalConfig(NULL); 79 | 80 | rocket::Logger::InitGlobalLogger(0); 81 | 82 | // test_connect(); 83 | 84 | test_tcp_client(); 85 | 86 | return 0; 87 | } -------------------------------------------------------------------------------- /testcases/test_eventloop.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "rocket/common/log.h" 9 | #include "rocket/common/config.h" 10 | #include "rocket/net/fd_event.h" 11 | #include "rocket/net/eventloop.h" 12 | #include "rocket/net/timer_event.h" 13 | #include "rocket/net/io_thread.h" 14 | #include "rocket/net/io_thread_group.h" 15 | 16 | 17 | void test_io_thread() { 18 | 19 | // int listenfd = socket(AF_INET, SOCK_STREAM, 0); 20 | // if (listenfd == -1) { 21 | // ERRORLOG("listenfd = -1"); 22 | // exit(0); 23 | // } 24 | 25 | // sockaddr_in addr; 26 | // memset(&addr, 0, sizeof(addr)); 27 | 28 | // addr.sin_port = htons(12310); 29 | // addr.sin_family = AF_INET; 30 | // inet_aton("127.0.0.1", &addr.sin_addr); 31 | 32 | // int rt = bind(listenfd, reinterpret_cast(&addr), sizeof(addr)); 33 | // if (rt != 0) { 34 | // ERRORLOG("bind error"); 35 | // exit(1); 36 | // } 37 | 38 | // rt = listen(listenfd, 100); 39 | // if (rt != 0) { 40 | // ERRORLOG("listen error"); 41 | // exit(1); 42 | // } 43 | 44 | // rocket::FdEvent event(listenfd); 45 | // event.listen(rocket::FdEvent::IN_EVENT, [listenfd](){ 46 | // sockaddr_in peer_addr; 47 | // socklen_t addr_len = sizeof(peer_addr); 48 | // memset(&peer_addr, 0, sizeof(peer_addr)); 49 | // int clientfd = accept(listenfd, reinterpret_cast(&peer_addr), &addr_len); 50 | 51 | // DEBUGLOG("success get client fd[%d], peer addr: [%s:%d]", clientfd, inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port)); 52 | 53 | // }); 54 | 55 | int i = 0; 56 | rocket::TimerEvent::s_ptr timer_event = std::make_shared( 57 | 1000, true, [&i]() { 58 | INFOLOG("trigger timer event, count=%d", i++); 59 | } 60 | ); 61 | 62 | 63 | // rocket::IOThread io_thread; 64 | 65 | 66 | // io_thread.getEventLoop()->addEpollEvent(&event); 67 | // io_thread.getEventLoop()->addTimerEvent(timer_event); 68 | // io_thread.start(); 69 | 70 | // io_thread.join(); 71 | 72 | rocket::IOThreadGroup io_thread_group(2); 73 | rocket::IOThread* io_thread = io_thread_group.getIOThread(); 74 | // io_thread->getEventLoop()->addEpollEvent(&event); 75 | io_thread->getEventLoop()->addTimerEvent(timer_event); 76 | 77 | rocket::IOThread* io_thread2 = io_thread_group.getIOThread(); 78 | io_thread2->getEventLoop()->addTimerEvent(timer_event); 79 | 80 | io_thread_group.start(); 81 | 82 | io_thread_group.join(); 83 | 84 | 85 | } 86 | 87 | int main() { 88 | 89 | rocket::Config::SetGlobalConfig(NULL); 90 | 91 | rocket::Logger::InitGlobalLogger(0); 92 | 93 | test_io_thread(); 94 | 95 | // rocket::EventLoop* eventloop = new rocket::EventLoop(); 96 | 97 | // int listenfd = socket(AF_INET, SOCK_STREAM, 0); 98 | // if (listenfd == -1) { 99 | // ERRORLOG("listenfd = -1"); 100 | // exit(0); 101 | // } 102 | 103 | // sockaddr_in addr; 104 | // memset(&addr, 0, sizeof(addr)); 105 | 106 | // addr.sin_port = htons(12310); 107 | // addr.sin_family = AF_INET; 108 | // inet_aton("127.0.0.1", &addr.sin_addr); 109 | 110 | // int rt = bind(listenfd, reinterpret_cast(&addr), sizeof(addr)); 111 | // if (rt != 0) { 112 | // ERRORLOG("bind error"); 113 | // exit(1); 114 | // } 115 | 116 | // rt = listen(listenfd, 100); 117 | // if (rt != 0) { 118 | // ERRORLOG("listen error"); 119 | // exit(1); 120 | // } 121 | 122 | // rocket::FdEvent event(listenfd); 123 | // event.listen(rocket::FdEvent::IN_EVENT, [listenfd](){ 124 | // sockaddr_in peer_addr; 125 | // socklen_t addr_len = sizeof(peer_addr); 126 | // memset(&peer_addr, 0, sizeof(peer_addr)); 127 | // int clientfd = accept(listenfd, reinterpret_cast(&peer_addr), &addr_len); 128 | 129 | // DEBUGLOG("success get client fd[%d], peer addr: [%s:%d]", clientfd, inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port)); 130 | 131 | // }); 132 | // eventloop->addEpollEvent(&event); 133 | 134 | // int i = 0; 135 | // rocket::TimerEvent::s_ptr timer_event = std::make_shared( 136 | // 1000, true, [&i]() { 137 | // INFOLOG("trigger timer event, count=%d", i++); 138 | // } 139 | // ); 140 | 141 | // eventloop->addTimerEvent(timer_event); 142 | // eventloop->loop(); 143 | 144 | return 0; 145 | } -------------------------------------------------------------------------------- /testcases/test_log.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "rocket/common/log.h" 4 | #include "rocket/common/config.h" 5 | 6 | 7 | void* fun(void*) { 8 | 9 | int i = 20; 10 | while (i--) { 11 | DEBUGLOG("debug this is thread in %s", "fun"); 12 | INFOLOG("info this is thread in %s", "fun"); 13 | } 14 | 15 | return NULL; 16 | } 17 | 18 | int main() { 19 | 20 | rocket::Config::SetGlobalConfig(NULL); 21 | 22 | rocket::Logger::InitGlobalLogger(0); 23 | 24 | 25 | pthread_t thread; 26 | pthread_create(&thread, NULL, &fun, NULL); 27 | 28 | int i = 20; 29 | while (i--) { 30 | DEBUGLOG("test debug log %s", "11"); 31 | INFOLOG("test info log %s", "11"); 32 | } 33 | 34 | pthread_join(thread, NULL); 35 | return 0; 36 | } -------------------------------------------------------------------------------- /testcases/test_rpc_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "rocket/common/log.h" 13 | #include "rocket/common/config.h" 14 | #include "rocket/common/log.h" 15 | #include "rocket/net/tcp/tcp_client.h" 16 | #include "rocket/net/tcp/net_addr.h" 17 | #include "rocket/net/coder/string_coder.h" 18 | #include "rocket/net/coder/abstract_protocol.h" 19 | #include "rocket/net/coder/tinypb_coder.h" 20 | #include "rocket/net/coder/tinypb_protocol.h" 21 | #include "rocket/net/tcp/net_addr.h" 22 | #include "rocket/net/tcp/tcp_server.h" 23 | #include "rocket/net/rpc/rpc_dispatcher.h" 24 | #include "rocket/net/rpc/rpc_controller.h" 25 | #include "rocket/net/rpc/rpc_channel.h" 26 | #include "rocket/net/rpc/rpc_closure.h" 27 | 28 | #include "order.pb.h" 29 | 30 | 31 | 32 | void test_tcp_client() { 33 | 34 | rocket::IPNetAddr::s_ptr addr = std::make_shared("127.0.0.1", 12345); 35 | rocket::TcpClient client(addr); 36 | client.connect([addr, &client]() { 37 | DEBUGLOG("conenct to [%s] success", addr->toString().c_str()); 38 | std::shared_ptr message = std::make_shared(); 39 | message->m_msg_id = "99998888"; 40 | message->m_pb_data = "test pb data"; 41 | 42 | makeOrderRequest request; 43 | request.set_price(100); 44 | request.set_goods("apple"); 45 | 46 | if (!request.SerializeToString(&(message->m_pb_data))) { 47 | ERRORLOG("serilize error"); 48 | return; 49 | } 50 | 51 | message->m_method_name = "Order.makeOrder"; 52 | 53 | client.writeMessage(message, [request](rocket::AbstractProtocol::s_ptr msg_ptr) { 54 | DEBUGLOG("send message success, request[%s]", request.ShortDebugString().c_str()); 55 | }); 56 | 57 | 58 | client.readMessage("99998888", [](rocket::AbstractProtocol::s_ptr msg_ptr) { 59 | std::shared_ptr message = std::dynamic_pointer_cast(msg_ptr); 60 | DEBUGLOG("msg_id[%s], get response %s", message->m_msg_id.c_str(), message->m_pb_data.c_str()); 61 | makeOrderResponse response; 62 | 63 | if(!response.ParseFromString(message->m_pb_data)) { 64 | ERRORLOG("deserialize error"); 65 | return; 66 | } 67 | DEBUGLOG("get response success, response[%s]", response.ShortDebugString().c_str()); 68 | }); 69 | }); 70 | } 71 | 72 | void test_rpc_channel() { 73 | 74 | NEWRPCCHANNEL("127.0.0.1:12345", channel); 75 | 76 | // std::shared_ptr request = std::make_shared(); 77 | 78 | NEWMESSAGE(makeOrderRequest, request); 79 | NEWMESSAGE(makeOrderResponse, response); 80 | 81 | request->set_price(100); 82 | request->set_goods("apple"); 83 | 84 | NEWRPCCONTROLLER(controller); 85 | controller->SetMsgId("99998888"); 86 | controller->SetTimeout(10000); 87 | 88 | std::shared_ptr closure = std::make_shared(nullptr, [request, response, channel, controller]() mutable { 89 | if (controller->GetErrorCode() == 0) { 90 | INFOLOG("call rpc success, request[%s], response[%s]", request->ShortDebugString().c_str(), response->ShortDebugString().c_str()); 91 | // 执行业务逻辑 92 | if (response->order_id() == "xxx") { 93 | // xx 94 | } 95 | } else { 96 | ERRORLOG("call rpc failed, request[%s], error code[%d], error info[%s]", 97 | request->ShortDebugString().c_str(), 98 | controller->GetErrorCode(), 99 | controller->GetErrorInfo().c_str()); 100 | } 101 | 102 | INFOLOG("now exit eventloop"); 103 | // channel->getTcpClient()->stop(); 104 | channel.reset(); 105 | }); 106 | 107 | { 108 | std::shared_ptr channel = std::make_shared(rocket::RpcChannel::FindAddr("127.0.0.1:12345")); 109 | ; 110 | channel->Init(controller, request, response, closure); 111 | Order_Stub(channel.get()).makeOrder(controller.get(), request.get(), response.get(), closure.get()); 112 | } 113 | 114 | // CALLRPRC("127.0.0.1:12345", Order_Stub, makeOrder, controller, request, response, closure); 115 | 116 | 117 | 118 | // xxx 119 | // 协程 120 | } 121 | 122 | int main() { 123 | 124 | rocket::Config::SetGlobalConfig(NULL); 125 | 126 | rocket::Logger::InitGlobalLogger(0); 127 | 128 | // test_tcp_client(); 129 | test_rpc_channel(); 130 | 131 | INFOLOG("test_rpc_channel end"); 132 | 133 | return 0; 134 | } -------------------------------------------------------------------------------- /testcases/test_rpc_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "rocket/common/log.h" 13 | #include "rocket/common/config.h" 14 | #include "rocket/common/log.h" 15 | #include "rocket/net/tcp/tcp_client.h" 16 | #include "rocket/net/tcp/net_addr.h" 17 | #include "rocket/net/coder/string_coder.h" 18 | #include "rocket/net/coder/abstract_protocol.h" 19 | #include "rocket/net/coder/tinypb_coder.h" 20 | #include "rocket/net/coder/tinypb_protocol.h" 21 | #include "rocket/net/tcp/net_addr.h" 22 | #include "rocket/net/tcp/tcp_server.h" 23 | #include "rocket/net/rpc/rpc_dispatcher.h" 24 | 25 | #include "order.pb.h" 26 | 27 | class OrderImpl : public Order { 28 | public: 29 | void makeOrder(google::protobuf::RpcController* controller, 30 | const ::makeOrderRequest* request, 31 | ::makeOrderResponse* response, 32 | ::google::protobuf::Closure* done) { 33 | APPDEBUGLOG("start sleep 5s"); 34 | sleep(5); 35 | APPDEBUGLOG("end sleep 5s"); 36 | if (request->price() < 10) { 37 | response->set_ret_code(-1); 38 | response->set_res_info("short balance"); 39 | return; 40 | } 41 | response->set_order_id("20230514"); 42 | APPDEBUGLOG("call makeOrder success"); 43 | if (done) { 44 | done->Run(); 45 | delete done; 46 | done = NULL; 47 | } 48 | } 49 | 50 | }; 51 | 52 | 53 | int main(int argc, char* argv[]) { 54 | 55 | if (argc != 2) { 56 | printf("Start test_rpc_server error, argc not 2 \n"); 57 | printf("Start like this: \n"); 58 | printf("./test_rpc_server ../conf/rocket.xml \n"); 59 | return 0; 60 | } 61 | 62 | rocket::Config::SetGlobalConfig(argv[1]); 63 | 64 | rocket::Logger::InitGlobalLogger(); 65 | 66 | std::shared_ptr service = std::make_shared(); 67 | rocket::RpcDispatcher::GetRpcDispatcher()->registerService(service); 68 | 69 | rocket::IPNetAddr::s_ptr addr = std::make_shared("127.0.0.1", rocket::Config::GetGlobalConfig()->m_port); 70 | 71 | rocket::TcpServer tcp_server(addr); 72 | 73 | tcp_server.start(); 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /testcases/test_tcp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rocket/common/log.h" 3 | #include "rocket/net/tcp/net_addr.h" 4 | #include "rocket/net/tcp/tcp_server.h" 5 | 6 | void test_tcp_server() { 7 | 8 | rocket::IPNetAddr::s_ptr addr = std::make_shared("127.0.0.1", 12346); 9 | 10 | DEBUGLOG("create addr %s", addr->toString().c_str()); 11 | 12 | rocket::TcpServer tcp_server(addr); 13 | 14 | tcp_server.start(); 15 | 16 | } 17 | 18 | int main() { 19 | 20 | // rocket::Config::SetGlobalConfig("../conf/rocket.xml"); 21 | // rocket::Logger::InitGlobalLogger(); 22 | 23 | rocket::Config::SetGlobalConfig(NULL); 24 | 25 | rocket::Logger::InitGlobalLogger(0); 26 | 27 | test_tcp_server(); 28 | 29 | } --------------------------------------------------------------------------------