beanstalk把监听socket加入了epoll,当客户端有连接时,在主循环sockmain中通过处理epoll事件完成对连接的处理。
1. 客户端连接处理代码
通过前面对主循环的分析可以看出,监听socket的回调处理函数为srvaccept(见如下函数)。
通过分析h_accept可以看出,客户端连接的处理包括三个步骤:
a.建立连接socket,并将连接设置为非阻塞;
b.创建连接管理对象,
c.将和客户端的连接加入epoll
连接处理#监听服务回调函数,用作接受连接 void srvaccept(Server *s, int ev) { h_accept(s->sock.fd, ev, s); } void h_accept(const int fd, const short which, Server *s) { Conn *c; int cfd, flags, r; socklen_t addrlen; struct sockaddr_in6 addr; addrlen = sizeof addr; cfd = accept(fd, (struct sockaddr *)&addr, &addrlen); if (cfd == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) twarn("accept()"); update_conns(); return; } if (verbose) { printf("accept %d\n", cfd); } flags = fcntl(cfd, F_GETFL, 0); if (flags < 0) { twarn("getting flags"); close(cfd); if (verbose) { printf("close %d\n", cfd); } update_conns(); return; } r = fcntl(cfd, F_SETFL, flags | O_NONBLOCK); if (r < 0) { twarn("setting O_NONBLOCK"); close(cfd); if (verbose) { printf("close %d\n", cfd); } update_conns(); return; } //创建连接,并将状态设置为获取用户的请求命令 c = make_conn(cfd, STATE_WANTCOMMAND, default_tube, default_tube); if (!c) { twarnx("make_conn() failed"); close(cfd); if (verbose) { printf("close %d\n", cfd); } update_conns(); return; } c->srv = s; c->sock.x = c; //回调参数,连接信息 c->sock.f = (Handle)prothandle; //回调函数,协议处理 c->sock.fd = cfd; //和客户端连接的socket句柄 //将连接socket加入epoll,设置为读取用户请求命令 r = sockwant(&c->sock, 'r'); if (r == -1) { twarn("sockwant"); close(cfd); if (verbose) { printf("close %d\n", cfd); } update_conns(); return; } update_conns(); }
2. 客户端连接管理
每一个连接抽象为如下结构。
连接抽象struct Conn { Server *srv; //连接所属的Server Socket sock; //连接socket char state; //连接状态 char type; Conn *next; tube use; int64 tickat; // time at which to do more work int tickpos; // position in srv->conns job soonest_job; // memoization of the soonest job int rw; // currently want: 'r', 'w', or 'h' int pending_timeout; char cmd[LINE_BUF_SIZE]; // this string is NOT NUL-terminated int cmd_len; int cmd_read; char *reply; int reply_len; int reply_sent; char reply_buf[LINE_BUF_SIZE]; // this string IS NUL-terminated // How many bytes of in_job->body have been read so far. If in_job is NULL // while in_job_read is nonzero, we are in bit bucket mode and // in_job_read's meaning is inverted -- then it counts the bytes that // remain to be thrown away. int in_job_read; job in_job; // a job to be read from the client job out_job; int out_job_sent; struct ms watch; //watch的tube struct job reserved_jobs; // linked list header };
注意这里的连接socket和监听socket都抽象为统一的Socket类型,两者的差别是属性值。
监听socket的回调参数是Server,回调函数是h_accept,而连接socket的回调参数是Conn,回调函数是prothandle。