linux main函数 线程,主线程之main函数 - 分布式缓存系统 Memcached_服务器应用_Linux公社-Linux系统门户网站...

news/2024/5/15 10:32:24/文章来源:https://blog.csdn.net/weixin_26759093/article/details/116805167

前两节中对工作线程的工作流程做了较为详细的分析,现把其主要流程总结为下图:

35fff726c094e27851eee1c502f9a589.png

接下来本节主要分析主线程相关的函数设计,主函数main的基本流程如下图所示:

0d3361a87e596441bf02774cb831659b.png

对于主线程中的工作线程的初始化到启动所有的工作线程前面已经做了分析,后面的创建监听socket、注册监听socket的libevent事件、启动主线程的libevent事件循环,就是接下来的内容了。

其中主要调用的函数是server_sockets,该函数从配置参数setting.inner字符串中依次提取出一个ip或者一个hostname(一个hostname可能有多个ip),然后传给函数server_socket函数处理之。server_socket函数负责完成创建socket,绑定到端口,监听socket,并将该监听socket对应的conn结构(调用函数conn_new,在该函数中将监听socket注册到主线程libevent main_base上,回调函数为event_handler,其核心部分是drive_machine,这与工作线程是一致的),然后将该conn放入监听队列( conn *listen_conn)中。监听socket上接收到的客户连接的conn将放到连接队列conn **conns中。 最后在main函数中启动libevent事件循环。 还是图来的直观,如下:

e91b564914ee89afe2c6b317ef5ded72.png

static int server_sockets(int port, enum network_transport transport,

FILE *portnumber_file) {  //port是默认的11211或者用户使用-p选项设置的端口号

//settings.inter里面可能有多个IP地址.如果有多个那么将用逗号分隔

char *b;

int ret = 0;

//复制一个字符串,避免下面的strtok_r函数修改(污染)全局变量settings.inter

char *list = strdup(settings.inter);

//这个循环主要是处理多个IP的情况

for (char *p = strtok_r(list, ";,", &b);

p != NULL; //分割出一个个的ip,使用分号;作为分隔符

p = strtok_r(NULL, ";,", &b)) {

int the_port = port;

char *s = strchr(p, ':');//启动的可能使用-l ip:port 参数形式

//ip后面接着端口号,即指定ip的同时也指定了该ip的端口号

//此时采用ip后面的端口号,而不是采用-p指定的端口号

if (s != NULL) {

*s = '\0';//截断后面的端口号,使得p指向的字符串只是一个ip

++s;

if (!safe_strtol(s, &the_port)) {//非法端口号参数值

return 1;

}

}

if (strcmp(p, "*") == 0) {

p = NULL;

}

//处理其中一个IP。有p指定ip(或者hostname)

ret |= server_socket(p, the_port, transport, portnumber_file);

}

free(list);

return ret;

}

static conn *listen_conn = NULL;//监听队列(可能要同时监听多个IP)

//interface是一个ip、hostname或者NULL。这个ip字符串后面没有端口号。端口号由参数port指出

static int server_socket(const char *interface,

int port,

enum network_transport transport,

FILE *portnumber_file) {

int sfd;

struct linger ling = {0, 0};

struct addrinfo *ai;

struct addrinfo *next;

struct addrinfo hints = { .ai_flags = AI_PASSIVE,

.ai_family = AF_UNSPEC };

char port_buf[NI_MAXSERV];

int success = 0;

int flags =1;

hints.ai_socktype = IS_UDP(transport) ? SOCK_DGRAM : SOCK_STREAM;

snprintf(port_buf, sizeof(port_buf), "%d", port);

getaddrinfo(interface, port_buf, &hints, &ai);

//如果interface是一个hostname的话,那么可能就有多个ip

for (next= ai; next; next= next->ai_next) {

conn *listen_conn_add;

//创建一个套接字,然后设置为非阻塞的

sfd = new_socket(next);//调用socket函数

bind(sfd, next->ai_addr, next->ai_addrlen);

success++;

listen(sfd, settings.backlog);

//函数conn_new中将监听套接字fd注册到main_base上,并设定回调函数为event_handler,其中核心为drive_machine函数,这与工作线程是一致的

if (!(listen_conn_add = conn_new(sfd, conn_listening,

EV_READ | EV_PERSIST, 1,

transport, main_base))) {

fprintf(stderr, "failed to create listening connection\n");

exit(EXIT_FAILURE);

}

//将要监听的多个conn放到一个监听队列里面

listen_conn_add->next = listen_conn;

listen_conn = listen_conn_add;

}

freeaddrinfo(ai);

/* Return zero iff we detected no errors in starting up connections */

return success == 0;

}

