C++开发者如何使用Swoole

PHP编写的Server程序在某些情况下表现会较差

  • 内存占用敏感的场景,PHP底层使用内存结构zval来管理所有变量,会额外占用内存,如一个int32的整数可能需要占用16(PHP7)或24字节(PHP5)的内存,而C/C++只需要4字节。如果系统需要存储大量整数,占用的内存会非常大。
  • PHP是动态解释执行的,计算性能较差,纯运算的代码可能会比C/C++程序差几十甚至上百倍。此类场景下不适合使用PHP
    C/C++的支持弥补了这些不足,在上述场景下可以使用c-swoole或者cpp-swoole来编写Server程序。

cpp-swoole是对c-swoole的面向对象封装,支持了绝大部分swoole_server的特性包括task功能,另外还支持高精度定时器特性。

cpp-swoole依赖libswoole.so,需要先编译c-swoole生成libswoole.so

编译libswoole.so

  1. git clone https://github.com/swoole/swoole-src.git
  2. phpize
  3. ./configure
  4. cmake .
  5. #cmake -DCMAKE_INSTALL_PREFIX=/opt/swoole .
  6. sudo make install

编译安装好libswoole.so后就可以下载cpp-swoole源码,编译libswoole_cpp.so

编译libswoole_cpp.so

  1. git clone https://github.com/swoole/cpp-swoole.git
  2. cmake .
  3. make
  4. sudo make install

编写程序

头文件:

  1. #include <swoole/Server.hpp>
  2. #include <swoole/Timer.hpp>

服务器程序只需要继承swoole::Server,并实现响应的回调函数即可。

  1. #include <swoole/Server.hpp>
  2. #include <swoole/Timer.hpp>
  3. #include <iostream>
  4. using namespace std;
  5. using namespace swoole;
  6. class MyServer : public Server
  7. {
  8. public:
  9. MyServer(string _host, int _port, int _mode = SW_MODE_PROCESS, int _type = SW_SOCK_TCP) :
  10. Server(_host, _port, _mode, _type)
  11. {
  12. serv.worker_num = 4;
  13. SwooleG.task_worker_num = 2;
  14. }
  15. virtual void onStart();
  16. virtual void onShutdown() {};
  17. virtual void onWorkerStart(int worker_id) {}
  18. virtual void onWorkerStop(int worker_id) {}
  19. virtual void onPipeMessage(int src_worker_id, const DataBuffer &) {}
  20. virtual void onReceive(int fd, const DataBuffer &data);
  21. virtual void onConnect(int fd);
  22. virtual void onClose(int fd);
  23. virtual void onPacket(const DataBuffer &data, ClientInfo &clientInfo) {};
  24. virtual void onTask(int task_id, int src_worker_id, const DataBuffer &data);
  25. virtual void onFinish(int task_id, const DataBuffer &data);
  26. };
  27. void MyServer::onReceive(int fd, const DataBuffer &data)
  28. {
  29. swConnection *conn = swWorker_get_connection(&this->serv, fd);
  30. printf("onReceive: fd=%d, ip=%s|port=%d Data=%s|Len=%ld\n", fd, swConnection_get_ip(conn),
  31. swConnection_get_port(conn), (char *) data.buffer, data.length);
  32. int ret;
  33. char resp_data[SW_BUFFER_SIZE];
  34. int n = snprintf(resp_data, SW_BUFFER_SIZE, (char *) "Server: %*s\n", (int) data.length, (char *) data.buffer);
  35. ret = this->send(fd, resp_data, (uint32_t) n);
  36. if (ret < 0)
  37. {
  38. printf("send to client fail. errno=%d\n", errno);
  39. }
  40. else
  41. {
  42. printf("send %d bytes to client success. data=%s\n", n, resp_data);
  43. }
  44. DataBuffer task_data("hello world\n");
  45. this->task(task_data);
  46. // this->close(fd);
  47. }
  48. void MyServer::onConnect(int fd)
  49. {
  50. printf("PID=%d\tConnect fd=%d\n", getpid(), fd);
  51. }
  52. void MyServer::onClose(int fd)
  53. {
  54. printf("PID=%d\tClose fd=%d\n", getpid(), fd);
  55. }
  56. void MyServer::onTask(int task_id, int src_worker_id, const DataBuffer &data)
  57. {
  58. printf("PID=%d\tTaskID=%d\n", getpid(), task_id);
  59. }
  60. void MyServer::onFinish(int task_id, const DataBuffer &data)
  61. {
  62. printf("PID=%d\tClose fd=%d\n", getpid(), task_id);
  63. }
  64. void MyServer::onStart()
  65. {
  66. printf("server start\n");
  67. }
  68. class MyTimer : Timer
  69. {
  70. public:
  71. MyTimer(long ms, bool interval) :
  72. Timer(ms, interval)
  73. {
  74. }
  75. MyTimer(long ms) :
  76. Timer(ms)
  77. {
  78. }
  79. protected:
  80. virtual void callback(void);
  81. int count = 0;
  82. };
  83. void MyTimer::callback()
  84. {
  85. printf("#%d\thello world\n", count);
  86. if (count > 9)
  87. {
  88. this->clear();
  89. }
  90. count++;
  91. }
  92. int main(int argc, char **argv)
  93. {
  94. MyServer server("127.0.0.1", 9501, SW_MODE_SINGLE);
  95. server.listen("127.0.0.1", 9502, SW_SOCK_UDP);
  96. server.listen("::1", 9503, SW_SOCK_TCP6);
  97. server.listen("::1", 9504, SW_SOCK_UDP6);
  98. server.setEvents(EVENT_onStart | EVENT_onReceive | EVENT_onClose | EVENT_onTask | EVENT_onFinish);
  99. server.start();
  100. }