Linux 实现Web服务器

文章目录

  • 1、http协议介绍
    • GET请求行
    • POST请求头
    • 请求行
    • 响应报文
    • http状态码
  • 2、代码实现

1、http协议介绍

HTTP报文分为请求报文和响应报文两种,每种报文必须按照特有格式生成,才能被浏览器端识别。其中,浏览器端向服务器发送的为请求报文,服务器处理后返回给浏览器端的为响应报文。

请求报文
HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。其中,请求分为两种,GET和POST,具体的:

GET请求行


 1    GET /562f25980001b1b106000338.jpg HTTP/1.1
 2    Host:img.mukewang.com
 3    User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64)
 4    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
 5    Accept:image/webp,image/*,*/*;q=0.8
 6    Referer:http://www.imooc.com/
 7    Accept-Encoding:gzip, deflate, sdch
 8    Accept-Language:zh-CN,zh;q=0.8
 9    空行
10    请求数据为空

POST请求头

1    POST / HTTP1.1
2    Host:www.wrox.com
3    User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
4    Content-Type:application/x-www-form-urlencoded
5    Content-Length:40
6    Connection: Keep-Alive
7    空行
8    name=Professional%20Ajax&publisher=Wiley

请求行

请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本。
GET说明请求类型为GET,/562f25980001b1b106000338.jpg(URL)为要访问的资源,该行的最后一部分说明使用的是HTTP1.1版本。

请求头部,紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息。

HOST,给出请求资源所在服务器的域名。

User-Agent,HTTP客户端程序的信息,该信息由你发出请求使用的浏览器来定义,并且在每个请求中自动发送等。

Accept,说明用户代理可处理的媒体类型。

Accept-Encoding,说明用户代理支持的内容编码。

Accept-Language,说明用户代理能够处理的自然语言集。

Content-Type,说明实现主体的媒体类型。

Content-Length,说明实现主体的大小。

Connection,连接管理,可以是Keep-Alive或close。

空行,请求头部后面的空行是必须的即使第四部分的请求数据为空,也必须有空行。

请求数据也叫主体,可以添加任意的其他数据。

响应报文

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

 1HTTP/1.1 200 OK
 2Date: Fri, 22 May 2009 06:07:21 GMT
 3Content-Type: text/html; charset=UTF-8
 4空行
 5<html>
 6      <head></head>
 7      <body>
 8            <!--body goes here-->
 9      </body>
10</html>
状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。
第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为OK。

消息报头,用来说明客户端要使用的一些附加信息。
第二行和第三行为消息报头,Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8。

空行,消息报头后面的空行是必须的。

响应正文,服务器返回给客户端的文本信息。空行后面的html部分为响应正文。

http状态码

HTTP有5种类型的状态码,具体的:

1xx:指示信息--表示请求已接收,继续处理。

2xx:成功--表示请求正常处理完毕。

200 OK:客户端请求被正常处理。

206 Partial content:客户端进行了范围请求。

3xx:重定向--要完成请求必须进行更进一步的操作。

301 Moved Permanently:永久重定向,该资源已被永久移动到新位置,将来任何对该资源的访问都要使用本响应返回的若干个URI之一。

302 Found:临时重定向,请求的资源现在临时从不同的URI中获得。

4xx:客户端错误--请求有语法错误,服务器无法处理请求。

400 Bad Request:请求报文存在语法错误。

403 Forbidden:请求被服务器拒绝。

404 Not Found:请求不存在,服务器上找不到请求的资源。

5xx:服务器端错误--服务器处理请求出错。

500 Internal Server Error:服务器在执行请求时出现错误。

2、代码实现

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

enum METHOD
{
    GET = 0,
    POST,
    HEAD,
    PUT,
    DELETE,
    TRACE,
    OPTIONS,
    CONNECT,
    PATH
};

enum CHECK_STATE
{
    CHECK_STATE_REQUESTLINE = 0,
    CHECK_STATE_HEADER,
    CHECK_STATE_CONTENT
};

