在Mac OS系统上,命令行终端切换到/Users/***/ClionProjects/Beautiful1205/ClickHouse/cmake-build-debug/dbms/programs目录下,执行以下命令:
./clickhouse client --port=9000
则通过TCP连接与Server端建立连接,Client端打印如下日志:
ClickHouse源码阅读(0000 0001) —— main.cpp分析这篇文章已经分析了根据启动参数选择不同的应用进行启动,client的mainEntryClickHouseClient方法为:
int mainEntryClickHouseClient(int argc, char **argv) {
try {
DB::Client client;
client.init(argc, argv);//注意客户端需要先执行这里的client.init()方法
return client.run();
}
catch (const boost::program_options::error &e) {
std::cerr << "Bad arguments: " << e.what() << std::endl;
return 1;
}
catch (...) {
std::cerr << DB::getCurrentExceptionMessage(true) << std::endl;
return 1;
}
}
可以看到,这里比server应用启动时多了一个init()方法,具体看下这个方法具体干了啥。
内容比较繁琐,基本就是根据你的输入参数初始化一些内容,比如输入中增加了-n,-m等参数,会做相应的初始化。比较核心的应该是这里:
/// Parse main commandline options.
po::parsed_options parsed = po::command_line_parser(
common_arguments.size(), common_arguments.data()).options(main_description).run();
po::variables_map options;
po::store(parsed, options);
po::notify(options);
就是根据一些预定义的参数和输入的参数将输入参数解析,保存在options中,然后即可以options为基础进行相应的处理。这里先不多做分析了。
接着就是执行client.run()方法,ClickHouse源码阅读(0000 0010) —— 根据日志分析ClickHouse Server启动和终止过程这篇文章已经提到了poco Application 框架以及核心的run()方法,这里就直接跳转到client的实现,即
接着来到了Client.cpp文件ClickHouse Client启动的main()方法这里,一路来到mainImpl()方法。
关键步骤包括:
1)注册相关函数;
2)判断是否是交互模式,如果是交互式模式,输出client版本信息;
// 如果满足以下条件之一, 则表示不是命令行交互模式, 设置is_interactive = false;
// 将启用批处理模式:
//1)输入的参数形如: ./clickhouse-client --query='****';
//2)stdin不是终端命令行.
3)设置标准输出和错误输出的浮点数的精度;
4)判断输出格式;
5)设置一些参数。注意命令行中的settings会覆盖clickhouse-client.xml中的配置;
6)connect()方法向服务端Server发起连接, 连接请求被服务端对应端口的Handler捕获并处理。连接完成后,如果是交互式模式打印连接成功的提示。
client和server是通过Connection这个类来进行连接的。client和server之间通过互相发送数据包通信,server服务端发给client端的数据包定义如下:
//server服务端发给client端的数据包定义
/// Packet that could be received from server.
struct Packet {
UInt64 type;
Block block;
std::unique_ptr<Exception> exception;
std::vector<String> multistring_message;
Progress progress;
BlockStreamProfileInfo profile_info;
Packet() : type(Protocol::Server::Hello) {}
};
7)初始化时区;
8)一些参数的设置;
9)针对交互式模式和非交互式模型,进行不同的处理逻辑。
对于交互式模式,1)从服务器加载建议数据, 方便在客户端命令行输出command line suggestions;2)加载历史命令记录(可以使用上下按键查看历史命令);3)loop()方法, 客户端与服务端一直保持连接。
针对非交互式模式,主要由nonInteractive()方法进行处理。
备注:loop()方法和nonInteractive()方法内部对SQL的处理都是调用了process()方法。在深入分析就涉及SQL的处理了,后面再写文章分析吧。