🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 1) 框架结构 ![](https://img.kancloud.cn/f3/cc/f3cc8ba143e5e0f612a13f507c396fc4_1082x687.png) ## 2) Lars Reactor V0.1开发 ​ 我们首先先完成一个最基本的服务器开发模型,封装一个`tcp_server`类。 > lars_reactor/include/tcp_server.h ```c #pragma once #include <netinet/in.h> class tcp_server { public: //server的构造函数 tcp_server(const char *ip, uint16_t port); //开始提供创建链接服务 void do_accept(); //链接对象释放的析构 ~tcp_server(); private: int _sockfd; //套接字 struct sockaddr_in _connaddr; //客户端链接地址 socklen_t _addrlen; //客户端链接地址长度 }; ``` ​ 在tcp_server.cpp中完成基本的功能实现,我们在构造函数里将基本的socket创建服务器编程写完,然后提供一个阻塞的do_accept()方法。 > lars_reactor/src/tcp_server.cpp ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <arpa/inet.h> #include <errno.h> #include "tcp_server.h" //server的构造函数 tcp_server::tcp_server(const char *ip, uint16_t port) { bzero(&_connaddr, sizeof(_connaddr)); //忽略一些信号 SIGHUP, SIGPIPE //SIGPIPE:如果客户端关闭,服务端再次write就会产生 //SIGHUP:如果terminal关闭,会给当前进程发送该信号 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) { fprintf(stderr, "signal ignore SIGHUP\n"); } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { fprintf(stderr, "signal ignore SIGPIPE\n"); } //1. 创建socket _sockfd = socket(AF_INET, SOCK_STREAM /*| SOCK_NONBLOCK*/ | SOCK_CLOEXEC, IPPROTO_TCP); if (_sockfd == -1) { fprintf(stderr, "tcp_server::socket()\n"); exit(1); } //2 初始化地址 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; inet_aton(ip, &server_addr.sin_addr); server_addr.sin_port = htons(port); //2-1可以多次监听,设置REUSE属性 int op = 1; if (setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) { fprintf(stderr, "setsocketopt SO_REUSEADDR\n"); } //3 绑定端口 if (bind(_sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { fprintf(stderr, "bind error\n"); exit(1); } //4 监听ip端口 if (listen(_sockfd, 500) == -1) { fprintf(stderr, "listen error\n"); exit(1); } } //开始提供创建链接服务 void tcp_server::do_accept() { int connfd; while(true) { //accept与客户端创建链接 printf("begin accept\n"); connfd = accept(_sockfd, (struct sockaddr*)&_connaddr, &_addrlen); if (connfd == -1) { if (errno == EINTR) { fprintf(stderr, "accept errno=EINTR\n"); continue; } else if (errno == EMFILE) { //建立链接过多,资源不够 fprintf(stderr, "accept errno=EMFILE\n"); } else if (errno == EAGAIN) { fprintf(stderr, "accept errno=EAGAIN\n"); break; } else { fprintf(stderr, "accept error"); exit(1); } } else { //accept succ! //TODO 添加心跳机制 //TODO 消息队列机制 int writed; char *data = "hello Lars\n"; do { writed = write(connfd, data, strlen(data)+1); } while (writed == -1 && errno == EINTR); if (writed > 0) { //succ printf("write succ!\n"); } if (writed == -1 && errno == EAGAIN) { writed = 0; //不是错误,仅返回0表示此时不可继续写 } } } } //链接对象释放的析构 tcp_server::~tcp_server() { close(_sockfd); } ``` ​ 好了,现在回到`lars_reactor`目录下进行编译。 ```bash $~/Lars/lars_reactor/ $make ``` 在`lib`下,得到了库文件。 接下来,做一下测试,写一个简单的服务器应用. ```bash $cd ~/Lars/lars_reactor/example $mkdir lars_reactor_0.1 $cd lars_reactor_0.1 ``` > lars_reactor/example/lars_reactor_0.1/Makefile ```makefile CXX=g++ CFLAGS=-g -O2 -Wall -fPIC -Wno-deprecated INC=-I../../include LIB=-L../../lib -llreactor OBJS = $(addsuffix .o, $(basename $(wildcard *.cc))) all: $(CXX) -o lars_reactor $(CFLAGS) lars_reactor.cpp $(INC) $(LIB) clean: -rm -f *.o lars_reactor ``` > lars_reactor/example/lars_reactor_0.1/lars_reactor.cpp ```c #include "tcp_server.h" int main() { tcp_server server("127.0.0.1", 7777); server.do_accept(); return 0; } ``` ​ 接下来,我们make进行编译,编译的时候会指定链接我们刚才生成的liblreactor.a库。 服务端: ```bash $ ./lars_reactor begin accept ``` 客户端: ```bash $nc 127.0.0.1 7777 hello Lars ``` 得到了服务器返回的结果,那么我们最开始的0.1版本就已经搭建完了,但是实际上这并不是一个并发服务器,万里长征才刚刚开始而已。 --- ### 关于作者: 作者:`Aceld(刘丹冰)` mail: [danbing.at@gmail.com](mailto:danbing.at@gmail.com) github: [https://github.com/aceld](https://github.com/aceld) 原创书籍: [https://www.kancloud.cn/@aceld](https://www.kancloud.cn/@aceld) ![](https://img.kancloud.cn/b0/d1/b0d11a21ba62e96aef1c11d5bfff2cf8_227x227.jpg) >**原创声明:未经作者允许请勿转载, 如果转载请注明出处**