enum HTTP_CODE
{
    NO_REQUEST,
    GET_REQUEST,
    BAD_REQUEST,
    NO_RESOURCE,
    FORBIDDEN_REQUEST,
    FILE_REQUEST,
    INTERNAL_ERROR,
    CLOSED_CONNECTION
};

enum LINE_STATUS
{
    LINE_OK = 0,
    LINE_BAD,
    LINE_OPEN
};

#define BUFFER_LENGTH		4096
#define MAX_EPOLL_EVENTS	1024
#define SERVER_PORT			8888
#define PORT_COUNT			1
#define HTTP_WEBSERVER_HTML_ROOT	"html"
#define HTTP_METHOD_GET		0
#define HTTP_METHOD_POST	1

typedef int NCALLBACK(int ,int, void*);

enum METHOD m_method;
long m_read_idx;
struct iovec m_iv[2];
enum CHECK_STATE m_check_state;
int m_iv_count;
bool m_linger;
int cgi;        //是否启用的POST
char *m_string; //存储请求头数据
char *m_url;
char *m_version;
char *m_host;
long m_content_length;
char m_read_buf[MAX_EPOLL_EVENTS] = {0};
long m_checked_idx;
int m_start_line;
char m_real_file[1024];
char *doc_root = "/root/c_20230613/static";
struct stat m_file_stat;
char *m_file_address;
// memset(m_read_buf,0,MAX_EPOLL_EVENTS);

struct ntyevent {
	int fd;
	int events;
	void *arg;
	int (*callback)(int fd, int events, void *arg);
	
	int status;
	char buffer[BUFFER_LENGTH];
	int length;
	long last_active;

	// http param
	int method; //
	char resource[BUFFER_LENGTH];
	int ret_code;
	
	
};

struct eventblock {

	struct eventblock *next;
	struct ntyevent *events;
	
};

struct ntyreactor {
	int epfd;
	int blkcnt;
	struct eventblock *evblk; //fd --> 100w
};


int recv_cb(int fd, int events, void *arg);
int send_cb(int fd, int events, void *arg);
struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd);


void nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) {

	ev->fd = fd;
	ev->callback = callback;
	ev->events = 0;
	ev->arg = arg;
	ev->last_active = time(NULL);

	return ;
	
}


int nty_event_add(int epfd, int events, struct ntyevent *ev) {

	struct epoll_event ep_ev = {0, {0}};
	ep_ev.data.ptr = ev;
	ep_ev.events = ev->events = events;

	int op;
	if (ev->status == 1) {
		op = EPOLL_CTL_MOD;
	} else {
		op = EPOLL_CTL_ADD;
		ev->status = 1;
	}

	if (epoll_ctl(epfd, op, ev->fd, &ep_ev) < 0) {
		printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);
		return -1;
	}

	return 0;
}

int nty_event_del(int epfd, struct ntyevent *ev) {

	struct epoll_event ep_ev = {0, {0}};

	if (ev->status != 1) {
		return -1;
	}

	ep_ev.data.ptr = ev;
	ev->status = 0;
	epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd, &ep_ev);

	return 0;
}

char *get_line()
{ 
    return m_read_buf + m_start_line; 
}

//从状态机,用于分析出一行内容
//返回值为行的读取状态,有LINE_OK,LINE_BAD,LINE_OPEN
enum LINE_STATUS parse_line()
{
    char temp;
    for (; m_checked_idx < m_read_idx; ++m_checked_idx)
    {
        temp = m_read_buf[m_checked_idx];
        if (temp == '\r')
        {
            if ((m_checked_idx + 1) == m_read_idx)
                return LINE_OPEN;
            else if (m_read_buf[m_checked_idx + 1] == '\n')
            {
                m_read_buf[m_checked_idx++] = '\0';
                m_read_buf[m_checked_idx++] = '\0';
                return LINE_OK;
            }
            return LINE_BAD;
        }
        else if (temp == '\n')
        {
            if (m_checked_idx > 1 && m_read_buf[m_checked_idx - 1] == '\r')
            {
                m_read_buf[m_checked_idx - 1] = '\0';
                m_read_buf[m_checked_idx++] = '\0';
                return LINE_OK;
            }
            return LINE_BAD;
        }
    }
    return LINE_OPEN;
}

