问题
客户端业务逻辑如何实现?
与服务设备具体交互细节如何设计?
客户端业务逻辑实现
用户输入处理
- 字符串空格处理,分割获取命令与参数
服务信息处理
- 字符串预处理,分割获取服务命令
- 存储服务命令与设备地址之间的映射(命令字符串 => 地址字符串)
客户端业务逻辑实现 - 用户输入处理
服务端逻辑实现
查询消息处理
- 接收广播,并回复UDP消息
服务命令处理
- 接收 TCP 连接,通过 请求-响应 的模式进行服务
UDP响应模块设计
服务模块设计
TCP 响应模块设计
客户端响应接收
客户端服务端交互实现
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include "utility.h"
#include "addr_mgr.h"
#include "udp_point.h"
#include "tcp_client.h"
#include "type_def.h"
#define BUF_SIZE 64
#define DESC_SIZE 32
#define ADDR_SIZE 16
#define USAGE_SIZE 256
#define DIM(a) sizeof((a)) / sizeof((*a))
typedef struct
{
const char* cmd;
void (*handler)(const char*);
} Handler;
static int GetCharCount(const char* s, int c)
{
int ret = 0;
if(s)
{
while(*s)
{
if(*s == c)
{
ret++;
}
s++;
}
}
return ret;
}
static void ParseCommand(const char* s)
{
const char* desc = s;
const char* addr = desc + DESC_SIZE;
const char* usage = addr + ADDR_SIZE;
int count = 0;
int cnt = 0;
char** arg = NULL;
char** cmd = NULL;
int r = 0;
printf("desc: %s\n", desc);
printf("addr: %s\n", addr);
count = GetCharCount(usage, '\n');
arg = Malloc2d(char, count, BUF_SIZE);
if(arg && (count > 0))
{
r = DivideByChar(usage, '\n', arg, count, BUF_SIZE);
for(int i = 0; i < r; i++)
{
count = GetCharCount(arg[i], ' ') + 1;
cmd = Malloc2d(char, count, BUF_SIZE);
if(cmd && (count > 0))
{
cnt = DivideByChar(arg[i], ' ', cmd, count, BUF_SIZE);
for(int j = 1; j < cnt; j++)
{
AddrMgr_Add(cmd[j], addr);
printf("%s %s\n", cmd[j], addr);
}
}
Free2d(cmd);
}
}
Free2d(arg);
}
void Query_Handler(const char* s)
{
UdpPoint* point = UdpPoint_New(8888);
Message* msg = NULL;
int brd = 1;
char* remote = "255.255.255.255";
int port = 9999;
int i = 0;
if(point)
{
UdpPoint_SetOpt(point, SOL_SOCKET, SO_BROADCAST, &brd, sizeof(brd));
msg = Message_New(TYPE_QUERY, 0, 0, 0, NULL, 0);
if(msg)
{
UdpPoint_SendMsg(point, msg, remote, port);
free(msg);
msg = NULL;
}
while(i < 3)
{
if(UdpPoint_Available(point) > 0)
{
msg = UdpPoint_RecvMsg(point, NULL, NULL);
if(msg)
{
if(msg->type == TYPE_RESPONSE)
{
printf("Find service!\n");
ParseCommand(msg->payload);
i = 0;
free(msg);
msg = NULL;
}
else if(msg->type == TYPE_ERROR)
{
printf("Can NOT find service!\n");
}
}
}
else
{
sleep(1);
i++;
}
}
}
UdpPoint_Del(point);
}
void Touch_Handler(const char* s)
{
if(s && *s)
{
TcpClient* client = TcpClient_New();
char* addr = AddrMgr_Find(s);
Message* msg = NULL;
if(client && addr && TcpClient_Connect(client, addr, 8888))
{
msg = Message_New(TYPE_TOUCH, 0, 0, 0, s, strlen(s) + 1);
if(msg)
{
TcpClient_SendMsg(client, msg);
free(msg);
msg = NULL;
msg = TcpClient_RecvMsg(client);
if(msg && (msg->type == TYPE_RESPONSE))
{
printf("%s\n", msg->payload);
free(msg);
msg = NULL;
}
}
}
TcpClient_Del(client);
}
}
Handler g_handler[] = {
{"query", Query_Handler},
{"touch", Touch_Handler},
};
int main(void)
{
char line[BUF_SIZE] = {0};
char** arg = NULL;
int r = 0;
printf("<<<< This is client demo >>>>\n");
arg = Malloc2d(char, 2, BUF_SIZE);
while(arg)
{
fgets(line, sizeof(line), stdin);
line[strlen(line) - 1] = 0;
if(*line)
{
r = DivideByChar(line, ' ', arg, 2, BUF_SIZE);
for(int i = 0; (i < DIM(g_handler) && (r > 0)); i++)
{
if(strcmp(arg[0], g_handler[i].cmd) == 0)
{
g_handler[i].handler(arg[1]);
break;
}
}
}
}
Free2d(arg);
return 0;
}
response_task.c
#include <stdio.h>
#include "response_task.h"
#include "udp_point.h"
#include "type_def.h"
#define DESC_SIZE 32
#define ADDR_SIZE 16
#define USAGE_SIZE 256
void* Response_Task(const char* arg)
{
UdpPoint* point = NULL;
Message* msg = NULL;
char remote[16] = {0};
int port = 0;
point = UdpPoint_New(9999);
if(point)
{
printf("point = 0x%X\n", point);
while(1)
{
msg = UdpPoint_RecvMsg(point, remote, &port);
if(msg && msg->type == TYPE_QUERY)
{
free(msg);
msg = NULL;
msg = Message_New(TYPE_RESPONSE, 0, 0, 0, NULL, DESC_SIZE + ADDR_SIZE + USAGE_SIZE);
if(msg)
{
strncpy(msg->payload, Service_GetDesc(), DESC_SIZE);
strncpy(msg->payload + DESC_SIZE, Wifi_IpAddr(), ADDR_SIZE);
strncpy(msg->payload + DESC_SIZE + ADDR_SIZE, Service_GetUsage(), USAGE_SIZE);
UdpPoint_SendMsg(point, msg, remote, port);
free(msg);
msg = NULL;
}
else
{
Message m = {TYPE_ERROR};
UdpPoint_SendMsg(point, &m, remote, port);
}
}
else
{
Message m = {TYPE_ERROR};
UdpPoint_SendMsg(point, &m, remote, port);
}
}
UdpPoint_Del(point);
}
return NULL;
}
local_service.h
#ifndef LOCAL_SERVICE_H
#define LOCAL_SERVICE_H
typedef struct
{
float illumination;
float humidity;
float temperature;
int light;
} SvrData;
void Service_Init(void);
const char* Service_GetDesc(void);
const char* Service_GetUsage(void);
SvrData Service_GetData(void);
int Service_SetLight(int on);
#endif
local_service.c
#include "local_service.h"
void Service_Init(void)
{
}
const char* Service_GetDesc(void)
{
return "Environment Service";
}
const char* Service_GetUsage(void)
{
return "Illumination: Ill_Get\n"
"Temperature: Tem_Get\n"
"Humidity: Hum_Get\n"
"Light: Lig_Get Lig_Set_On Lig_Set_Off\n";
}
SvrData Service_GetData(void)
{
SvrData ret = {188, 0.33, 35.6, 1};
return ret;
}
int Service_SetLight(int on)
{
int ret = 1;
printf("set light: %d\n", on);
return ret;
}
service_task.c
#include <stdio.h>
#include "stdlib.h"
#include <string.h>
#include "service_task.h"
#include "tcp_client.h"
#include "tcp_server.h"
#include "local_service.h"
#include "type_def.h"
typedef struct
{
const char* cmd;
void* data;
char* (*handler)(void*);
} Handler;
static char* FormatNumber(float num)
{
char* ret = (char*)malloc(16);
snprintf(ret, 16, "%.2f", num);
return ret;
}
static char* Ill_Get_Handler(void* data)
{
return FormatNumber(Service_GetData().illumination);
}
static char* Tem_Get_Handler(void* data)
{
return FormatNumber(Service_GetData().temperature);
}
static char* Hum_Get_Handler(void* data)
{
return FormatNumber(Service_GetData().humidity);
}
static char* Lig_Get_Handler(void* data)
{
char* ret = (char*)malloc(4);
if(Service_GetData().light)
{
strcpy(ret, "on");
}
else
{
strcpy(ret, "off");
}
return ret;
}
static char* Lig_Set_Handler(void* data)
{
char* ret = (char*)malloc(4);
Service_SetLight((int)data);
if(data)
{
strcpy(ret, "on");
}
else
{
strcpy(ret, "off");
}
return ret;
}
static Handler g_handler[] =
{
{"Ill_Get", NULL, Ill_Get_Handler},
{"Tem_Get", NULL, Tem_Get_Handler},
{"Hum_Get", NULL, Hum_Get_Handler},
{"Lig_Get", NULL, Lig_Get_Handler},
{"Lig_Set_On", (void*)1, Lig_Set_Handler},
{"Lig_Set_Off", (void*)0, Lig_Set_Handler},
};
static int g_handler_size = sizeof(g_handler) / sizeof(*g_handler);
static void Server_Listener_Handler(TcpClient* client, int evt)
{
if(evt == EVT_COON)
{
printf("a client connect\n");
}
else if(evt == EVT_DATA)
{
Message* msg = NULL;
char* s = NULL;
msg = TcpClient_RecvMsg(client);
if(msg && (msg->type == TYPE_TOUCH))
{
printf("service type = %s\n", msg->payload);
for(int i = 0; i < g_handler_size; i++)
{
if(strcmp(msg->payload, g_handler[i].cmd) == 0)
{
s = g_handler[i].handler(g_handler[i].data);
break;
}
}
free(msg);
msg = NULL;
if(s)
{
msg = Message_New(TYPE_RESPONSE, 0, 0, 0, s, strlen(s) + 1);
free(s);
if(msg)
{
TcpClient_SendMsg(client, msg);
free(msg);
}
else
{
Message m = {TYPE_ERROR};
TcpClient_SendMsg(client, &m);
}
free(s);
}
}
else
{
const char* message = "Invalid touch request";
free(msg);
msg = Message_New(TYPE_RESPONSE, 0, 0, 0, message, strlen(message) + 1);
TcpClient_SendMsg(client, &m);
}
}
else if(evt == EVT_CLOSE)
{
printf("a client left\n");
}
return NULL;
}
void* Service_Task(const char* arg)
{
TcpServer* server = NULL;
server = TcpServer_New();
if(server)
{
printf("server = 0x%X\n", server);
Service_Init();
TcpServer_SetListener(server, Server_Listener_Handler);
TcpServer_Start(server, 8888, 5);
TcpServer_DoWork(server);
TcpServer_Del(server);
}
return NULL;
}
实验结果如下图所示
课后思考
服务模块如何获取真实环境信息?