static int new_socket(struct addrinfo *ai) {

int sfd;

int flags;

sfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

flags = fcntl(sfd, F_GETFL, 0);

fcntl(sfd, F_SETFL, flags | O_NONBLOCK);

return sfd;

}

主线程为每一个监听socket 和接收到的每一个客户端连接socket都分配一个conn结构体,用于管理该socket的各种状态信息等。需要注意的是的,memcached并不是对每一个socket分别创建分配一个conn结构,而是在初始化时一次性分配若干(跟审定的允许的同时最大数量的客户端连接数有关)个conn结构的指针(注意不是conn结构体,因为每一个conn结构是比较大的,因此如果直接分配若干个conn结构需要占用较大空间),在都确实需要一个conn结构时,再从预分配的指针数组中取用一个,并实际为该指针分配空间,完成具体的初始化等。 这与前面的CQ_ITEM内存池是一致的——按配置预分配若干,按需取用,循环利用。 避免内存碎片,提高性能。

其中函数conn_init负责预分配设置的若干个conn的指针,由一个conn**指针维护。函数conn_new则在确实需要一个conn时从conn**维护的数组中取得一个conn*,并完成实际的空间分配等。

具体分析如下:

函数conn_init:

conn **conns; //conn数组指针

static void conn_init(void) {

/* We're unlikely to see an FD much higher than maxconns. */

//已经dup返回当前未使用的最小正整数,所以next_fd等于此刻已经消耗了的fd个数

int next_fd = dup(1);//获取当前已经使用的fd的个数

//预留一些文件描述符。也就是多申请一些conn结构体。以免有别的需要把文件描述符

//给占了。导致socket fd的值大于这个数组长度

int headroom = 10;//预留一些文件描述符  /* account for extra unexpected open FDs */

struct rlimit rl;

//settings.maxconns的默认值是1024.

max_fds = settings.maxconns + headroom + next_fd;

/* But if possible, get the actual highest FD we can possibly ever see. */

if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {

max_fds = rl.rlim_max;

} else {

fprintf(stderr, "Failed to query maximum file descriptor; "

"falling back to maxconns\n");

}

close(next_fd);//next_fd只是用来计数的,并没有其他用途

//注意,申请的conn结构体数量是比settings.maxconns这个客户端同时在线数

//还要大的。因为memcached是直接用socket fd的值作为数组下标的。也正是

//这个原因,前面需要使用headroom预留一些空间给突发情况

if ((conns = calloc(max_fds, sizeof(conn *))) == NULL) {//注意是conn指针不是conn结构体

fprintf(stderr, "Failed to allocate connection structures\n");

/* This is unrecoverable so bail out early. */

exit(1);

}

}

函数conn_new:

//为sfd分配一个conn结构体,并且为这个sfd建立一个event,然后注册到event_base上。

conn *conn_new(const int sfd, enum conn_states init_state,//init_state值为conn_listening

const int event_flags,

const int read_buffer_size, enum network_transport transport,

struct event_base *base) {

conn *c;

assert(sfd >= 0 && sfd < max_fds);

c = conns[sfd];//直接使用下标

if (NULL == c) {//之前没有哪个连接用过这个sfd值,需要申请一个conn结构体

if (!(c = (conn *)calloc(1, sizeof(conn)))) {

fprintf(stderr, "Failed to allocate connection object\n");

return NULL;

}

...//初始化一些成员变量

c->sfd = sfd;

conns[sfd] = c; //将这个结构体交由conns数组管理

}

...//初始化另外一些成员变量

c->state = init_state;//值为conn_listening

//等同于event_assign,会自动关联current_base。event的回调函数是event_handler

event_set(&c->event, sfd, event_flags, event_handler, (void *)c);

event_base_set(base, &c->event);

c->ev_flags = event_flags;

if (event_add(&c->event, 0) == -1) {

perror("event_add");

return NULL;

}

return c;

}

从上可以看到,实际上所有的conn从预分配到实际分配,都是有conn**指针维护的。只需要通过判断该数组中的某元素conn指针是否为空:等于NULL即没被实际占用,处于空闲状态,反之,已经被一个实际的socket fd占用。

至此,主线程所有的准备工作已经就绪,接下来就是真正的客户端连接事件的处理了:

回调函数event_handler(工作线程的注册事件的回调函数也是它):