//解析http请求行,获得请求方法,目标url及http版本号
enum HTTP_CODE parse_request_line(char *text)
{
    m_url = strpbrk(text, " \t");
    if (!m_url)
    {
        return BAD_REQUEST;
    }
    *m_url++ = '\0';
    char *method = text;
    if (strcasecmp(method, "GET") == 0)
        m_method = GET;
    else if (strcasecmp(method, "POST") == 0)
    {
        m_method = POST;
        cgi = 1;
    }
    else
        return BAD_REQUEST;
    m_url += strspn(m_url, " \t");
    m_version = strpbrk(m_url, " \t");
    if (!m_version)
        return BAD_REQUEST;
    *m_version++ = '\0';
    m_version += strspn(m_version, " \t");
    if ((strcasecmp(m_version, "HTTP/1.1") != 0) && (strcasecmp(m_version, "HTTP/1.0")!=0))
        return BAD_REQUEST;

    if (strncasecmp(m_url, "http://", 7) == 0)
    {
        m_url += 7;
        m_url = strchr(m_url, '/');
    }

    if (strncasecmp(m_url, "https://", 8) == 0)
    {
        m_url += 8;
        m_url = strchr(m_url, '/');
    }
    if (!m_url || m_url[0] != '/')
        return BAD_REQUEST;
    //当url为/时,显示判断界面
    if (strlen(m_url) == 1)
        //strcat(m_url, "judge.html");
        strcat(m_url, "index.html");
    m_check_state = CHECK_STATE_HEADER;
    return NO_REQUEST;
}

//解析http请求的一个头部信息
enum HTTP_CODE parse_headers(char *text)
{
    if (text[0] == '\0')
    {
        if (m_content_length != 0)
        {
            m_check_state = CHECK_STATE_CONTENT;
            return NO_REQUEST;
        }
        return GET_REQUEST;
    }
    else if (strncasecmp(text, "Connection:", 11) == 0)
    {
        text += 11;
        text += strspn(text, " \t");
        if (strcasecmp(text, "keep-alive") == 0)
        {
            m_linger = true;
        }
    }
    else if (strncasecmp(text, "Content-length:", 15) == 0)
    {
        text += 15;
        text += strspn(text, " \t");
        m_content_length = atol(text);
    }
    else if (strncasecmp(text, "Host:", 5) == 0)
    {
        text += 5;
        text += strspn(text, " \t");
        m_host = text;
    }
    else
    {
        //LOG_INFO("oop!unknow header: %s", text);
    }
    return NO_REQUEST;
}

//判断http请求是否被完整读入
enum HTTP_CODE parse_content(char *text)
{
    if (m_read_idx >= (m_content_length + m_checked_idx))
    {
        text[m_content_length] = '\0';
        //POST请求中最后为输入的用户名和密码
        m_string = text;
        return GET_REQUEST;
    }
    return NO_REQUEST;
}

