做遊戲行業的大神衆多。我是做應用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++了。嘎嘎。