connector *connector_new(struct sockaddr *sa, int socklen, rpc_cb_func rpc) { connector *cr = (connector *)malloc(sizeof(connector)); if (NULL == cr) { mfatal("connector alloc failed!"); return NULL; } cr->sa = (struct sockaddr *)malloc(socklen); if (NULL == cr->sa) { mfatal("sockaddr alloc failed!"); free(cr); return NULL; } cr->cb.rpc = rpc; cr->state = STATE_NOT_CONNECTED; cr->c = NULL; memcpy(cr->sa, sa, socklen); cr->socklen = socklen; snprintf(cr->addrtext, 32, "%s:%d", inet_ntoa(((struct sockaddr_in *)(cr->sa))->sin_addr), ntohs(((struct sockaddr_in *)(cr->sa))->sin_port)); cr->timer = NULL; dispatch_conn_new(-1, 't', cr); return cr; }
void signal_cb(evutil_socket_t fd, short what, void *arg) { mdebug("signal_cb"); struct event_base *base = (struct event_base *)arg; event_base_loopbreak(base); dispatch_conn_new(-1, 'k', NULL); }
static void client_accept(aeEventLoop *el, int fd, void *privdata, int mask) { int sd; vr_listen *vlisten = privdata; while((sd = vr_listen_accept(vlisten)) > 0) { dispatch_conn_new(vlisten, sd); } }
/* * Wait continously for events. We exit only if no events are left. */ void event_dispatch_loop(int listenfd) { int connfd; printf("======waiting for client's request======\n"); while(1){ if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){ perror("accept"); continue; } dispatch_conn_new(connfd, conn_new_cmd, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, tcp_transport); //close(connfd); } }
//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; }
static int server_socket(const int port, const bool is_udp) { int sfd; struct linger ling = { 0, 0 }; struct addrinfo *ai; struct addrinfo *next; struct addrinfo hints; char port_buf[NI_MAXSERV]; int error; int success = 0; int flags = 1; /* * the memset call clears nonstandard fields in some impementations * that otherwise mess things up. */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; if (is_udp) { hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; hints.ai_family = AF_INET; /* This left here because of issues with OSX 10.5 */ } else { hints.ai_family = AF_UNSPEC; hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; } snprintf(port_buf, NI_MAXSERV, "%d", port); error = getaddrinfo(settings.inter, port_buf, &hints, &ai); if (error != 0) { if (error != EAI_SYSTEM) fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error)); else perror("getaddrinfo()"); return 1; } for (next = ai; next; next = next->ai_next) { conn *listen_conn_add; if ((sfd = new_socket(next)) == -1) { freeaddrinfo(ai); return 1; } setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *) &flags, sizeof(flags)); if (is_udp) { maximize_sndbuf(sfd); } else { setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *) &flags, sizeof(flags)); setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *) &ling, sizeof(ling)); setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *) &flags, sizeof(flags)); } if (bind(sfd, next->ai_addr, next->ai_addrlen) == -1) { if (errno != EADDRINUSE) { perror("bind()"); close(sfd); freeaddrinfo(ai); return 1; } close(sfd); continue; } else { success++; if (!is_udp && listen(sfd, 1024) == -1) { perror("listen()"); close(sfd); freeaddrinfo(ai); return 1; } } if (is_udp) { int c; for (c = 0; c < settings.num_threads; c++) { /* this is guaranteed to hit all threads because we round-robin */ dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST, UDP_READ_BUFFER_SIZE, 1); } } else { if (!(listen_conn_add = conn_new(sfd, conn_listening, EV_READ | EV_PERSIST, 1, false, main_base))) { fprintf(stderr, "failed to create listening connection\n"); exit (EXIT_FAILURE); } 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; }