研究下skynet,雲風大神的開源框架

做遊戲行業的大神衆多。我是做應用server的,小打小鬧,現在到處流行大數據,分佈式。都是僞的。。做應用服務器開發的大神,沒聽說多。做webserver的一大堆電商。。只有做遊戲服務器的比較多。基本上都是從做遊戲架構等方面,學習開發應用server。


skynet是雲風用c和lua寫的,正好準備學習lua,一起看了。研究下。


本文純屬記錄。毫無技術含量,閱讀需謹慎。

github下載,然後看源碼,都是沒文檔的東西,自己慢慢琢磨。

skynet-src文件夾。

socket_poll.h文件

#ifndef socket_poll_h
#define socket_poll_h
#include <stdbool.h>
typedef int poll_fd;
struct event {
    void * s;
    bool read;
    bool write;
};
static bool sp_invalid(poll_fd fd);
static poll_fd sp_create();
static void sp_release(poll_fd fd);
static int sp_add(poll_fd fd, int sock, void *ud);
static void sp_del(poll_fd fd, int sock);
static void sp_write(poll_fd, int sock, void *ud, bool enable);
static int sp_wait(poll_fd, struct event *e, int max);
static void sp_nonblocking(int sock);
#ifdef __linux__
#include "socket_epoll.h"
#endif
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
#include "socket_kqueue.h"
#endif
#endif

作爲一個庫,要考慮的多,這裏是poll,還有kqueue和epoll,不同的系統用的不同,就得都加上。這個現在都通用,地球人都知道,不解釋。

#ifndef poll_socket_epoll_h
#define poll_socket_epoll_h
#include <netdb.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
static bool
sp_invalid(int efd) {
    return efd == -1;
}
static int
sp_create() {
    return epoll_create(1024);
}
static void
sp_release(int efd) {
    close(efd);
}
static int
sp_add(int efd, int sock, void *ud) {
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.ptr = ud;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev) == -1) {
        return 1;
    }
    return 0;
}
static void
sp_del(int efd, int sock) {
    epoll_ctl(efd, EPOLL_CTL_DEL, sock , NULL);
}
static void
sp_write(int efd, int sock, void *ud, bool enable) {
    struct epoll_event ev;
    ev.events = EPOLLIN | (enable ? EPOLLOUT : 0);
    ev.data.ptr = ud;
    epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev);
}
static int
sp_wait(int efd, struct event *e, int max) {
    struct epoll_event ev[max];
    int n = epoll_wait(efd , ev, max, -1);
    int i;
    for (i=0;i<n;i++) {
        e[i].s = ev[i].data.ptr;
        unsigned flag = ev[i].events;
        e[i].write = (flag & EPOLLOUT) != 0;
        e[i].read = (flag & EPOLLIN) != 0;
    }
    return n;
}
static void
sp_nonblocking(int fd) {
    int flag = fcntl(fd, F_GETFL, 0);
    if ( -1 == flag ) {
        return;
    }
    fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}
#endif


這個直接在h文件就實現了代碼。

