做游戏行业的大神众多。我是做应用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++了。嘎嘎。