问题
Response Task 和 Service Task 的业务逻辑如何实现?客户端如何实现?
再论交互流程
交互详细设计 (Message::payload)
客户端主动发起服务查询 (局域网广播)
服务设备能够将自身提供的服务信息及用法返回 (字符串描述)
客户端根据收到的服务用法向设备发起请求 (字符串描述)
服务设备接收命令并匹配服务,并返回服务结果 (字符串描述)
交互示例
关键问题
"Touch Lig_Set_On" 怎么知道给哪一个服务设备发送命令?
地址管理器模块
每个服务设备在回复服务查询消息时,会附带服务地址;因此,记录服务命令与设备地址之间的映射关系。
基础功能模块
客户端初步实现
utility.h
#ifndef UTILITY_H
#define UTILITY_H
#define Malloc2d(type, row, col) \
({ \
type** ret = NULL; \
type* p = NULL; \
\
if((row > 0) && (col > 0)) \
{ \
ret = (type**)malloc(row * sizeof(type*)); \
\
if(ret) \
{ \
p = (type*)malloc(row * col * sizeof(type)); \
\
if(p) \
{ \
int i = 0; \
\
for(i = 0; i < row; i++) \
{ \
ret[i] = p + i * col; \
} \
} \
else \
{ \
free(ret); \
ret = NULL; \
} \
} \
} \
\
ret; \
})
void Free2d(void* p);
char* FormatByChar(const char* src, char c);
int DivideByChar(const char* src, char c, char** arg, int row, int col);
#endif
utility.c
#include <string.h>
#include <stdlib.h>
#include "utility.h"
void Free2d(void* p)
{
void** pp = p;
if( pp && *pp )
{
free(*pp);
}
free(pp);
}
char* FormatByChar(const char* src, char c) // O(n)
{
int i = 0;
int j = 0;
int len = src ? strlen(src) : 0;
int flag = 0;
char* ret = len ? malloc(len + 1) : NULL;
if( ret )
{
while( (i < len) && (src[i] == c) ) i++;
while( i < len )
{
if( src[i] != c )
{
ret[j++] = src[i];
flag = 0;
}
else
{
if( !flag )
{
ret[j++] = src[i];
flag = 1;
}
}
i++;
}
if( flag ) j--;
ret[j] = 0;
}
return ret;
}
int DivideByChar(const char* line, char c, char** argv, int row, int col)
{
int ret = 0;
if( line && argv )
{
int i = 0;
int j = 0;
char* buf = FormatByChar(line, c);
int len = buf ? strlen(buf) : 0;
if( len )
{
buf[len] = c;
for(i=0, j=0; (i<=len) && (ret<row); i++)
{
if( buf[i] == c )
{
int k = (i-j < col) ? i-j : col;
strncpy(argv[ret], buf+j, k);
argv[ret][(k < col) ? k : (k-1)] = 0;
j = i + 1;
ret++;
}
}
free(buf);
}
}
return ret;
}
addr_mgr.h
#ifndef ADDR_MGR_H
#define ADDR_MGR_H
int AddrMgr_Add(const char* cmd, const char* addr);
char* AddrMgr_Find(const char* cmd);
void AddrMgr_Remove(const char* cmd);
void AddrMgr_Clear(void);
#endif
addr_mgr.c
#include <stdlib.h>
#include <string.h>
#include "addr_mgr.h"
#include "list.h"
#define CMD_SIZE 48
#define ADDR_SIZE 16
typedef struct
{
struct list_head head;
char cmd[CMD_SIZE];
char addr[ADDR_SIZE];
} SrvAddr;
static LIST_HEAD(g_srvList);
int AddrMgr_Add(const char* cmd, const char* addr)
{
int ret = 0;
if(cmd && addr)
{
char* ip = NULL;
int cmd_len = strlen(cmd);
int addr_len = strlen(addr);
int cmd_copy_len = (cmd_len < CMD_SIZE) ? cmd_len : (CMD_SIZE - 1);
int addr_copy_len = (addr_len < ADDR_SIZE) ? addr_len : (ADDR_SIZE - 1);
if(ip = AddrMgr_Find(cmd))
{
ret = !!strncpy(ip, addr, addr_copy_len);
ip[addr_copy_len] = 0;
}
else
{
SrvAddr* node = (SrvAddr*)malloc(sizeof(SrvAddr));
if(ret = !!node)
{
strncpy(node->cmd, cmd, cmd_copy_len);
strncpy(node->addr, addr, addr_copy_len);
node->cmd[cmd_copy_len] = 0;
node->addr[addr_copy_len] = 0;
list_add((struct list_head*)node, &g_srvList);
}
}
}
return ret;
}
char* AddrMgr_Find(const char* cmd)
{
char* ret = NULL;
if(cmd)
{
struct list_head* pos = NULL;
list_for_each(pos, &g_srvList)
{
SrvAddr* node = (SrvAddr*)pos;
if(strcmp(node->cmd, cmd) == 0)
{
ret = node->addr;
break;
}
}
}
return ret;
}
void AddrMgr_Remove(const char* cmd)
{
char* addr = NULL;
if(addr = AddrMgr_Find(cmd))
{
SrvAddr* node = container_of(addr, SrvAddr, addr);
if(node)
{
list_del((struct list_head*)node);
free(node);
}
}
}
void AddrMgr_Clear(void)
{
while(!list_empty(&g_srvList))
{
struct list_head* next = g_srvList.next;
list_del((struct list_head*)next);
free(next);
}
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utility.h"
#include "addr_mgr.h"
void test1(void)
{
char** arg = Malloc2d(char, 3, 10);
strcpy(arg[0], "Dephi");
strcpy(arg[1], "Tang");
strcpy(arg[2], "D.T.");
for(int i = 0; i < 3; i++)
{
printf("arg[%d] = %s\n", i, arg[i]);
}
Free2d(arg);
}
void test2(void)
{
const char* src = " ab c d ";
char** arg = Malloc2d(char, 5, 10);
int num = 0;
char* res = FormatByChar(src, ' ');
printf("res = *%s*\n", res);
num = DivideByChar(src, ' ', arg, 5, 10);
for(int i = 0; i < num; i++)
{
printf("arg[%d] = *%s*\n", i, arg[i]);
}
Free2d(arg);
}
void test3(void)
{
char* cmd[] = {"Dephi", "Tang", "D.T."};
char* addr[] = {"1.1.1.1", "2.2.2.2", "255.255.255.255"};
for(int i = 0; i < 3; i++)
{
AddrMgr_Add(cmd[i], addr[i]);
}
for(int i = 0; i < 3; i++)
{
printf("cmd: *%s*, addr: *%s*\n", cmd[i], AddrMgr_Find(cmd[i]));
}
printf("\n-------------------------------------------\n");
AddrMgr_Remove(cmd[1]);
for(int i = 0; i < 3; i++)
{
printf("cmd: *%s*, addr: *%s*\n", cmd[i], AddrMgr_Find(cmd[i]));
}
printf("\n-------------------------------------------\n");
AddrMgr_Add(cmd[2], "3.3.3.3");
for(int i = 0; i < 3; i++)
{
printf("cmd: *%s*, addr: *%s*\n", cmd[i], AddrMgr_Find(cmd[i]));
}
printf("\n-------------------------------------------\n");
AddrMgr_Clear();
for(int i = 0; i < 3; i++)
{
printf("cmd: *%s*, addr: *%s*\n", cmd[i], AddrMgr_Find(cmd[i]));
}
}
int main(void)
{
test1();
test2();
test3();
return 0;
}
测试结果如下图所示
课后思考
客户端业务逻辑如何实现?与服务设备具体交互细节如何设计?