event_handler本身是简单的,其核心是drive_machine函数(一个有限状态机,负责处理所有的客户逻辑)。

void event_handler(const int fd, const short which, void *arg) {

conn *c;

c = (conn *)arg;

assert(c != NULL);

c->which = which;

if (fd != c->sfd) {

conn_close(c);

return;

}

drive_machine(c);

return;

}

其中的drive_machine还是比较复杂的,接下来将分几个小节的内容,对此细细道来。0b1331709591d260c1c78e86d0c51c18.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_749249.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何删除谷歌拼音_外贸网站如何进行域名解析和主机绑定?

网站的域名和主机是生死相关的两兄弟.但是很多人不是很清楚这两者的联系以及如何将这两者联系在一起的操作.简单的打个比方&#xff1a;网站就是你家的房子&#xff0c;主机就是你家房子的地基&#xff0c;域名就是你家的门牌主机地址在地图上可以用经纬度表示&#xff0c;这就…

SNS社交类网站照片头像裁剪源码

客户端js不能操作文件&#xff0c;所以只能先上传图片再在服务器端剪切。 1、上传图片 2、js剪切图片&#xff08;其实只是选取要剪切的部分&#xff09; 3、服务器端剪切 &#xff08;1&#xff09;在页面的cs文件中剪切。须放几个隐藏控件以便回传js选取的坐标。 其中剪切图片…

filebeat+logstash+influxdb+ Grafana打造网站日志监控系统

filebeatlogstashinfluxdb Grafana打造网站日志监控系统 yexiansen关注 0.822018.02.01 13:13:22字数 1,093阅读 3,109 filebeatlogstashinfluxdb Grafana打造网站日志监控系统 image 采集数据&#xff08;fliebeat&#xff09;->过滤数据&#xff08;logstash&#xff09…

18个黑科技网站,你想要的软件都能找到,请收藏!!!

序言 要说现在啊&#xff0c;我们使用频率最高的设备是啥&#xff0c;那一定是手机啊&#xff0c;几乎不离身&#xff0c;没了它&#xff0c;生活就索然无味啊&#x1f62a;&#xff0c;除了手机&#xff0c;对我来说&#xff0c;排在第二位的就是电脑了。 那么使用手机和电脑…

百度SEO优化那些事(5月14日)相约天极传媒

活动类型: 沙龙讲座 开始时间: 2011-5-14 14:00 活动地点: 北京市海淀区海淀中街15号远中悦莱大厦2层(天极传媒集团公司第一会议室) 性别: 不限 报名截止: 2011-5-14 14:00 报名地址: http://bang.chinabyte.com/thread-502109-1-1.html 百度&#xff0c;全球最大的中文搜…

使用HTML5,CSS3和jQuery增强网站用户体验

记 得几年前如果你需要添加一些互动元素到你的网站中用来改善用户体验&#xff1f; 是不是立刻就想到了flash实现&#xff1f;这彷佛年代久远的事了。使用现在最流行的web技术 HTML5&#xff0c;CSS3和jQuery&#xff0c;同样也可以实现类似的用户体验。而且使用这些特性将会比…

9月第1周社交网站综合排行:网易微博跌出榜外

据站长之家综合排行榜数据&#xff0c;9月第1周&#xff08;2013-08-27至2013-09-02&#xff09;的社交网站排行的首位是新浪微博&#xff0c;其综合积分为4415&#xff0c;第二位是综合积分为4261的豆瓣网&#xff0c;第三位是综合积分为4249的腾讯微博。而网易微博在今周跌出…

管中窥豹:美丽说的一些SEO优化小细节

大家好&#xff0c;我是虚子雨。前面跟大家分享过关于美丽说和蘑菇街的品牌关键词策略&#xff0c;得到一些朋友的反馈&#xff0c;有好评&#xff0c;多半来自好朋友&#xff0c;也有差评&#xff0c;多半来自一 些真心看过文章的朋友&#xff0c;这说明文章的确有不足&#x…

B2B策划书:B2B行业网站未来5年发展趋势预测

B2B行业网站目前已经发展成一个不可忽视的行业&#xff0c;虽然绝大部分的企业本身不是很大&#xff0c;只能算是中小企业&#xff0c;但是由于涉及到的公司多、行业范围广、从业者多&#xff0c;且还是一个值得投资的产业&#xff0c;在2009年刚过&#xff0c;2010年到来的时候…

推荐大家几个网站

