우선 명령어를 실행할 함수를 만들어보자. 위의 commands.d 의 echo 정의를 보면 echo 명령어에 대한 함수의 이름은 echoCommand 이다.
echoCommand 를 찾기 위해 grep -n echoCommand -r 을 실행하면
(스크린샷의 경우, 이미 커스텀 명령어를 정의한 이후 캡처하였기 떄문에 커스텀 명령어가 함께 나오고 있습니다.)
echoCommand 함수는 server.c 파일에 정의되어 있으며 server.h 에 선언되어 있음을 알 수 있다.
따라서 커스텀 명령어를 만들때도 server.c 파일에 함수를 정의하고 server.h 에 선언해야 한다.
echoCommand 의 정의를 보면 addReplyBulk 함수를 통해, 사용자의 입력을 똑같이 돌려주는 기능을 구현하고 있음을 확인할 수 있다.
조금 더 해당 함수를 분석해보자.
addReplyBulk 함수의 경우, networking.c 에 정의되어 있는데 서버에서 클라이언트에게 데이터 객체를 벌크 형식 (바이너리 형식)으로 응답할 때 사용하는 함수이다.
RESP의 Bulk 형식
Redis Serialization Protocol(RESP)에서는 클라이언트가 명령을 서버에 벌크 문자열 배열로 보내고, 서버는 RESP 형식으로 응답한다.
여기서 RESP 문자열은 simple, bulk 유형으로 나뉘는데 이 중 bulk 유형의 경우 모든 바이너리 데이터를 포함할 수 있는 유형이다.
벌크 문자열은 다음과 같은 형식으로 표현된다.
1
$<length>\r\n<data>\r\n
$로 시작
데이터의 바이트 길이
CRLF(\r\n) 줄바꿈
실제 데이터
마지막 CRLF(\r\n) 줄바꿈
따라서 addReplyBulk 경우, 이러한 형식에 맞게 응답을 구성한다.
addReplyBulkLen 함수로 $<length>\r\n 부분 추가
addReply 함수로 실제 데이터 <data> 추가
addReplyProto 함수로 마지막 \r\n 추가
인자로 들어가는 client 구조체의 경우, server.h 에 정의되어 있다.
이 구조체는 클라이언트의 연결 정보와 상태를 저장한다.
따라서 c->argv[1] 은 명령어 다음에 오는 첫 번째 인자를 의미하며, 예를 들어 echo hello 라는 명령이 입력되면 argv[1] 은 hello 가 된다.
{MAKE_CMD("echoPunchDrunkard","Returns the given string. (custom)","O(1)","1.0.0",CMD_DOC_NONE,NULL,NULL,"connect ion",COMMAND_GROUP_CONNECTION,ECHO_History,0,ECHO_Tips,0,echoPunchDrunkard,2,CMD_LOADING|CMD_STALE|CMD_FAST,ACL_C ATEGORY_CONNECTION,ECHO_Keyspecs,0,NULL,1),.args=ECHO_Args},