static void maxconns_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 0, .tv_usec = 10000}; if (fd == -42 || allow_new_conns == false) { /* reschedule in 10ms if we need to keep polling */ evtimer_set(&maxconnsevent, maxconns_handler, 0); event_base_set(main_base, &maxconnsevent); evtimer_add(&maxconnsevent, &t); } else { evtimer_del(&maxconnsevent); accept_new_conns(true); } } static bool update_event(conn *c, const int new_flags) { assert(c != NULL); if (c->ev_flags == new_flags) return true; pthread_t tid = pthread_self(); if (tid == dispatcher_thread.thread_id) { struct event_base *base = c->event.ev_base; if (event_del(&c->event) == -1) return false; event_set(&c->event, c->sfd, new_flags, master_event_handler, (void *)c); event_base_set(base, &c->event); c->ev_flags = new_flags; if (event_add(&c->event, 0) == -1) return false; return true; }else{ struct event_base *base = bufferevent_get_base(c->buf_ev); bufferevent_free(c->buf_ev); c->buf_ev = bufferevent_new(c->sfd, event_handler, buf_write_callback, buf_error_callback, (void * )c); bufferevent_base_set(base, c->buf_ev); c->ev_flags = new_flags; if (bufferevent_enable(c->buf_ev, new_flags) == -1) return false; return true; } //这个也得改成bufferevent的形式 /* event_set(&c->event, c->sfd, new_flags, event_handler, (void *)c); event_base_set(base, &c->event); event_add(&c->event, 0); c->buf_ev = bufferevent_new(c->sfd, event_handler, event_handler, NULL, (void * )c); bufferevent_base_set(base, c->buf_ev); bufferevent_enable(c->buf_ev, new_flags); c->ev_flags = new_flags; if (event_add(&c->event, 0) == -1) return false; return true; */ }
void conn_close(conn *c) { assert(c != NULL); /* delete the event, the socket and the conn */ event_del(&c->event); if (settings.verbose > 1) fprintf(stderr, "<%d connection closed.\n", c->sfd); close(c->sfd); accept_new_conns(true); conn_cleanup(c); /* if the connection has big buffers, just free it */ if (c->rsize > READ_BUFFER_HIGHWAT || conn_add_to_freelist(c)) { conn_free(c); } return; }
//void drive_machine(conn* c){ //改成bufferevent之后event_handler和drive_machine都不能幸免需要改参数 void drive_machine(conn* c, struct bufferevent * incoming){ assert(c != NULL); // 真正的处理函数,根据不同的conn的状态来进行不同的处理。 // 虽然我做这个demo只是把消息回显而已,但貌似这么多种状态还是得处理。 bool stop = false; int sfd; socklen_t addrlen; struct sockaddr_storage addr; struct evbuffer *evreturn; char *req; while(!stop){ switch(c->state){ case conn_listening: //如果是listenting状态,则需要把连接accept addrlen = sizeof(addr); sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen); if (sfd == -1) { // accept错误 perror("sfd accept failed"); accept_new_conns(false); //用来决定主线程是否还需要accept连接,如果已经接近饱和了,就停住,等一个时间间隔再来试。 stop = true; } //分派conn任务 dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, tcp_transport); stop = true; break; case conn_new_cmd: /* fall through */ case conn_read: /* now try reading from the socket */ req = evbuffer_readline(incoming->input); if (req == NULL){ //conn_set_state(c, conn_closing); //goto set_conn_closing; conn_set_state(c, conn_waiting); break; } if(c->req != NULL){ free(c->req); c->req = NULL; } c->req = req; conn_set_state(c, conn_mwrite); //if (!update_event(c, EV_WRITE | EV_PERSIST)){ // printf("conn_read update event failed"); // goto set_conn_closing; //} //stop = true; //stop = true; break; //evreturn = evbuffer_new(); //evbuffer_add_printf(evreturn, "You said %s\n", req); // bufferevent_write_buffer(incoming, evreturn); //evbuffer_free(evreturn); //free(req); set_conn_closing: conn_set_state(c, conn_closing); break; case conn_mwrite: //所有的回复到在这个函数进行输出 req = c->req; evreturn = evbuffer_new(); // bufferevent_setwatermark(incoming, EV_WRITE, 0, 0); int res1 = evbuffer_add_printf(evreturn, "You said %s\n", req); int res2 = bufferevent_write_buffer(incoming, evreturn); // int res3 = bufferevent_flush(incoming, EV_WRITE, BEV_FLUSH); int res4 = evbuffer_get_length(incoming->output); evbuffer_free(evreturn); free(req); evreturn = NULL; //int fd = (int)bufferevent_getfd(incoming); //char buf[20]; // //sprintf(buf, "You said %s\n", req); //write(fd, buf, 11); c->req = NULL; conn_set_state(c,conn_waiting); stop = true; break; case conn_waiting: if (!update_event(c, EV_READ | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); conn_set_state(c, conn_closing); break; } conn_set_state(c, conn_read); stop = true; break; case conn_closing: conn_close(c); stop = true; break; } /* otherwise we have a real error, on which we close the connection */ } }
void drive_machine(conn *c) { bool stop = false; int sfd, flags = 1; socklen_t addrlen; struct sockaddr_storage addr; struct linger ling = { 1, 0 }; int res; assert(c != NULL); while (!stop) { switch (c->state) { case conn_listening: addrlen = sizeof(addr); if ((sfd = accept(c->sfd, (struct sockaddr *) &addr, &addrlen)) == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* these are transient, so don't log anything */ stop = true; } else if (errno == EMFILE) { if (settings.verbose > 0) fprintf(stderr, "Too many open connections\n"); accept_new_conns(false); stop = true; } else { perror("accept()"); stop = true; } break; } if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 || fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) { perror("setting O_NONBLOCK"); close(sfd); break; } DEBUG_LOGGER(dsmplog, "accept new socket[%d], wait for request", sfd); setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *) &flags, sizeof(flags)); setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *) &ling, sizeof(ling)); dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, false); break; case conn_read: //DEBUG_LOGGER(dsmplog, "-------------socket [%d] has incoming data-------------", c->sfd); if (try_read_cli(c)) { //数据处理完毕,可以读取下一个请求包 continue; } if (try_read_tcp(c)) { continue; } /* we have no command line and no data to read from network */ if (!update_event(c, EV_READ | EV_PERSIST)) { if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); conn_set_state(c, conn_closing); break; } stop = true; break; case conn_closing: if (c->udp) conn_cleanup(c); else conn_close(c); stop = true; break; } } return; }