cmd_server.c
/*编译: gcc cmd_server.c -lpthread */ #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <pthread.h> #include <stdarg.h> #include <regex.h> #include <stdbool.h> #include <errno.h>#define SOCKET_PORT_CMD_CLIENT 2001 #define SOCKET_PORT_CMD_SERVER 2002 #define LOCAL_ADDRESS ("127.0.0.1") #define RECV_BUFFER_LEN 512#define CMD_ELEMENT_MAX_LEN 128 #define CMD_ELEMENT_MAX_NUM 30 typedef struct {int socketFd;struct sockaddr_in stRemoteAddr; }RECV_SOCK_DATA;typedef struct {char szBuffer[CMD_ELEMENT_MAX_NUM][CMD_ELEMENT_MAX_LEN + 1];int strNum; }CMD_S;typedef int (*Callback)(CMD_S *pstCmd); typedef struct {CMD_S stCmd;Callback pfCallBack; }CMD_INFO_S;typedef enum {CMD_TYPE_PARAM_DEC,CMD_TYPE_PARAM_HEX,CMD_TYPE_PARAM_STRING,CMD_TYPE_PARAM_FLOAT,CMD_TYPE_CHAR,CMD_TYPE_UNKNOWN, }CMD_TYPE_E;typedef struct {regex_t stFloat; /* 浮点数正则 */regex_t stDec; /* 整数正则 */ }CMD_MATCH_RULE_S;static CMD_MATCH_RULE_S g_stMatchRule; /* 正则匹配规则合集 */CMD_INFO_S *pstCmdInfo = NULL; RECV_SOCK_DATA *pstSockInfo = NULL; static int cmdCount = 0; void resultToClient(const char *pcFormat, ...) {va_list stVaList = {0};int u32InfoLen = 0;char szBuffer[RECV_BUFFER_LEN] = {0};va_start(stVaList, pcFormat);u32InfoLen += vsnprintf(szBuffer, RECV_BUFFER_LEN, pcFormat, stVaList);va_end(stVaList);printf("send msg:%s\n", szBuffer);if(-1 == sendto(pstSockInfo->socketFd, szBuffer, strlen(szBuffer), 0, (struct sockaddr*)&pstSockInfo->stRemoteAddr, (socklen_t)sizeof(pstSockInfo->stRemoteAddr))){printf("sendto msg:%s fail,errno:%d\n", szBuffer, errno);}return; } int add(CMD_S *pstCmd) {resultToClient("%s + %s = %d\n", pstCmd->szBuffer[3], pstCmd->szBuffer[4], atoi(pstCmd->szBuffer[3]) + atoi(pstCmd->szBuffer[4]));return 0; } int sub(CMD_S *pstCmd) {resultToClient("%s - %s = %d\n", pstCmd->szBuffer[3], pstCmd->szBuffer[4], atoi(pstCmd->szBuffer[3]) - atoi(pstCmd->szBuffer[4]));return 0; } static CMD_TYPE_E cmd_cli_GetClientElementType(char *pcParam) {if(!pcParam){return CMD_TYPE_UNKNOWN;}if((0 == strncmp(pcParam, "0x", strlen("0x"))) || (0 == strncmp(pcParam, "0X", strlen("0X")))){return CMD_TYPE_PARAM_HEX;}else if(0 == regexec(&g_stMatchRule.stDec, pcParam, 0, NULL, 0)){return CMD_TYPE_PARAM_DEC;}else if(0 == regexec(&g_stMatchRule.stFloat, pcParam, 0, NULL, 0)){return CMD_TYPE_PARAM_FLOAT;}return CMD_TYPE_CHAR; }static CMD_TYPE_E cmd_cli_GetServerElementType(char *pcParam) {if(!pcParam){return CMD_TYPE_UNKNOWN;}if(0 == strncmp(pcParam, "DEC", strlen("DEC"))){return CMD_TYPE_PARAM_DEC;}else if(0 == strncmp(pcParam, "HEX", strlen("HEX"))){return CMD_TYPE_PARAM_HEX;}else if(0 == strncmp(pcParam, "STRING", strlen("STRING"))){return CMD_TYPE_PARAM_STRING;}else if(0 == strncmp(pcParam, "FLOAT", strlen("FLOAT"))){return CMD_TYPE_PARAM_FLOAT;}return CMD_TYPE_CHAR; } static bool cmd_param_Match(CMD_S *pstClientCmd, CMD_S *pstServerCmd) {int u32Index = 0;CMD_TYPE_E enClientElementType, enServerElementType;if(!pstClientCmd || !pstServerCmd){printf("Input param is null\n");return false;}if(pstClientCmd->strNum != pstServerCmd->strNum){return false;}for(u32Index = 0; u32Index < pstClientCmd->strNum; u32Index++){enClientElementType = cmd_cli_GetClientElementType(pstClientCmd->szBuffer[u32Index]);enServerElementType = cmd_cli_GetServerElementType(pstServerCmd->szBuffer[u32Index]);if(CMD_TYPE_CHAR == enServerElementType){/* POSIX 系统 */if (0 != strcasecmp(pstClientCmd->szBuffer[u32Index], pstServerCmd->szBuffer[u32Index])){return false;}}else if((CMD_TYPE_PARAM_DEC == enServerElementType) || (CMD_TYPE_PARAM_HEX == enServerElementType) || (CMD_TYPE_PARAM_FLOAT == enServerElementType)){/*元素是10进制或者16进制、小数,类型不同,匹配失败*/if(enClientElementType != enServerElementType){return false;}}else if(CMD_TYPE_PARAM_STRING == enServerElementType){/*server命令的元素是字符串参数类型,如果client命令的元素不是字符串,匹配失败*/if(CMD_TYPE_CHAR != enClientElementType){return false;}}}return true; }void * recvMsgFunc(void * arg) {RECV_SOCK_DATA *data = (RECV_SOCK_DATA *)arg; #if 0CMD_INFO_S stCmdInfo;stCmdInfo.pfCallBack = add; #endifint u32RecvLen = 0;char szBuffer[RECV_BUFFER_LEN];CMD_S stCmd;int i32RecvLen = 0;int u32AddrLen = 0;struct sockaddr_in stRemoteAddr = {0};char *str_ptr;char *token;int paramNum = 0;bool bMatch = false;while(1){memset(szBuffer, 0, RECV_BUFFER_LEN);memset(&stCmd, 0, sizeof(CMD_S)); u32AddrLen = sizeof(stRemoteAddr);i32RecvLen = recvfrom(data->socketFd, szBuffer, RECV_BUFFER_LEN, 0, (struct sockaddr *)&stRemoteAddr, &u32AddrLen);if(i32RecvLen > 0){printf("recv msg:%s\n", szBuffer);paramNum = 0;str_ptr = szBuffer;while(NULL != (token = strsep(&str_ptr, " "))){printf("token:%s\n", token);memcpy(stCmd.szBuffer[paramNum++], token, strlen(token));stCmd.strNum += 1;}bMatch = false;for(int i = 0; i < cmdCount; i++){if (cmd_param_Match(&stCmd, &pstCmdInfo[i].stCmd)){pstCmdInfo[i].pfCallBack(&stCmd);bMatch = true;break; }}if (!bMatch){resultToClient("no support cmd in server\n");}}}return NULL; } int main(int argc, char *argv[]) { int opt = 0;int socketFd = -1;struct sockaddr_in stAddr;struct sockaddr_in stClientAddr;struct timeval stTimeInterval = {3,0};int recvlen = 0;int addrlen = 0;struct sockaddr_in stRemoteAddr = {0};char szBuffer[RECV_BUFFER_LEN] = {0};RECV_SOCK_DATA stSockInfo;pthread_t theadID;CMD_INFO_S stInfos[] = {{ {{"st", "cal", "add", "DEC<a[0~10]>", "DEC<b[0~10]>"}, 5}, add },{ {{"st", "cal", "sub", "DEC<a[0~10]>", "DEC<b[0~10]>"}, 5}, sub },};pstCmdInfo = stInfos;cmdCount = sizeof(stInfos) / sizeof(stInfos[0]);if (regcomp(&g_stMatchRule.stDec, "^-?[0-9]+$", REG_NOSUB | REG_EXTENDED) != 0){printf("precompiled DEC failed\n");return -1;}if (regcomp(&g_stMatchRule.stFloat, "^-?[0-9]+\\.[0-9]+$", REG_NOSUB | REG_EXTENDED) != 0){printf("precompiled FLOAT failed\n");return -1;}if (0 > (socketFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))){printf("create socket error, errno(%d)\n",errno);return -1;}memset(&stAddr, 0, sizeof(stAddr));stAddr.sin_family = AF_INET;stAddr.sin_port = htons(SOCKET_PORT_CMD_SERVER);stAddr.sin_addr.s_addr = inet_addr(LOCAL_ADDRESS);if(0 != setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt, sizeof(opt))){printf("setsockopt error, errno(%d)\n",errno);return -1;}if(0 > bind(socketFd, (struct sockaddr*)&stAddr, sizeof(struct sockaddr))){printf("bind error, errno(%d)\n",errno);return -1;}if(0 != setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &stTimeInterval, sizeof(struct timeval))){printf("setsockopt error, errno(%d)\n",errno);return -1;}memset(&stSockInfo, 0, sizeof(stSockInfo));stSockInfo.socketFd = socketFd;stSockInfo.stRemoteAddr.sin_family = AF_INET;stSockInfo.stRemoteAddr.sin_port = htons(SOCKET_PORT_CMD_CLIENT);pstSockInfo = &stSockInfo;if (0 != pthread_create(&theadID, NULL, recvMsgFunc, (void*)&stSockInfo)){perror("create thread failed\n");return -1;}pthread_detach(theadID);while(1){sleep(200);}printf("recv error\n");return 0; }