Skip to content

Instantly share code, notes, and snippets.

@yongboy
Created March 4, 2014 05:58
Show Gist options
  • Select an option

  • Save yongboy/9341037 to your computer and use it in GitHub Desktop.

Select an option

Save yongboy/9341037 to your computer and use it in GitHub Desktop.

Revisions

  1. yongboy created this gist Mar 4, 2014.
    140 changes: 140 additions & 0 deletions pong_server.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,140 @@
    /**
    * [email protected]
    * how to compile it:
    * gcc pong_server.c -o pong_server /usr/local/lib/libev.a -lm
    */
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <err.h>
    #include <unistd.h>

    #include "../include/ev.h"

    static int server_port = 8080;

    struct ev_loop *loop;
    typedef struct {
    int fd;
    ev_io ev_read;
    } client_t;

    ev_io ev_accept;

    static void free_res(struct ev_loop *loop, ev_io *ws);

    int setnonblock(int fd) {
    int flags = fcntl(fd, F_GETFL);
    if (flags < 0)
    return flags;

    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0)
    return -1;

    return 0;
    }

    static void read_cb(struct ev_loop *loop, ev_io *w, int revents) {
    client_t *client = w->data;
    int r = 0;
    char rbuff[1024];
    if (revents & EV_READ) {
    r = read(client->fd, &rbuff, 1024);
    }

    if (EV_ERROR & revents) {
    fprintf(stderr, "error event in read\n");
    free_res(loop, w);
    return ;
    }

    if (r < 0) {
    fprintf(stderr, "read error\n");
    ev_io_stop(EV_A_ w);
    free_res(loop, w);
    return;
    }

    if (r == 0) {
    fprintf(stderr, "client disconnected.\n");
    ev_io_stop(EV_A_ w);
    free_res(loop, w);
    return;
    }

    send(client->fd, rbuff, r, 0);
    }

    static void accept_cb(struct ev_loop *loop, ev_io *w, int revents) {
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_fd = accept(w->fd, (struct sockaddr *) &client_addr, &client_len);
    if (client_fd == -1) {
    fprintf(stderr, "the client_fd is NULL !\n");
    return;
    }

    client_t *client = malloc(sizeof(client_t));
    client->fd = client_fd;
    if (setnonblock(client->fd) < 0)
    err(1, "failed to set client socket to non-blocking");

    client->ev_read.data = client;

    ev_io_init(&client->ev_read, read_cb, client->fd, EV_READ);
    ev_io_start(loop, &client->ev_read);
    }

    int main(int argc, char const *argv[]) {
    int ch;
    while ((ch = getopt(argc, argv, "p:")) != -1) {
    switch (ch) {
    case 'p':
    server_port = atoi(optarg);
    break;
    }
    }

    loop = ev_default_loop(0);
    struct sockaddr_in listen_addr;
    int reuseaddr_on = 1;
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0)
    err(1, "listen failed");
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on)) == -1)
    err(1, "setsockopt failed");

    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_addr.s_addr = INADDR_ANY;
    listen_addr.sin_port = htons(server_port);

    if (bind(listen_fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr)) < 0)
    err(1, "bind failed");
    if (listen(listen_fd, 5) < 0)
    err(1, "listen failed");
    if (setnonblock(listen_fd) < 0)
    err(1, "failed to set server socket to non-blocking");

    ev_io_init(&ev_accept, accept_cb, listen_fd, EV_READ);
    ev_io_start(loop, &ev_accept);
    ev_loop(loop, 0);

    return 0;
    }

    static void free_res(struct ev_loop *loop, ev_io *w) {
    client_t *client = w->data;
    if (client == NULL) {
    fprintf(stderr, "the client is NULL !!!!!!");
    return;
    }

    ev_io_stop(loop, &client->ev_read);
    close(client->fd);
    free(client);
    }