언어: Lua 로직 글루를 사용한 C++.
코드는 적절한 버전의 LuaJIT가 사용되는 경우 Ubuntu x86, Ubuntu x86_64 및 Gentoo x86_64에서 컴파일하고 실행되도록 테스트되었습니다. "정수"를 적절하게 지원하고 복식만 지원하는 Lua에서 자동 변환이 가능하도록 정수가 완료된 후 .0으로 부동 소수점의 강제 서식을 제거하도록 libjansson을 수정했습니다.
libjansson 및 google-glog가 수동으로 빌드된 경우 Ubuntu 12.04 LTS x86_64에서도 컴파일됩니다.
루아짓
리브브
evhttp클라이언트
구글글로그
google-perftools(tcmalloc) - 사소한 소스 및 메이크파일 수정이 포함된 선택사항
libjansson
고용된
libicu - 로컬 패키지 관리자 참조
컬 - 로컬 패키지 관리자 보기
부스트 - 침입 포인터를 자신만의 포인터로 바꾸는 경우 선택 사항입니다.
설치 폴더를 반영하도록 src/Makefile을 수정해야 할 수도 있습니다. 보다 강력한 빌드 시스템이 환영되지만 프로젝트 작성 당시에는 필요하지 않았습니다. (CMake?)
나(@zwagoth)는 여기서 배운 것이 있습니다: 글을 쓸 때 항상 코멘트를 하세요. 이를 보완하기 위해 이해를 돕기 위해 프로그램의 기본 구조를 문서화하겠습니다.
코드베이스의 혼란에 대해 사과드립니다. 이것은 또한 규모와 복잡성에 관계없이 나의 첫 번째 C++ 프로젝트 중 하나였습니다.
프로토콜 메시지, RTB 메시지, 연결 및 연결 해제 등 다양한 기본 이벤트 콜백의 메시지 처리를 위한 거의 모든 핵심 로직이 포함되어 있습니다.
파일에는 처리하는 이벤트의 이름을 딴 익명 함수 테이블이 포함되어 있습니다. 이 파일은 어떠한 상태도 저장해서는 안 되며 논리 저장 영역으로만 간주됩니다. 이 파일의 기본 디자인은 Lua에게 무거운 작업을 강요하지 않고 글루 논리를 허용하고 C++에 대한 더 많은 함수 호출을 희생하면서 Lua 안팎으로 전송되는 데이터의 양을 최소화하는 것입니다.
입력하기 쉽도록 짧은 이름을 사용하여 전역 파일 네임스페이스에 삽입된 4개의 테이블이 있습니다.
u
: 연결/캐릭터(사용자) 기능
s
: 서버/전역 상태 함수
c
: 채널 상태 함수
const
: 오류 ID 및 상수 값
프로토콜 콜백 함수는 두 개의 매개변수, 즉 명령과 연결된 연결과 제공된 json 인수의 테이블 복사본을 허용합니다.
연결은 불투명한 숫자이므로 어떤 방식으로든 수정해서는 안 됩니다. 연결 값을 변경하는 것은 안전하지 않습니다. 당신은 경고를 받았습니다.
채팅 데몬의 시작 및 작동 중에 사용되는 구성 변수의 lua 파일입니다.
최소한의 플래시 정책 서버입니다. Flash를 지원해야 하는 경우 이를 실행합니다. 인라인 정책을 필요에 맞게 맞춤설정하세요.
프로그램 진입점. 백그라운드 스레드 및 컬의 초기화를 다룹니다.
너무 많은 일을 합니다. 코드 흐름은 Server::run()
에서 시작됩니다.
연결 흐름은 다음과 같습니다.
listenCallback handshakeCallback connectionWriteCallback connectionReadCallback connectionwriteCallback
listenCallback
연결별 이벤트 핸들러를 설정하고 흐름을 다음으로 전달합니다.
websocket 핸드셰이크에 대한 읽기를 처리하는 handshakeCallback
.
connectionWriteCallback
연결을 쓸 준비가 되었을 때를 처리하고 항목이 연결에 쓸 큐에 있을 때 활성화됩니다. 버퍼링을 처리합니다.
connectionReadCallback
핸드셰이크 단계가 끝나면 모든 읽기 이벤트를 처리합니다. 모든 프로토콜 구문 분석은 여기에서 발생하며 이 함수 내부에서 명령이 전달되고 실행됩니다.
pingCallback
클라이언트에 대한 ping 이벤트 전송을 처리합니다. 프로토콜이 변경되면 가장 먼저 해야 할 일 중 하나입니다.
connectionTimerCallback
주기적으로 실행되며 연결이 끊어졌는지 확인하고 정리합니다.
runLuaEvent
새로운 마법입니다. 또한 각 명령에 대해 마법이 발생합니다. 여기에서 각 명령이 C++ 코드에서 Lua 코드로 이동됩니다. Lua가 무한 루프에 빠지지 않도록 모든 Lua 상태와 콜백을 처리합니다. Lua 내부의 인쇄 오류를 처리합니다.
이 파일은 채널, 연결, 금지 및 중재와 관련된 모든 상태 데이터를 저장합니다.
로그인 서버가 해당 캐릭터의 존재 여부를 확인하고 이름으로 조회할 수 있는 캐릭터 풀에서 해당 캐릭터를 제외할 때까지 캐릭터 이름을 알 수 없으므로 연결은 식별된 것과 식별되지 않은 것 사이로 분할됩니다.
상태를 디스크에 저장하고 복원하는 작업을 처리합니다.
로그인 요청과 응답을 처리하고 이를 기본 스레드로 다시 전달하는 백그라운드 스레드로 실행됩니다.
직렬화된 로그인 시스템은 글로벌 로그인 대기열을 사용합니다. 이 점은 상당히 개선될 수 있습니다.
컬_멀티(curl_multi)로 변환하는 것이 좋지만 libev와의 재미있는 상호 작용이나 많은 블라인드 폴링이 필요합니다. 스레딩으로 인해 대기열에 액세스하기 전에 대기열을 잠가야 합니다.
기본 채널 클래스는 수명 동안 채널에 대한 상태 데이터를 유지합니다. 채널과 관련된 모든 하위 수준 작업은 Lua의 후크를 통해 이 파일에서 발생합니다. 일반적으로 인스턴스 수명을 관리하기 위해 침입 포인터로 래핑됩니다.
여기에서 json의 채널 직렬화 및 역직렬화가 발생합니다.
모든 연결 네트워킹 및 디버그 Lua 상태를 처리합니다.
꼬임 목록, 상태, 상태 메시지 및 성별을 유지합니다.
무시 및 친구 목록을 유지합니다.
연결 제한당 핸들입니다.
출력 데이터의 버퍼링이 발생하는 곳입니다.
일반적으로 인스턴스 수명을 관리하기 위해 침입 포인터를 사용하여 전달됩니다.
어떤 채널이 가입되어 있는지에 대한 내부 목록을 유지합니다. 이는 실제 채널 사용자 목록과 동기화되어 유지되어야 합니다.
이 파일은 사용자 정의보다 원시 속도가 필요한 몇 가지 기능용으로 예약되어 있습니다. 로그인( IDN
) 명령을 처리합니다. 디버그( ZZZ
) 명령을 처리합니다. 검색( FKS
) 명령을 처리합니다.
Lua 파일의 s
카테고리에 속하는 모든 Lua 래퍼 명령입니다.
Lua 파일의 u
카테고리에 속하는 모든 Lua 래퍼 명령입니다.
Lua 파일의 c
범주에 속하는 모든 Lua 래퍼 명령입니다.
Lua 파일의 const
범주에 속하는 모든 Lua 래퍼 값입니다.
오류 메시지 및 정의.
오류 및 유형 검사를 위해 정의된 매크로를 사용하세요! 이는 잘못된 유형이 예기치 않게 경량 데이터로 함수에 전달되는 경우 충돌을 방지하는 유일한 방법입니다.
Lua 스택이 균형을 이루고 있는지 확인하세요. 나는 이것이 사실인지 확인하기 위해 열심히 노력했지만 실수는 쉽습니다.
테이블을 Lua 코드로 반환하지 마세요. 테이블을 만드는 데 비용이 많이 들고 사용 기간이 짧은 경우가 많습니다. 최선의 판단을 통해 함수 호출 비용과 테이블 구축 비용의 균형을 맞추세요.
문자열을 Lua에 불필요하게 전달하지 마세요. 메모리 복사로 인해 비용이 많이 들 수 있습니다.
lua가 여러 반환 값을 기본 기능으로 받아들이는 남용. 위의 두 가지 참고 사항을 참조하세요.
푸시 전용 Redis 스레드를 처리합니다. redis 명령과 해당 반환 값을 둘러싼 작은 래퍼입니다.
입력 대기열을 사용하여 명령을 수신합니다. 명령은 주기적으로 실행되며 신뢰성이 보장되지 않습니다. 비활성화할 수 있으며 비활성화되면 입력을 무시합니다.
gdb는 이 애플리케이션을 디버깅하는 데 적합합니다. tcmalloc 및 LuaJIT의 JIT 섹션을 비활성화하면 충돌 디버깅에 큰 도움이 됩니다(tcmalloc은 약간의 사소한 힙 손상을 숨길 수 있습니다).
tcmalloc의 메모리 프로파일링 도구는 매우 훌륭합니다. 사용 방법에 대한 자세한 내용은 tcmalloc 설명서를 참조하세요.