void write_dir(const char* path,const char* rootPath)
{
    char file_buf[255] = {0};
    printf("path:%s\n",path);
    strcat(file_buf,rootPath);
    strcat(file_buf,"/doc.html");
    printf("file_buf:%s\n",file_buf);
    printf("m_real_file%s\n",m_real_file);   

    int fd = open(file_buf,O_RDWR);
    ftruncate(fd,0);
    printf("fd:%d\n",fd);
    char buf[4096] = {0};
    sprintf(buf, "目录名: %s", path);
    sprintf(buf+strlen(buf), "

当前目录: %s

", path);structdirent** ptr;char* name;char dirpath[1024]={0};int num =scandir(path,&ptr,NULL, alphasort);printf("num:%d\n",num);int ret =0;for(int i =0; i < num;++i){ name = ptr[i]->d_name;// 拼接文件的完整路径sprintf(dirpath,"%s/%s",path, name);printf("dirpath:%s\n",dirpath);structstat st;stat(dirpath,&st);// 编码生成 //encode_str(enstr, sizeof(enstr), name);if(strcasecmp(name,"doc.html")==0)continue;if(strcasecmp(name,".")==0)continue;if(strcasecmp(name,"..")==0)continue;// 如果是文件if(S_ISREG(st.st_mode)){sprintf(buf+strlen(buf),"", dirpath,name,(long)st.st_size);}elseif(S_ISDIR(st.st_mode)){// 如果是目录 sprintf(buf+strlen(buf),"", dirpath,name,(long)st.st_size);} ret =write(fd, buf,strlen(buf));if(ret ==-1){//printf("写文件错误---------%d\n",i);}memset(buf,0,sizeof(buf));memset(dirpath,0,sizeof(dirpath));}sprintf(buf+strlen(buf),"
%ssize:%ldk
%s/size:%ldk
"
); ret = write(fd,buf,strlen(buf)); close(fd); } enum HTTP_CODE do_request() { strcpy(m_real_file, doc_root); int len = strlen(doc_root); const char *p = strrchr(m_url, '/'); if (*(p + 1) == '0') { char *m_url_real = (char *)malloc(sizeof(char) * 200); strcpy(m_url_real, "/register.html"); strncpy(m_real_file + len, m_url_real, strlen(m_url_real)); free(m_url_real); } else if (*(p + 1) == '1') { char *m_url_real = (char *)malloc(sizeof(char) * 200); //strcpy(m_url_real, "/log.html"); strcpy(m_url_real, "/index.html"); strncpy(m_real_file + len, m_url_real, strlen(m_url_real)); free(m_url_real); } else if (*(p + 1) == '5') { char *m_url_real = (char *)malloc(sizeof(char) * 200); strcpy(m_url_real, "/picture.html"); strncpy(m_real_file + len, m_url_real, strlen(m_url_real)); free(m_url_real); } else if (*(p + 1) == '6') { char *m_url_real = (char *)malloc(sizeof(char) * 200); strcpy(m_url_real, "/video.html"); strncpy(m_real_file + len, m_url_real, strlen(m_url_real)); free(m_url_real); } else if (*(p + 1) == '7') { char *m_url_real = (char *)malloc(sizeof(char) * 200); strcpy(m_url_real, "/fans.html"); strncpy(m_real_file + len, m_url_real, strlen(m_url_real)); free(m_url_real); } else if(strcasecmp(m_url,"/doc.html") == 0) {// 展示服务器目录结构 write_dir(doc_root,doc_root); strcpy(m_real_file + len, "/doc.html"); } else { if(strncasecmp(m_url,doc_root,strlen(doc_root)) == 0) { memset(m_real_file,0,strlen(m_real_file)); strcpy(m_real_file,m_url); } else { strncpy(m_real_file+len, m_url, strlen(m_url)); } } if (stat(m_real_file, &m_file_stat) < 0) return NO_RESOURCE; if (!(m_file_stat.st_mode & S_IROTH)) return FORBIDDEN_REQUEST; // 如果是目录按照目录方式输出 if (S_ISDIR(m_file_stat.st_mode)) { // 将目录下的文件写入到doc.html中 write_dir(m_real_file,doc_root); memset(m_real_file,0,sizeof(m_real_file)); strcpy(m_real_file, doc_root); strcpy(m_real_file+len, "/doc.html"); } int fd = open(m_real_file, O_RDONLY); m_file_address = (char *)mmap(0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); return FILE_REQUEST; } enum HTTP_CODE process_read() { enum LINE_STATUS line_status = LINE_OK; enum HTTP_CODE ret = NO_REQUEST; char *text = 0; while ((m_check_state == CHECK_STATE_CONTENT && line_status == LINE_OK) || ((line_status = parse_line()) == LINE_OK)) { text = get_line(); m_start_line = m_checked_idx; switch (m_check_state) { case CHECK_STATE_REQUESTLINE: { ret = parse_request_line(text); if (ret == BAD_REQUEST) return BAD_REQUEST; break; } case CHECK_STATE_HEADER: { ret = parse_headers(text); if (ret == BAD_REQUEST) return BAD_REQUEST; else if (ret == GET_REQUEST) { return do_request(); } break; } case CHECK_STATE_CONTENT: { ret = parse_content(text); if (ret == GET_REQUEST) return do_request(); line_status = LINE_OPEN; break; } default: return INTERNAL_ERROR; } } return NO_REQUEST; } bool process_write(HTTP_CODE ret) { switch (ret) { case INTERNAL_ERROR: { add_status_line(500, error_500_title); add_headers(strlen(error_500_form)); if (!add_content(error_500_form)) return false; break; } case BAD_REQUEST: { add_status_line(404, error_404_title); add_headers(strlen(error_404_form)); if (!add_content(error_404_form)) return false; break; } case FORBIDDEN_REQUEST: { add_status_line(403, error_403_title); add_headers(strlen(error_403_form)); if (!add_content(error_403_form)) return false; break; } case NO_RESOURCE: { add_status_line(403, error_403_title); add_headers(strlen(error_403_form)); if (!add_content(error_403_form)) return false; break; } case FILE_REQUEST: { add_status_line(200, ok_200_title); if (m_file_stat.st_size != 0) { add_headers(m_file_stat.st_size); m_iv[0].iov_base = m_write_buf; m_iv[0].iov_len = m_write_idx; m_iv[1].iov_base = m_file_address; m_iv[1].iov_len = m_file_stat.st_size; m_iv_count = 2; bytes_to_send = m_write_idx + m_file_stat.st_size; return true; } else { const char *ok_string = ""; add_headers(strlen(ok_string)); if (!add_content(ok_string)) return false; } } default: return false; } m_iv[0].iov_base = m_write_buf; m_iv[0].iov_len = m_write_idx; m_iv_count = 1; bytes_to_send = m_write_idx; return true; } 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; } int http_request(struct ntyevent *ev) { // GET, POST char linebuf[1024] = {0}; int idx = readline(ev->buffer, 0, linebuf); if (strstr(linebuf, "GET")) { ev->method = HTTP_METHOD_GET; //uri int i = 0; while (linebuf[sizeof("GET ") + i] != ' ') i++; linebuf[sizeof("GET ")+i] = '\0'; sprintf(ev->resource, "./%s/%s", HTTP_WEBSERVER_HTML_ROOT, linebuf+sizeof("GET ")); } else if (strstr(linebuf, "POST")) { } } int recv_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = ntyreactor_idx(reactor, fd); int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0); // if (len > 0) { ev->length = len; ev->buffer[len] = '\0'; printf("C[%d]:%s\n", fd, ev->buffer); //http // motify zl // http_request(ev); memset(m_read_buf,0,sizeof(m_read_buf)); memcpy(m_read_buf,ev->buffer,len); process_read(); //send(); nty_event_del(reactor->epfd, ev); nty_event_set(ev, fd, send_cb, reactor); nty_event_add(reactor->epfd, EPOLLOUT, ev); } else if (len == 0) { nty_event_del(reactor->epfd, ev); close(ev->fd); //printf("[fd=%d] pos[%ld], closed\n", fd, ev-reactor->events); } else { nty_event_del(reactor->epfd, ev); close(ev->fd); printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno)); } return len; } int http_response(struct ntyevent *ev) { if (ev == NULL) return -1; memset(ev->buffer, 0, BUFFER_LENGTH); #if 0 const char *html = "hello http

King

\r\n\r\n"
; ev->length = sprintf(ev->buffer, "HTTP/1.1 200 OK\r\n\ Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n\ Content-Type: text/html;charset=ISO-8859-1\r\n\ Content-Length: 83\r\n\r\n%s", html); #else printf("resource: %s\n", ev->resource); int filefd = open(ev->resource, O_RDONLY); if (filefd == -1) { // return 404 ev->ret_code = 404; ev->length = sprintf(ev->buffer, "HTTP/1.1 404 Not Found\r\n" "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n" "Content-Type: text/html;charset=ISO-8859-1\r\n" "Content-Length: 85\r\n\r\n" "404 Not Found

404

\r\n\r\n"
); } else { struct stat stat_buf; fstat(filefd, &stat_buf); close(filefd); if (S_ISDIR(stat_buf.st_mode)) { ev->ret_code = 404; ev->length = sprintf(ev->buffer, "HTTP/1.1 404 Not Found\r\n" "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n" "Content-Type: text/html;charset=ISO-8859-1\r\n" "Content-Length: 85\r\n\r\n" "404 Not Found

404

\r\n\r\n"
); } else if (S_ISREG(stat_buf.st_mode)) { ev->ret_code = 200; ev->length = sprintf(ev->buffer, "HTTP/1.1 200 OK\r\n" "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n" "Content-Type: text/html;charset=ISO-8859-1\r\n" "Content-Length: %ld\r\n\r\n", stat_buf.st_size ); } } #endif return ev->length; } int send_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = ntyreactor_idx(reactor, fd); http_response(ev); // int len = send(fd, ev->buffer, ev->length, 0); if (len > 0) { printf("send[fd=%d], [%d]%s\n", fd, len, ev->buffer); if (ev->ret_code == 200) { int filefd = open(ev->resource, O_RDONLY); struct stat stat_buf; fstat(filefd, &stat_buf); sendfile(fd, filefd, NULL, stat_buf.st_size); close(filefd); } nty_event_del(reactor->epfd, ev); nty_event_set(ev, fd, recv_cb, reactor); nty_event_add(reactor->epfd, EPOLLIN, ev); } else { close(ev->fd); nty_event_del(reactor->epfd, ev); printf("send[fd=%d] error %s\n", fd, strerror(errno)); } return len; } int accept_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; if (reactor == NULL) return -1; struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); int clientfd; if ((clientfd = accept(fd, (struct sockaddr*)&client_addr, &len)) == -1) { if (errno != EAGAIN && errno != EINTR) { } printf("accept: %s\n", strerror(errno)); return -1; } int flag = 0; if ((flag = fcntl(clientfd, F_SETFL, O_NONBLOCK)) < 0) { printf("%s: fcntl nonblocking failed, %d\n", __func__, MAX_EPOLL_EVENTS); return -1; } struct ntyevent *event = ntyreactor_idx(reactor, clientfd); nty_event_set(event, clientfd, recv_cb, reactor); nty_event_add(reactor->epfd, EPOLLIN, event); printf("new connect [%s:%d], pos[%d]\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), clientfd); return 0; } int init_sock(short port) { int fd = socket(AF_INET, SOCK_STREAM, 0); fcntl(fd, F_SETFL, O_NONBLOCK); struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(port); bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); if (listen(fd, 20) < 0) { printf("listen failed : %s\n", strerror(errno)); } return fd; } int ntyreactor_alloc(struct ntyreactor *reactor) { if (reactor == NULL) return -1; if (reactor->evblk == NULL) return -1; struct eventblock *blk = reactor->evblk; while (blk->next != NULL) { blk = blk->next; } struct ntyevent *evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); if (evs == NULL) { printf("ntyreactor_alloc ntyevents failed\n"); return -2; } memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); struct eventblock *block = (struct eventblock *)malloc(sizeof(struct eventblock)); if (block == NULL) { printf("ntyreactor_alloc eventblock failed\n"); return -2; } memset(block, 0, sizeof(struct eventblock)); block->events = evs; block->next = NULL; blk->next = block; reactor->blkcnt ++; // return 0; } struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd) { int blkidx = sockfd / MAX_EPOLL_EVENTS; while (blkidx >= reactor->blkcnt) { ntyreactor_alloc(reactor); } int i = 0; struct eventblock *blk = reactor->evblk; while(i ++ < blkidx && blk != NULL) { blk = blk->next; } return &blk->events[sockfd % MAX_EPOLL_EVENTS]; } int ntyreactor_init(struct ntyreactor *reactor) { if (reactor == NULL) return -1; memset(reactor, 0, sizeof(struct ntyreactor)); reactor->epfd = epoll_create(1); if (reactor->epfd <= 0) { printf("create epfd in %s err %s\n", __func__, strerror(errno)); return -2; } struct ntyevent *evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); if (evs == NULL) { printf("ntyreactor_alloc ntyevents failed\n"); return -2; } memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent)); struct eventblock *block = (struct eventblock *)malloc(sizeof(struct eventblock)); if (block == NULL) { printf("ntyreactor_alloc eventblock failed\n"); return -2; } memset(block, 0, sizeof(struct eventblock)); block->events = evs; block->next = NULL; reactor->evblk = block; reactor->blkcnt = 1; return 0; } int ntyreactor_destory(struct ntyreactor *reactor) { close(reactor->epfd); //free(reactor->events); struct eventblock *blk = reactor->evblk; struct eventblock *blk_next = NULL; while (blk != NULL) { blk_next = blk->next; free(blk->events); free(blk); blk = blk_next; } return 0; } int ntyreactor_addlistener(struct ntyreactor *reactor, int sockfd, NCALLBACK *acceptor) { if (reactor == NULL) return -1; if (reactor->evblk == NULL) return -1; //reactor->evblk->events[sockfd]; struct ntyevent *event = ntyreactor_idx(reactor, sockfd); nty_event_set(event, sockfd, acceptor, reactor); nty_event_add(reactor->epfd, EPOLLIN, event); return 0; } int ntyreactor_run(struct ntyreactor *reactor) { if (reactor == NULL) return -1; if (reactor->epfd < 0) return -1; if (reactor->evblk == NULL) return -1; struct epoll_event events[MAX_EPOLL_EVENTS+1]; int checkpos = 0, i; while (1) { /* long now = time(NULL); for (i = 0;i < 100;i ++, checkpos ++) { if (checkpos == MAX_EPOLL_EVENTS) { checkpos = 0; } if (reactor->events[checkpos].status != 1) { continue; } long duration = now - reactor->events[checkpos].last_active; if (duration >= 60) { close(reactor->events[checkpos].fd); printf("[fd=%d] timeout\n", reactor->events[checkpos].fd); nty_event_del(reactor->epfd, &reactor->events[checkpos]); } } */ int nready = epoll_wait(reactor->epfd, events, MAX_EPOLL_EVENTS, 1000); if (nready < 0) { printf("epoll_wait error, exit\n"); continue; } for (i = 0;i < nready;i ++) { struct ntyevent *ev = (struct ntyevent*)events[i].data.ptr; if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) { ev->callback(ev->fd, events[i].events, ev->arg); } if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) { ev->callback(ev->fd, events[i].events, ev->arg); } } } } // 3, 6w, 1, 100 == // int main(int argc, char *argv[]) { unsigned short port = SERVER_PORT; // listen 8888 if (argc == 2) { port = atoi(argv[1]); } struct ntyreactor *reactor = (struct ntyreactor*)malloc(sizeof(struct ntyreactor)); ntyreactor_init(reactor); int i = 0; int sockfds[PORT_COUNT] = {0}; for (i = 0;i < PORT_COUNT;i ++) { sockfds[i] = init_sock(port+i); ntyreactor_addlistener(reactor, sockfds[i], accept_cb); } ntyreactor_run(reactor); ntyreactor_destory(reactor); for (i = 0;i < PORT_COUNT;i ++) { close(sockfds[i]); } free(reactor); return 0; }

你可能感兴趣的:(Linux,系统编程,服务器,linux,前端)