#ifndef poll_socket_kqueue_h
#define poll_socket_kqueue_h
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/event.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static bool
sp_invalid(int kfd) {
    return kfd == -1;
}
static int
sp_create() {
    return kqueue();
}
static void
sp_release(int kfd) {
    close(kfd);
}
static void
sp_del(int kfd, int sock) {
    struct kevent ke;
    EV_SET(&ke, sock, EVFILT_READ, EV_DELETE, 0, 0, NULL);
    kevent(kfd, &ke, 1, NULL, 0, NULL);
    EV_SET(&ke, sock, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
    kevent(kfd, &ke, 1, NULL, 0, NULL);
}
static int
sp_add(int kfd, int sock, void *ud) {
    struct kevent ke;
    EV_SET(&ke, sock, EVFILT_READ, EV_ADD, 0, 0, ud);
    if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1) {
        return 1;
    }
    EV_SET(&ke, sock, EVFILT_WRITE, EV_ADD, 0, 0, ud);
    if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1) {
        EV_SET(&ke, sock, EVFILT_READ, EV_DELETE, 0, 0, NULL);
        kevent(kfd, &ke, 1, NULL, 0, NULL);
        return 1;
    }
    EV_SET(&ke, sock, EVFILT_WRITE, EV_DISABLE, 0, 0, ud);
    if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1) {
        sp_del(kfd, sock);
        return 1;
    }
    return 0;
}
static void
sp_write(int kfd, int sock, void *ud, bool enable) {
    struct kevent ke;
    EV_SET(&ke, sock, EVFILT_WRITE, enable ? EV_ENABLE : EV_DISABLE, 0, 0, ud);
    if (kevent(kfd, &ke, 1, NULL, 0, NULL) == -1) {
        // todo: check error
    }
}
static int
sp_wait(int kfd, struct event *e, int max) {
    struct kevent ev[max];
    int n = kevent(kfd, NULL, 0, ev, max, NULL);
    int i;
    for (i=0;i<n;i++) {
        e[i].s = ev[i].udata;
        unsigned filter = ev[i].filter;
        e[i].write = (filter == EVFILT_WRITE);
        e[i].read = (filter == EVFILT_READ);
    }
    return n;
}
static void
sp_nonblocking(int fd) {
    int flag = fcntl(fd, F_GETFL, 0);
    if ( -1 == flag ) {
        return;
    }
    fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}
#endif

kqueue還沒有機會用過,一直用的ubuntu系統,用的epoll,這個的寫法,和select很像。

poll對應的c文件,怎麼找不到。沒實現。哦。原來這個poll是調用epoll和kqueue的,沒有用poll event。。。

#ifndef _RWLOCK_H_
#define _RWLOCK_H_
struct rwlock {
    int write;
    int read;
};
static inline void
rwlock_init(struct rwlock *lock) {
    lock->write = 0;
    lock->read = 0;
}
static inline void
rwlock_rlock(struct rwlock *lock) {
    for (;;) {
        while(lock->write) {
            __sync_synchronize();
        }
        __sync_add_and_fetch(&lock->read,1);
        if (lock->write) {
            __sync_sub_and_fetch(&lock->read,1);
        } else {
            break;
        }
    }
}
static inline void
rwlock_wlock(struct rwlock *lock) {
    while (__sync_lock_test_and_set(&lock->write,1)) {}
    while(lock->read) {
        __sync_synchronize();
    }
}
static inline void
rwlock_wunlock(struct rwlock *lock) {
    __sync_lock_release(&lock->write);
}
static inline void
rwlock_runlock(struct rwlock *lock) {
    __sync_sub_and_fetch(&lock->read,1);
}
#endif


__sync_synchronize。。。這是神馬函數,加鎖,我都沒用過,這些個函數。。linux原子操作函數族。不知道boost的Atomic操作,和這個相同否。先記住,以後深入理解這個家族的函數把。

#ifndef SKYNET_ENV_H
#define SKYNET_ENV_H
const char * skynet_getenv(const char *key);
void skynet_setenv(const char *key, const char *value);
void skynet_env_init();
#endif

這麼看就是一個key-value的,就像設置配置文件一樣。

#include "skynet_env.h"
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <assert.h>
struct skynet_env {
    int lock;
    lua_State *L;
};
static struct skynet_env *E = NULL;
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
const char *
skynet_getenv(const char *key) {
    LOCK(E)
    lua_State *L = E->L;
                                                    
    lua_getglobal(L, key);
    const char * result = lua_tostring(L, -1);
    lua_pop(L, 1);
    UNLOCK(E)
    return result;
}
void
skynet_setenv(const char *key, const char *value) {
    LOCK(E)
                                                    
    lua_State *L = E->L;
    lua_getglobal(L, key);
    assert(lua_isnil(L, -1));
    lua_pop(L,1);
    lua_pushstring(L,value);
    lua_setglobal(L,key);
    UNLOCK(E)
}
void
skynet_env_init() {
    E = malloc(sizeof(*E));
    E->lock = 0;
    E->L = luaL_newstate();
}


終於用到lua了。。對於我這種lua小白,得好好看看。看樣子,就是把key-value這個map結構放到lua中,相當於調用c++的std map了。。雲風大神,看樣子拋棄c++了。嘎嘎。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章