【Lars教程目錄】
Lars源代碼
https://github.com/aceld/Lars
【Lars系統(tǒng)概述】
第1章-概述
第2章-項(xiàng)目目錄構(gòu)建
【Lars系統(tǒng)之Reactor模型服務(wù)器框架模塊】
第1章-項(xiàng)目結(jié)構(gòu)與V0.1雛形
第2章-內(nèi)存管理與Buffer封裝
第3章-事件觸發(fā)EventLoop
第4章-鏈接與消息封裝
第5章-Client客戶端模型
第6章-連接管理及限制
第7章-消息業(yè)務(wù)路由分發(fā)機(jī)制
第8章-鏈接創(chuàng)建/銷毀Hook機(jī)制
第9章-消息任務(wù)隊(duì)列與線程池
第10章-配置文件讀寫功能
第11章-udp服務(wù)與客戶端
第12章-數(shù)據(jù)傳輸協(xié)議protocol buffer
第13章-QPS性能測試
第14章-異步消息任務(wù)機(jī)制
第15章-鏈接屬性設(shè)置功能
【Lars系統(tǒng)之DNSService模塊】
第1章-Lars-dns簡介
第2章-數(shù)據(jù)庫創(chuàng)建
第3章-項(xiàng)目目錄結(jié)構(gòu)及環(huán)境構(gòu)建
第4章-Route結(jié)構(gòu)的定義
第5章-獲取Route信息
第6章-Route訂閱模式
第7章-Backend Thread實(shí)時(shí)監(jiān)控
【Lars系統(tǒng)之Report Service模塊】
第1章-項(xiàng)目概述-數(shù)據(jù)表及proto3協(xié)議定義
第2章-獲取report上報(bào)數(shù)據(jù)
第3章-存儲線程池及消息隊(duì)列
【Lars系統(tǒng)之LoadBalance Agent模塊】
第1章-項(xiàng)目概述及構(gòu)建
第2章-主模塊業(yè)務(wù)結(jié)構(gòu)搭建
第3章-Report與Dns Client設(shè)計(jì)與實(shí)現(xiàn)
第4章-負(fù)載均衡模塊基礎(chǔ)設(shè)計(jì)
第5章-負(fù)載均衡獲取Host主機(jī)信息API
第6章-負(fù)載均衡上報(bào)Host主機(jī)信息API
第7章-過期窗口清理與過載超時(shí)(V0.5)
第8章-定期拉取最新路由信息(V0.6)
第9章-負(fù)載均衡獲取Route信息API(0.7)
第10章-API初始化接口(V0.8)
第11章-Lars Agent性能測試工具
第12章- Lars啟動(dòng)工具腳本
1) 框架結(jié)構(gòu)
2) Lars Reactor V0.1開發(fā)
? 我們首先先完成一個(gè)最基本的服務(wù)器開發(fā)模型郭卫,封裝一個(gè)tcp_server
類调违。
lars_reactor/include/tcp_server.h
#pragma once
#include <netinet/in.h>
class tcp_server
{
public:
//server的構(gòu)造函數(shù)
tcp_server(const char *ip, uint16_t port);
//開始提供創(chuàng)建鏈接服務(wù)
void do_accept();
//鏈接對象釋放的析構(gòu)
~tcp_server();
private:
int _sockfd; //套接字
struct sockaddr_in _connaddr; //客戶端鏈接地址
socklen_t _addrlen; //客戶端鏈接地址長度
};
? 在tcp_server.cpp中完成基本的功能實(shí)現(xiàn)胁后,我們在構(gòu)造函數(shù)里將基本的socket創(chuàng)建服務(wù)器編程寫完偿荷,然后提供一個(gè)阻塞的do_accept()方法才菠。
lars_reactor/src/tcp_server.cpp
#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的構(gòu)造函數(shù)
tcp_server::tcp_server(const char *ip, uint16_t port)
{
bzero(&_connaddr, sizeof(_connaddr));
//忽略一些信號 SIGHUP, SIGPIPE
//SIGPIPE:如果客戶端關(guān)閉蹦锋,服務(wù)端再次write就會(huì)產(chǎn)生
//SIGHUP:如果terminal關(guān)閉忆谓,會(huì)給當(dāng)前進(jìn)程發(fā)送該信號
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. 創(chuàng)建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可以多次監(jiān)聽夜赵,設(shè)置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 監(jiān)聽ip端口
if (listen(_sockfd, 500) == -1) {
fprintf(stderr, "listen error\n");
exit(1);
}
}
//開始提供創(chuàng)建鏈接服務(wù)
void tcp_server::do_accept()
{
int connfd;
while(true) {
//accept與客戶端創(chuàng)建鏈接
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 添加心跳機(jī)制
//TODO 消息隊(duì)列機(jī)制
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; //不是錯(cuò)誤排作,僅返回0表示此時(shí)不可繼續(xù)寫
}
}
}
}
//鏈接對象釋放的析構(gòu)
tcp_server::~tcp_server()
{
close(_sockfd);
}
? 好了牵啦,現(xiàn)在回到lars_reactor
目錄下進(jìn)行編譯棍丐。
$~/Lars/lars_reactor/
$make
在lib
下仍劈,得到了庫文件。
接下來兴蒸,做一下測試衫生,寫一個(gè)簡單的服務(wù)器應(yīng)用.
$cd ~/Lars/lars_reactor/example
$mkdir lars_reactor_0.1
$cd lars_reactor_0.1
lars_reactor/example/lars_reactor_0.1/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
#include "tcp_server.h"
int main() {
tcp_server server("127.0.0.1", 7777);
server.do_accept();
return 0;
}
? 接下來裳瘪,我們make進(jìn)行編譯,編譯的時(shí)候會(huì)指定鏈接我們剛才生成的liblreactor.a庫罪针。
服務(wù)端:
$ ./lars_reactor
begin accept
客戶端:
$nc 127.0.0.1 7777
hello Lars
得到了服務(wù)器返回的結(jié)果彭羹,那么我們最開始的0.1版本就已經(jīng)搭建完了,但是實(shí)際上這并不是一個(gè)并發(fā)服務(wù)器泪酱,萬里長征才剛剛開始而已派殷。
關(guān)于作者:
作者:Aceld(劉丹冰)
mail: danbing.at@gmail.com
github: https://github.com/aceld
原創(chuàng)書籍gitbook: http://legacy.gitbook.com/@aceld
原創(chuàng)聲明:未經(jīng)作者允許請勿轉(zhuǎn)載, 如果轉(zhuǎn)載請注明出處