做游戏行业的大神众多。我是做应用server的,小打小闹,现在到处流行大数据,分布式。都是伪的。。做应用服务器开发的大神,没听说多。做webserver的一大堆电商。。只有做游戏服务器的比较多。基本上都是从做游戏架构等方面,学习开发应用server。


skynet是云风用c和lua写的,正好准备学习lua,一起看了。研究下。


本文纯属记录。毫无技术含量,阅读需谨慎。

github下载,然后看源码,都是没文档的东西,自己慢慢琢磨。

skynet-src文件夹。

socket_poll.h文件

#ifndef socket_poll_h
#define socket_poll_h
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
  


这个直接在h文件就实现了代码。

#ifndef poll_socket_kqueue_h
#define poll_socket_kqueue_h
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
  

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 
#include 
#include 
#include 
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++了。嘎嘎。