2019独角兽企业重金招聘Python工程师标准>>> 36kr 关注互联网信息 拉勾网 互联网公司招聘 Nitrous.IO 一个远程IDE开发环境 Terminal 看名字就知道了&#xff0c; Jelastic 一个远程的服务器&#xff0c;可以配置tomcat服务器 stack overflow githu…

Node与Git环境搭建登录网站

Node与Git环境搭建登录网站 引言 本篇博文教程用于前端搭建环境并实现简易登录网站,使用Git爬取前端项目,进行快速开发。 准备文件 配置Node与Git环境变量 (1) node配置:右击此电脑–>打开环境变量—>高级–>在系统变量中新建变量:NODE_HOME,变量值为文件所在地…

大型网站架构演变和知识体系 -转载学习

架构演变第一步&#xff1a;物理分离webserver和数据库 最开始&#xff0c;由于某些想法&#xff0c;于是在互联网上搭建了一个网站&#xff0c;这个时候甚至有可能主机都是租借的&#xff0c;但由于这篇文章我们只关注架构的演变历程&#xff0c;因此就假设这个时候 已经是托管…

经典案例:那些让人赞不绝口的创新 HTML5 网站

在过去的10年里&#xff0c;网页设计师使用 Flash、JavaScript 或其他复杂的软件和技术来创建网站。但现在你可以前所未有的快速、轻松地设计或创造互动的、有趣好看的网站。如何创建&#xff1f;答案是 HTML5 。 这篇文章向大家展示20个创新的 HTML5 网站。看看这些惊人的 HTM…

springsecurity oauth2_Spring Security 实战干货:客户端OAuth2授权请求的入口在哪里-WEB资讯专栏-DMOZ中文网站分类目录

CSDN 双十一 活动优惠提前抢&#xff01;全站好课1元起&#xff0c;万券齐发折上折&#xff01; 超值膨胀金【10元抵100元】限量发放&#xff01;11月11日当天全站通用&#xff0c;更有机会享受折上折优惠&#xff01;仅限299份&#xff0c;先到先得&#xff01; 1. 前言 在Spr…

layui的tab加入其他页面_SEO干货知识分享:字数会影响SEO吗?| 教你如何为页面撰写合格的内容...

你的页面内容需要多少字数才能排到谷歌搜索结果第一页&#xff1f;搜索引擎优化的最佳内容长度是多少&#xff1f;今天就让我们来找出字数和谷歌SEO优化背后的关系。当我们在为页面确定内容时&#xff0c;“我需要写多少字&#xff1f;”是其中一个人们经常会问到的问题&#x…

wap建站程序源码_免费网站建站好不好?超简单建站教程来了

现在各种建站模式都开始陆续出现&#xff0c;有写代码建站&#xff0c;模板建站&#xff0c;免费建站&#xff0c;付费建站……对于大多数缺少资金和时间&#xff0c;也不懂技术的小白来说&#xff0c;可选余地就非常有限了&#xff0c;一般是选择找免费网站建站。那么这种建站…

黄聪:WordPress 多站点建站教程(二):后台(管理网络)设置详解,如何管理子站的用户、主题、插件、设置等功能...

建立好了子站&#xff0c;我们需要有个地方配置所有子站的主题、插件等功能&#xff0c;我们可以在后台看到 我的站点--管理网络 如下图&#xff1a; 在 管理网络--仪表盘 里面&#xff0c;我们可以创新用户和站点&#xff0c;也提供了查询功能。 要注意的是&#xff1a;当你新…

各大网站CSS代码初始化集合

2019独角兽企业重金招聘Python工程师标准>>> css代码之所以初始化&#xff0c;是因为能尽量减少 各浏览器之间的兼容性问题!腾讯QQ官网 样式初始化 body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select{margin:0;padding:0} b…

github mysql优化_GitHub如何通过迁移MySQL数据库提高网站性能

GitHub&#xff0c;作为广泛使用的开源代码库以及版本控制系统&#xff0c;其数据库MySQL性能的优劣对整个网站平台有着举足轻重的影响。接下来我们一起GitHub&#xff0c;作为广泛使用的开源代码库以及版本控制系统&#xff0c;其数据库MySQL性能的优劣对整个网站平台有着举足…

熊掌号 php提交,网站接入熊掌号,网页配置并提交

百度熊掌号是什么&#xff1f;百度熊掌号是站长、自媒体、开发者、商家等各种内容和服务提供者入驻百度的身份账号&#xff0c;该账号可实现包括百度搜索资源平台、百度数据开放平台、百家号自媒体平台、用户运营平台等各类平台的能力互通。开通熊掌号之后站点自然也就有了原创…