这个代码核心就是我们首先监听一个8000接口,然后再服务器上访问这个接口,会得到一些https头文件
rbuffer: GET / HTTP/1.1
Host: 10.150.132.253:8000
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
注意看这里:
然后我们回复一个html,再网页上显示。
其底层就是这样的:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#define BUFFER_LENGTH 1024
#define EVENT_LENGTH 1024
typedef int (*ZVCALLBACK)(int fd, int events, void *arg);
typedef struct zv_connect_s {
int fd;
ZVCALLBACK cb; // 回调函数
int count;
char rbuffer[BUFFER_LENGTH];
int rc; // 当前rbuffer占用了多少
char wbuffer[BUFFER_LENGTH];
int wc; // 当前wbuffer占用了多少
} zv_connect_t;
typedef struct zv_connblock_s {
zv_connect_t *block;
struct zv_connblock_s *next;
} zv_connblock_t;
typedef struct zv_reactor_s {
int epfd;
int blkcnt;
zv_connblock_t *blockheader;
} zv_reactor_t;
//初始化的三种写发
//zv_reactor_t* zv_init_reactor(void);
//zv_reactor_t* zv_init_reactor(zv_reactor_t * reactor);
int zv_init_reactor(zv_reactor_t *reactor) {
if (!reactor) return -1;
#if 0
reactor->blockheader = malloc(sizeof(zv_reactor_t));
if (reactor->blockheader == NULL) return -1;
reactor->epfd = epoll_create(1);
reactor->blockheader->block = calloc(1024, sizeof(zv_connect_t));
if (reactor->blockheader->block == NULL) return -1;
#else
reactor->blockheader = (zv_connblock_t *)malloc(sizeof(zv_reactor_t) + EVENT_LENGTH * sizeof(zv_connect_t));
if (reactor->blockheader == NULL) return -1;
reactor->blockheader->block = (zv_connect_t*)(reactor->blockheader + 1);
reactor->blkcnt = 1;
reactor->blockheader->next = NULL;
reactor->epfd = epoll_create(1);
#endif
return 0;
}
void zv_destory_reactor(zv_reactor_t *reactor) {
if (!reactor) return ;
if (reactor->blockheader) free(reactor->blockheader);
close(reactor->epfd);
}
int zv_connect_block(zv_reactor_t *reactor) {
if (!reactor) return -1;
zv_connblock_t *blk = reactor->blockheader;
while (blk->next != NULL) blk = blk->next;
zv_connblock_t *connblock = (zv_connblock_t *) malloc(sizeof(zv_reactor_t) + EVENT_LENGTH * sizeof(zv_connect_t));
if (connblock == NULL) return -1;
//blk->next = connblock;
connblock->block = (zv_connect_t*)(connblock + 1);
connblock->next = NULL;
blk->next = connblock;
reactor->blkcnt++;
return 0;
}
zv_connect_t *zv_connect_idx(zv_reactor_t *reactor, int fd) {
if (!reactor) return NULL;
int blkidx = fd / EVENT_LENGTH;
while (blkidx >= reactor->blkcnt) {
zv_connect_block(reactor);
}
int i = 0;
zv_connblock_t *blk = reactor->blockheader;
while (i++ < blkidx) {
blk = blk->next;
}
return &blk->block[fd % EVENT_LENGTH];
}
//recv_cb(reactor)
//send_cb()
//zv_connect_t
// rbuffer: GET / HTTP/1.1
// Host: 127.0.0.1:8000
// Connection: keep-alive
// Cache-Control: max-age=0
// sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"
// sec-ch-ua-mobile: ?0
// sec-ch-ua-platform: "Linux"
// Upgrade-Insecure-Requests: 1
// User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
// Sec-Fetch-Site: cross-site
// Sec-Fetch-Mode: navigate
// Sec-Fetch-Dest: document
// Accept-Encoding: gzip, deflate, br, zstd
// Accept-Language: zh-CN,zh;q=0.9
int readline(char *allbuf,int idx,char *linebuf){
int len=strlen(allbuf);
for(;idx<len;idx++){
if(allbuf[idx]=='\r'&&allbuf[idx+1]=='\n'){
return idx+2;
}else{
*(linebuf++)=allbuf[idx];
}
}
}
int zv_http_response(zv_connect_t *conn){
//将响应协议写入wbuffer中
int len = sprintf(conn->wbuffer,
"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: 78r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n"
"<html><head><title>0vi=oice.king</title></head><boby><h1>lipu123</h1></boby></html>");
conn->wc=len;
//conn->wbuffer
//conn->wc=len
}
//要让请求和关联做在一起
int zv_http_request(zv_connect_t *conn){
//conn->rbuffer
//conn->rc
printf("http ---> request:\n %s\n",conn->rbuffer);
char linebuffer[1024]={0};
int idx = readline(conn->rbuffer,0,linebuffer);
printf("line: %s\n",linebuffer);
#if 1
if(strstr(linebuffer,"GET")){//resource
//printf("resource: %s\n",linebuffer+4);
int i=0;
while(linebuffer[sizeof("GET ") + i]!=' ') i++;
linebuffer[sizeof("GET ")+i]='\0';
printf("resource: %s\n",linebuffer+4);
}
#endif
}
int init_server(short port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //io
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(struct sockaddr_in)); // 192.168.1.123
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
servaddr.sin_port = htons(port);
if(-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
printf(" bind failed: %s", strerror(errno));
return -1;
}
listen(sockfd, 10);
printf("sockfd port: %d\n", port);
return sockfd;
}
int recv_cb(int fd, int events, void * arg);
int send_cb(int fd, int events, void *arg) {
//printf("send_cb\n");
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, fd);
//send之前返回response
zv_http_response(conn);
send(fd, conn->wbuffer, conn->wc, 0);
conn->cb = recv_cb;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_MOD, fd, &ev);
return 0;
}
int recv_cb(int fd, int events, void *arg) {
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, fd);
int ret = recv(fd, conn->rbuffer + conn->rc, conn->count, 0);
if (ret < 0) {
printf("recv errno: %d\n", errno);
return -1;
}
else if (ret == 0) { // 当io断开 置为不可用
conn->fd = -1;
conn->rc = 0;
conn->wc = 0;
epoll_ctl(reactor->epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
return -1;
}else{
conn->rc += ret;
printf("rbuffer: %s, rc: %d\n", conn->rbuffer, conn->rc);
//-->echo
//memcpy(conn->wbuffer, conn->rbuffer, conn->rc);
//printf("rc: %d\n", conn->rc);
//conn->wc = conn->rc;
//接收之后处理请求
zv_http_request(conn);
conn->cb = send_cb;
struct epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_MOD, fd, &ev);
}
return 0;
}
int accept_cb(int fd, int events, void *arg) {
//printf("accept_cb\n");
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);
if (clientfd < 0) {
printf("accept errno: %d\n", errno);
return -1;
}
printf("clientfd: %d\n", clientfd);
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, clientfd);;
conn->fd = clientfd;
conn->cb = recv_cb;
conn->count = BUFFER_LENGTH;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(reactor->epfd, EPOLL_CTL_ADD, clientfd, &ev);
return 0;
}
int set_listener(zv_reactor_t *reactor, int fd, ZVCALLBACK cb) {
if (!reactor || !reactor->blockheader) return -1;
reactor->blockheader->block[fd].fd = fd;
reactor->blockheader->block[fd].cb = cb;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_ADD, fd, &ev);
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) return -1;
zv_reactor_t reactor;
zv_init_reactor(&reactor);
int port = atoi(argv[1]);
int i = 0;
for (i = 0; i < 1; ++ i) {
int sockfd = init_server(port + i);
set_listener(&reactor, sockfd, accept_cb);
}
struct epoll_event events[EVENT_LENGTH] = {0};
while (1) {
int nready = epoll_wait(reactor.epfd, events, EVENT_LENGTH, -1);
int i = 0;
for (i = 0; i < nready; ++ i) {
int connfd = events[i].data.fd;
zv_connect_t *conn = zv_connect_idx(&reactor, connfd); // 等同于 &reactor.blockheader->block[connfd]
if (events[i].events & EPOLLIN) {
conn->cb(connfd, events[i].events, &reactor);
}
if (events[i].events & EPOLLOUT) {
conn->cb(connfd, events[i].events, &reactor);
}
}
}
return 0;
}
之后我们定义该目录为http的根目录,然后就可以访问该目录下的html文件了。
如果我们想访问图片的画,要改一个地方:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#define BUFFER_LENGTH 1024
#define EVENT_LENGTH 1024
#define HTTP_WEB_ROOT "/home/user/03_high_server/06_reactor" // hb.jpg所在的文件夹(绝对路径)
typedef int (*ZVCALLBACK)(int fd, int events, void *arg);
typedef struct zv_connect_s {
int fd;
ZVCALLBACK cb; // 回调函数
int count;
char rbuffer[BUFFER_LENGTH];
int rc; // 当前rbuffer占用了多少
char wbuffer[BUFFER_LENGTH];
int wc; // 当前wbuffer占用了多少
char resource[BUFFER_LENGTH]; //
int enable_sendfile;
} zv_connect_t;
typedef struct zv_connblock_s {
zv_connect_t *block;
struct zv_connblock_s *next;
} zv_connblock_t;
typedef struct zv_reactor_s {
int epfd;
int blkcnt;
zv_connblock_t *blockheader;
} zv_reactor_t;
//初始化的三种写发
//zv_reactor_t* zv_init_reactor(void);
//zv_reactor_t* zv_init_reactor(zv_reactor_t * reactor);
int zv_init_reactor(zv_reactor_t *reactor) {
if (!reactor) return -1;
#if 0
reactor->blockheader = malloc(sizeof(zv_reactor_t));
if (reactor->blockheader == NULL) return -1;
reactor->epfd = epoll_create(1);
reactor->blockheader->block = calloc(1024, sizeof(zv_connect_t));
if (reactor->blockheader->block == NULL) return -1;
#else
reactor->blockheader = malloc(sizeof(zv_reactor_t) + EVENT_LENGTH * sizeof(zv_connect_t));
if (reactor->blockheader == NULL) return -1;
reactor->blockheader->block = (zv_connect_t*)(reactor->blockheader + 1);
reactor->blkcnt = 1;
reactor->blockheader->next = NULL;
reactor->epfd = epoll_create(1);
#endif
return 0;
}
void zv_destory_reactor(zv_reactor_t *reactor) {
if (!reactor) return ;
if (reactor->blockheader) free(reactor->blockheader);
close(reactor->epfd);
}
int zv_connect_block(zv_reactor_t *reactor) {
if (!reactor) return -1;
zv_connblock_t *blk = reactor->blockheader;
while (blk->next != NULL) blk = blk->next;
zv_connblock_t *connblock = malloc(sizeof(zv_reactor_t) + EVENT_LENGTH * sizeof(zv_connect_t));
if (connblock == NULL) return -1;
//blk->next = connblock;
connblock->block = (zv_connect_t*)(connblock + 1);
connblock->next = NULL;
blk->next = connblock;
reactor->blkcnt++;
return 0;
}
zv_connect_t *zv_connect_idx(zv_reactor_t *reactor, int fd) {
if (!reactor) return NULL;
int blkidx = fd / EVENT_LENGTH;
while (blkidx >= reactor->blkcnt) {
zv_connect_block(reactor);
}
int i = 0;
zv_connblock_t *blk = reactor->blockheader;
while (i++ < blkidx) {
blk = blk->next;
}
return &blk->block[fd % EVENT_LENGTH];
}
//http的请求协议
//GET / HTTP/1.1
//Host: 192.168.126.132:8000
//Connection: keep-alive
//Cache-Control: max-age=0
//Upgrade-Insecure-Requests: 1
//User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
//Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
//Accept-Encoding: gzip, deflate
//Accept-Language: zh-CN,zh;q=0.9
//读取协议的一行
int readline(char *allbuf, int idx, char *linebuf) {
int len = strlen(allbuf);
for (; idx < len; ++idx) {
if (allbuf[idx] == '\r' && allbuf[idx+1] == '\n') {
return idx + 2;
} else {
*(linebuf++) = allbuf[idx];
}
}
return -1;
}
//URL:
//http://192.168.126.132:8000/hb.jpg
//响应协议
//HTTP/1.1 200 OK
//Accept-Ranges: bytes
//Content-Length: 92678
//Content-Type: image/jpg
//Date: Sat, 06 Aug 2022 13:16:46 GMT
int zv_http_response(zv_connect_t *conn) {
#if 0
int len = sprintf(conn->wbuffer,
"");
conn->wc = len;
#elif 0
printf("resource: %s\n", conn->resource);
int filefd = open(conn->resource, O_RDONLY);
if (filefd == -1) return -1;
//fseek(, SEEK_END)
struct stat stat_buf;
fstat(filefd, &stat_buf);
//将响应协议写入wbuffer中
int len = sprintf(conn->wbuffer,
"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: %ld\r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n", stat_buf.st_size);
len += read(filefd, conn->wbuffer + len, BUFFER_LENGTH-len); //将文件信息也写在wbuffer后
conn->wc = len;
close(filefd);
#elif 0
int filefd = open(conn->resource, O_RDONLY);
if (filefd == -1) return -1;
struct stat stat_buf;
fstat(filefd, &stat_buf);
close(filefd);
int len = sprintf(conn->wbuffer,
"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: %ld\r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n", stat_buf.st_size);
conn->wc = len;
conn->enable_sendfile = 1;
#else
int filefd = open(conn->resource, O_RDONLY); // 打开文件,以只读的方式
if (filefd == -1) return -1;
struct stat stat_buf;
fstat(filefd, &stat_buf); // 将打开的文件信息,存入stat_buf
close(filefd);
// 将第三个参数stat_buf.st_size写在第二个参数的%ld的位置,再把第二个参数存入第一个参数conn->wbuffer中
//返回参数len表示此次写入conn->wbuffer中的长度
int len = sprintf(conn->wbuffer,
"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: %ld\r\n"
"Content-Type: image/jpg\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n", stat_buf.st_size);
conn->wc = len;
conn->enable_sendfile = 1;
#endif
}
//URL:
//http://192.168.126.132:8000/hb.jpg
//请求协议:
//GET /hb.jpg HTTP/1.1
//Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
//Accept-Encoding: gzip, deflate
//Accept-Language: zh-CN,zh;q=0.9
//Cache-Control: max-age=0
//Connection: keep-alive
//Host: 192.168.126.132:8000
//Upgrade-Insecure-Requests: 1
//User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
int zv_http_request(zv_connect_t *conn) {
printf("http --> request:\n %s\n", conn->rbuffer);
char linebuffer[1024] = {0};
int idx = readline(conn->rbuffer, 0, linebuffer);
printf("line: %s\n", linebuffer);
#if 1
if (strstr(linebuffer, "GET")) {
//printf("resource: %s\n", linebuffer+4);
int i = 0;
while (linebuffer[sizeof("GET ") + i] != ' ') ++i;
linebuffer[sizeof("GET ") + i] = '\0';
//memcpy(conn->resource, linebuffer + sizeof("GET "), sizeof(linebuffer));
//printf("resource: %s\n", linebuffer+4); n
sprintf(conn->resource, "%s/%s", HTTP_WEB_ROOT, linebuffer + sizeof("GET ")); // conn->resource = "/home/hebo/server-1/2-1-1-multi-io/hb.jpg"
}
#endif
}
int init_server(short port) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //io
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(struct sockaddr_in)); // 192.168.1.123
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
servaddr.sin_port = htons(port);
if(-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
printf("bind failed: %s", strerror(errno));
return -1;
}
listen(sockfd, 10);
printf("sockfd port: %d\n", port);
return sockfd;
}
int recv_cb(int fd, int events, void * arg);
int send_cb(int fd, int events, void *arg) {
//printf("send_cb\n");
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, fd);
zv_http_response(conn); // 在服务端发送响应协议之前 在send之前进行响应协议处理
// 1. 如果是conn->enable_sendfile == 0,此次send就将响应协议和文件信息一起发送给客户端,只发送一次
// 2_1. 如果是conn->enable_sendfile == 1,此次send就只发送响应协议,共需发送两次(第一次)
send(fd, conn->wbuffer, conn->wc, 0); // send head
#if 1
if (conn->enable_sendfile) { // send body
int filefd = open(conn->resource, O_RDONLY);
if (filefd == -1) return -1;
struct stat stat_buf;
fstat(filefd, &stat_buf);
//ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); 零拷贝机制(指磁盘到内存不需要cpu参与) DMA
// 2_2. 如果是conn->enable_sendfile == 1,此次send就只发送文件信息,共需发送两次(第二次)
int ret = sendfile(fd, filefd, NULL, stat_buf.st_size); // sendbody 发送文件信息
if (ret == -1) {
printf("sendfile errno: %d\n", errno);
}
close(filefd);
}
#endif
conn->cb = recv_cb;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_MOD, fd, &ev);
//return 0;
}
int recv_cb(int fd, int events, void *arg) {
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, fd);
int ret = recv(fd, conn->rbuffer + conn->rc, conn->count, 0);
if (ret < 0) {
//printf("recv errno: %d\n", errno);
//return -1;
}
else if (ret == 0) { // 当io断开 置为不可用
conn->fd = -1;
conn->rc = 0;
conn->wc = 0;
epoll_ctl(reactor->epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
return -1;
}
else {
printf("rc: %d rbuffer:\n%s\n", conn->rc, conn->rbuffer);
conn->rc += ret;
//memcpy(conn->wbuffer, conn->rbuffer, conn->rc);
//printf("rc: %d\n", conn->rc);
//conn->wc = conn->rc;
zv_http_request(conn); // 客户端发送请求协议后 在send之前进行协议处理
conn->cb = send_cb;
struct epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_MOD, fd, &ev);
}
//return 0;
}
int accept_cb(int fd, int events, void *arg) {
//printf("accept_cb\n");
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);
if (clientfd < 0) {
printf("accept errno: %d\n", errno);
return -1;
}
printf("clientfd: %d\n", clientfd);
zv_reactor_t *reactor = (zv_reactor_t*)arg;
zv_connect_t *conn = zv_connect_idx(reactor, clientfd);;
conn->fd = clientfd;
conn->cb = recv_cb;
conn->count = BUFFER_LENGTH;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(reactor->epfd, EPOLL_CTL_ADD, clientfd, &ev);
//return 0;
}
int set_listener(zv_reactor_t *reactor, int fd, ZVCALLBACK cb) {
if (!reactor || !reactor->blockheader) return -1;
reactor->blockheader->block[fd].fd = fd;
reactor->blockheader->block[fd].cb = cb;
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(reactor->epfd, EPOLL_CTL_ADD, fd, &ev);
//return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) return -1;
//printf("sockfd: %d\n", sockfd);
zv_reactor_t reactor;
zv_init_reactor(&reactor);
int port = atoi(argv[1]);
int i = 0;
for (i = 0; i < 1; ++ i) {
int sockfd = init_server(port + i);
set_listener(&reactor, sockfd, accept_cb);
}
struct epoll_event events[EVENT_LENGTH] = {0};
while (1) {
int nready = epoll_wait(reactor.epfd, events, EVENT_LENGTH, -1);
int i = 0;
for (i = 0; i < nready; ++ i) {
int connfd = events[i].data.fd;
zv_connect_t *conn = zv_connect_idx(&reactor, connfd); // 等同于 &reactor.blockheader->block[connfd]
if (events[i].events & EPOLLIN) {
conn->cb(connfd, events[i].events, &reactor);
}
if (events[i].events & EPOLLOUT) {
conn->cb(connfd, events[i].events, &reactor);
}
}
}
return 0;
}
如果我们要做一个http服务器的话,我们要注意几点
- reactor
- request/response
- 并发量测出来
- index.html/png
- header用什么存储,这里通常用key-Value存储
对于Key-value有哪些可以存储: