【AUTOSAR COM Eth】Service Discovery (SD) 模块技术解析
文章目录
- 一、基本概念
- 1.1 SD模块定位
- 1.2 协议规范
- 1.3 模块架构
- 二、工作原理详解
- 2.1 整体流程
- 2.2 核心交互流程
- 2.2.1 服务发现流程
- 2.2.2 事件组订阅流程
- 三、核心数据结构解析
- 3.1 协议头结构(Sd_HeaderType)
- 3.2 服务条目结构(Sd_Type1EntryType)
- 3.3 事件组条目结构(Sd_Type2EntryType)
- 3.4 会话控制结构(Sd_SessionIdCtrlType)
- 3.5 发送队列结构(Sd_SendQueueType)
- 四、重要函数功能解析
- 4.1 模块初始化(Sd_Init)
- 4.2 主处理函数(Sd_MainFunction)
- 4.3 消息解析(Sd_ParseRxMessage)
- 4.4 服务生命周期管理
- 4.4.1 服务下线处理(Sd_ServerServiceDownPhaseHandle)
- 4.4.2 初始等待处理(Sd_ServerServiceInitialWaitPhaseHandle)
- 4.5 事件组订阅管理
- 4.5.1 订阅处理(Sd_RxSubscribeEventgroupHandle)
- 4.5.2 多播控制(Sd_FanOutMulticastUnicastCtrlAddClient)
- 五、内存管理机制
- 5.1 内存池设计
- 5.2 内存操作函数
- 六、网络协议处理
- 6.1 IP地址检查(Sd_IsIpAddrInSameSubset)
- 6.2 端点选项处理
- 6.2.1 IPv4端点构建
- 6.2.2 IPv6支持
- 七、状态机实现
- 7.1 服务器状态机
- 7.2 客户端状态机
- 八、错误处理机制
- 8.1 错误报告
- 8.2 重启处理
- 九、应用案例分析
- 9.1 服务发现场景
- 9.2 事件组订阅场景
- 9.3 网络异常处理
- 十、性能优化措施
- 10.1 内存分配优化
- 10.2 状态机优化
- 10.3 发送队列优化
- 十一、安全机制实现
- 11.1 选项安全检查
- 11.2 会话ID管理
- 11.3 重启检测
- 十二、配置管理机制
- 12.1 动态配置支持
- 12.2 配置选项构建
- 十三、版本特性实现
- 13.1 多播发送优化
- 13.2 会话ID管理改进
- 十四、编译配置管理
- 14.1 条件编译控制
- 14.2 特性开关
- 十五、运行时数据结构
- 15.1 服务器运行时(Sd_ServerServiceRTType)
- 15.2 客户端运行时(Sd_ClientServiceRTType)
- 十六、接口函数实现
- 16.1 服务状态设置(Sd_ServerServiceSetState)
- 16.2 事件组状态设置(Sd_ConsumedEventGroupSetState)
- 十七、网络适配层交互
- 17.1 套接字管理
- 17.2 地址分配处理
- 十八、消息打包发送
- 18.1 消息打包(Sd_PackageMessage)
- 18.2 发送调度(Sd_TransmitMessage)
- 十九、异常处理机制
- 19.1 消息格式检查(Sd_OptionFormatCheck)
- 19.2 消息冲突检查(Sd_OptionsConflictCheck)
- 二十、高级特性实现
- 20.1 会话ID管理
- 20.2 重试机制(SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE)
- 20.3 路由控制
- 二十一、典型应用场景
- 21.1 服务发现
- 21.2 事件组订阅
- 21.3 网络异常恢复(续)
- TCP连接异常恢复
- UDP连接异常恢复
- 21.4 消息重传机制
- 订阅事件组重试
- 21.5 安全检查机制
- IP地址子网检查
- 21.6 版本兼容性处理
- 协议版本检查
- 21.7 内存管理优化
- 内存池初始化
- 22. 应用案例分析
- 22.1 车载娱乐系统服务发现
- 22.2 自动驾驶系统的事件组订阅
- 22.3 网络拓扑变化处理
- 23. 模块优势与局限性
- 23.1 优势分析
- 23.2 局限性探讨
- 24. 未来优化方向
- 24.1 IPv6全面支持
- 24.2 内存管理优化
- 24.3 错误恢复增强
- 25. 总结
一、基本概念
1.1 SD模块定位
Service Discovery(SD)模块是AUTOSAR架构中负责服务发现的核心组件,作为SOME/IP协议栈的关键组成部分,主要实现以下功能:
- 服务生命周期管理(Offer/StopOffer)
- 事件组订阅控制(Subscribe/Unsubscribe)
- 网络地址转换与路由控制
- 会话ID管理
- 异常消息处理
1.2 协议规范
本模块严格遵循:
- AUTOSAR Classic Platform R19-11规范
- SOME/IP-SD协议标准
- TCP/IP协议族规范(IPv4为主)
1.3 模块架构
模块采用分层设计:
+-----------------------+
| 应用接口层 |
| (BswM/Sd_User) |
+-----------------------+
| 协议解析层 |
| (Sd_ParseRxMessage) |
+-----------------------+
| 服务管理层 |
| (Sd_ServerService...) |
+-----------------------+
| 事件组管理层 |
| (Sd_EventHandler...) |
+-----------------------+
| 网络适配层 |
| (SoAd集成) |
+-----------------------+
| 内存管理层 |
| (MemHeap自定义实现) |
+-----------------------+
二、工作原理详解
2.1 整体流程
模块工作周期分为四个阶段:
+-----------------+| 初始化阶段 || (SD_INIT) |+--------+--------+|+-------------------------v--------------------------+| +------------------+ +------------------+ || | 服务器服务处理 | | 客户端服务处理 | || | (ServerService) | | (ClientService) | || +--------+--------+ +--------+--------+ +---v---+| | | | 消息发 || | | | 送处理 || +--------v--------+ +--------v--------+ +---+---+| | 事件组处理 | | 事件组订阅处理 | || | (EventHandler) | | (ConsumedEvent) | || +------------------+ +------------------+ |+-------------------------+--------------------------+
2.2 核心交互流程
2.2.1 服务发现流程
2.2.2 事件组订阅流程
三、核心数据结构解析
3.1 协议头结构(Sd_HeaderType)
typedef struct {uint16 ClientID; // 客户端标识uint16 SessionID; // 会话IDuint8 ProtocolVersion; // 协议版本(固定0x01)uint8 InterfaceVersion; // 接口版本(固定0x01)uint8 MessageType; // 消息类型(固定0x02)uint8 ReturnCode; // 返回码(固定0x00)union {struct {uint8 RebootFlag : 1; // 重启标志uint8 UnicastFlag : 1; // 单播标志};struct {uint8 Reserved : 6; // 保留位};};uint8 Reserved[3]; // 保留字段
} Sd_HeaderType;
内存布局特性:
- 支持大小端自适应
- 包含必要的协议元数据
- 会话ID管理支持单播/多播独立计数
3.2 服务条目结构(Sd_Type1EntryType)
typedef struct {uint8 Type; // 条目类型uint8 Index1stOptions; // 第一个选项索引uint8 Index2ndOptions; // 第二个选项索引union {struct {uint8 NumOfOpt1 : 4; // 选项1数量uint8 NumOfOpt2 : 4; // 选项2数量};};uint16 ServiceID; // 服务IDuint16 InstanceID; // 实例IDuint8 MajorVersion; // 主版本号uint8 TTL[3]; // 生存时间(3字节)uint32 MinorVersion; // 次版本号
} Sd_Type1EntryType;
关键字段说明:
- TTL字段采用3字节存储,通过Sd_SetTTL进行64位扩展
- 支持两个选项索引,实现灵活的选项引用
- 版本号分离存储(Major/Minor)
3.3 事件组条目结构(Sd_Type2EntryType)
typedef struct {uint8 Type; // 条目类型uint8 Index1stOptions; // 第一个选项索引uint8 Index2ndOptions; // 第二个选项索引union {struct {uint8 NumOfOpt1 : 4; // 选项1数量uint8 NumOfOpt2 : 4; // 选项2数量};};uint16 ServiceID; // 服务IDuint16 InstanceID; // 实例IDuint8 MajorVersion; // 主版本号uint8 TTL[3]; // 生存时间uint8 Reserved; // 保留字段union {struct {uint8 Counter : 4; // 订阅计数器uint8 Reserved : 4; // 保留位};};uint16 EventGroupID; // 事件组ID
} Sd_Type2EntryType;
增强特性:
- 支持订阅计数器(4位)
- 保留字段确保内存对齐
- 支持事件组级别的TTL管理
3.4 会话控制结构(Sd_SessionIdCtrlType)
typedef struct Sd_SessionIdCtrlType_ {TcpIp_SockAddrType remoteAddr; // 远程地址uint16 txUniSesIdCnt; // 单播会话计数uint16 rxUniSesIdCnt; // 接收单播计数uint16 rxMultiSesIdCnt; // 接收多播计数uint8 rxUniRebootFlag; // 单播重启标志uint8 rxMultiRebootFlag; // 多播重启标志Sd_ServiceHandleIdListType* serverServiceList; // 服务列表Sd_ServiceHandleIdListType* clientServiceList; // 客户端列表struct Sd_SessionIdCtrlType_* next; // 下一个节点
} Sd_SessionIdCtrlType;
设计亮点:
- 双链表结构支持动态扩展
- 独立维护单播/多播会话ID
- 服务列表支持按需分配(16项为单位)
3.5 发送队列结构(Sd_SendQueueType)
typedef struct Sd_SendQueueType_ {TcpIp_SockAddrType destAddr; // 目标地址uint8* entryPtr; // 条目指针uint8* optionPtr; // 选项指针uint32 sendTime; // 发送时间struct Sd_SendQueueType_* next; // 下一个节点uint16 optStartPos[3]; // 选项起始位置uint16 optionLen; // 选项总长度uint8 optionNum; // 选项数量boolean isUnicastSend; // 是否单播发送
} Sd_SendQueueType;
队列管理机制:
- 支持多播/单播消息分离
- 环形队列优化发送效率
- 每个队列节点独立管理发送参数
四、重要函数功能解析
4.1 模块初始化(Sd_Init)
功能:
- 配置数据验证
- 内存池初始化(RX/TX)
- 状态机初始化
- 套接字连接建立
关键代码段:
/* 初始化内存池 */
memPoolRet = Sd_InitMemoryPool(SD_TX_MEMORY_POOL_SIZE, Sd_TxMemPool);
if (MEMHEAP_OK == memPoolRet) {initResult1 = SD_INIT_SUCCESS;
}/* 初始化IP地址状态 */
for (index = 0u; index < SD_INSTANCE_NUM; index++) {Sd_InstanceRTData[index].ipAddrState = TCPIP_IPADDR_STATE_UNASSIGNED;Sd_InstanceRTData[index].rebootFlag = TRUE;
}
4.2 主处理函数(Sd_MainFunction)
执行流程:
- 随机种子递增
- 解析接收队列
- 服务状态机处理
- 事件组状态机处理
- 消息发送调度
性能优化:
/* 随机种子递增 */
Sd_RandomSeed++;/* 解析接收消息 */
#if ((SD_SERVER_SERVICE_NUM > 0) || (SD_CLIENT_SERVICE_NUM > 0))
Sd_ParseRxMessage();
#endif/* 定时器处理 */
Sd_ServerServiceTimerHandle(instancePtr, serverServicePtr);
4.3 消息解析(Sd_ParseRxMessage)
处理流程:
- 选项格式检查
- 地址有效性验证
- 会话ID更新
- 条目类型分发
安全机制:
optFormatCheckRet = Sd_OptionFormatCheck(sdMsg);
if (E_OK == optFormatCheckRet) {// 选项冲突检查optConflictCheckRet = Sd_OptionsConflictCheck(sdMsg, index, optStartPos);
}// 地址子网检查
checkPass = Sd_IsIpAddrInSameSubset((uint8*)localAddr.addr,(const uint8*)ipv4Opt.IPv4Address,localAddrCheckLen,4u);
4.4 服务生命周期管理
4.4.1 服务下线处理(Sd_ServerServiceDownPhaseHandle)
处理逻辑:
- 清理发送队列
- 发送StopOfferService
- 重置事件组订阅
- 路由关闭
状态迁移:
if (SD_CLIENT_PHASE_MAIN == cRtDataPtr->phase) {// 清理发送队列Sd_ClearSendQueue(&cRtDataPtr->head);// 发送停止服务消息Sd_BuildOfferServiceEntry(..., TRUE);
}
4.4.2 初始等待处理(Sd_ServerServiceInitialWaitPhaseHandle)
随机延迟计算:
tRandom = Sd_GetRandomValue(delayMin, delayMax);
tRandom = Sd_SendTimeAdjust(tRandom / SD_MAIN_FUNCTION_CYCLE_TIME);
4.5 事件组订阅管理
4.5.1 订阅处理(Sd_RxSubscribeEventgroupHandle)
关键检查:
if ((tcpEndpointNum > 0u) && (NULL_PTR != eventHandlerPtr->SdEventHandlerTcp)) {ret = Sd_FanOutControlTCP(...);
}if ((E_OK == ret) && (udpEndpointNum > 0u) && (NULL_PTR != eventHandlerPtr->SdEventHandlerUdp)) {ret = Sd_FanOutControlUDP(...);
}
4.5.2 多播控制(Sd_FanOutMulticastUnicastCtrlAddClient)
动态路由切换:
if (subscribedClientNum < threshold) {// 启用单播SoAd_EnableSpecificRouting(...);
} else if (subscribedClientNum == threshold) {// 切换为多播SoAd_EnableSpecificRouting(multiSoConId);// 禁用单播Sd_DisableUnicastForSubscribedClient(...);
}
五、内存管理机制
5.1 内存池设计
#define SD_RX_MEMORY_POOL_SIZE // 接收池大小
#define SD_TX_MEMORY_POOL_SIZE // 发送池大小static uint8 Sd_RxMemPool[SD_RX_MEMORY_POOL_SIZE];
static uint8 Sd_TxMemPool[SD_TX_MEMORY_POOL_SIZE];
分配策略:
- 使用ILib_MemHeap系列函数
- 支持配置报告内存不足错误(SD_MALLOC_FAIL_REPORT_ENABLE)
5.2 内存操作函数
SD_LOCAL_INLINE void Sd_InitMemoryPool(...) {return ILib_MemHeapInit(...);
}static void* Sd_MallocEx(...) {// 支持错误报告#if ((SD_DEM_USED == STD_ON) && (SD_MALLOC_FAIL_REPORT_ENABLE == STD_ON))if (NULL_PTR == ret) {Dem_ReportErrorStatus(...);}#endif
}static void Sd_FreeEx(...) {// 线程安全释放SchM_Enter_Sd_ExclusiveArea();ILib_MemHeapFree(...);SchM_Exit_Sd_ExclusiveArea();
}
六、网络协议处理
6.1 IP地址检查(Sd_IsIpAddrInSameSubset)
子网匹配算法:
cmpResult = ILib_memcmp(ipAddr1, ipAddr2, addrLen);
if (0 != cmpResult) {// 子网掩码计算netmaskArray[tAddrLen - index] = 0x00;// 按位与运算cmpResult = ILib_memcmp(addr1AndResult, addr2AndResult, addrLen);
}
6.2 端点选项处理
6.2.1 IPv4端点构建
static void Sd_SetIPv4EndpointOption(...) {ipv4Option.Length = Sd_HtoNs(SD_IPV4_ENDPOINT_OPTION_LENGTH);ipv4Option.Type = SD_IPV4_ENDPOINT_OPTION;// 设置IP地址ILib_memcpy(ipv4Option.IPv4Address, ipv4Address, 4);// 端口转换ipv4Option.PortNumber = Sd_HtoNs(portNumber);
}
6.2.2 IPv6支持
#if (STD_ON == SD_IPV6_ENABLE)
static void Sd_SetIPv6EndpointOption(...) {ipv6Option.Length = Sd_HtoNs(SD_IPV6_ENDPOINT_OPTION_LENGTH);ipv6Option.Type = SD_IPV6_ENDPOINT_OPTION;ILib_memcpy(ipv6Option.IPv6Address, ipv6Address, 16);ipv6Option.PortNumber = Sd_HtoNs(portNumber);
}
#endif
七、状态机实现
7.1 服务器状态机
typedef enum {SD_SERVER_PHASE_DOWN, // 下线状态SD_SERVER_PHASE_INITIAL_WAIT, // 初始等待SD_SERVER_PHASE_REPETITION, // 重复发送SD_SERVER_PHASE_MAIN // 主状态
} Sd_ServerServicePhaseType;
状态迁移:
DOWN -> INITIAL_WAIT -> REPETITION -> MAIN
^
|
+----+----+----+----+| | || | +-- Sd_ServerServiceRepetitionPhaseHandle| +------- Sd_ServerServiceInitialWaitPhaseHandle+------------ Sd_ServerServiceDownPhaseHandle
7.2 客户端状态机
typedef enum {SD_CLIENT_PHASE_DOWN, // 下线状态SD_CLIENT_PHASE_INITIAL_WAIT, // 初始等待SD_CLIENT_PHASE_REPETITION, // 重复请求SD_CLIENT_PHASE_MAIN // 主状态
} Sd_ClientServicePhaseType;
状态处理:
switch (phase) {
case SD_CLIENT_PHASE_DOWN:Sd_ClientServiceDownPhaseHandle(...);
case SD_CLIENT_PHASE_INITIAL_WAIT:Sd_ClientServiceInitialWaitPhaseHandle(...);
case SD_CLIENT_PHASE_REPETITION:Sd_ClientServiceRepetitionPhaseHandle(...);
case SD_CLIENT_PHASE_MAIN:Sd_ClientServiceMainPhaseHandle(...);
}
八、错误处理机制
8.1 错误报告
#if (STD_ON == SD_DEV_ERROR_DETECT)
#define SD_REPORT_ERROR(ApiId, ErrorId) \Det_ReportError(SD_MODULE_ID, SD_INSTANCE_ID, (ApiId), (ErrorId));
#endif#if (SD_DEM_USED == STD_ON)
void Sd_RemoteRebootDetectedHandle(...) {Dem_ReportErrorStatus(eventId, DEM_EVENT_STATUS_FAILED);
}
#endif
8.2 重启处理
static void Sd_RemoteRebootDetectedHandle(...) {// 处理服务重启for (index = 0u; index < clientServiceList->handleIdNum; index++) {Sd_RxStopOfferServiceHandle(clientServiceList->serviceHandleId[index]);}// 删除会话节点Sd_DeleteSessionIdNode(...);
}
九、应用案例分析
9.1 服务发现场景
典型交互流程:
关键代码:
void Sd_LocalIpAddrAssignmentChg(...) {for (idx = 0u; idx < SD_INSTANCE_NUM; idx++) {if (txPduSoConId == SoConId) {Sd_InstanceRTData[idx].ipAddrState = State;}}
}
9.2 事件组订阅场景
订阅流程:
实现细节:
static Std_ReturnType Sd_BuildSubscribeEventgroupEntry(...) {// 构建TCP/UDP选项if (tcpSoCon.isSoConOpened) {build IPv4/IPv6 Endpoint OptionSoAd_EnableSpecificRouting(tcpSoCon.soConId);}// 构建配置选项Sd_BuildType2ConfigurationOption(...);
}
9.3 网络异常处理
IP地址变更处理:
void Sd_SoConModeChg(...) {if (SOAD_SOCON_ONLINE != Mode) {// 关闭连接Sd_ClientServiceCloseSoCon(...);// 进入初始等待Sd_ClientServiceInitialWaitEnter(...);}
}
重启处理:
static void Sd_ServerServiceDownPhaseHandle(...) {// 清理发送队列Sd_ClearSendQueue(&sRtDataPtr->head);// 发送StopOfferSd_BuildOfferServiceEntry(..., TRUE);
}
十、性能优化措施
10.1 内存分配优化
- 采用内存池分配器,减少碎片
- 批量预分配服务句柄列表(16项为单位)
- 支持编译时配置内存池大小
10.2 状态机优化
- 使用位域优化状态存储
- 合并重复检查逻辑(如Sd_IsIpAddrInSameSubset)
- 减少不必要的内存拷贝
10.3 发送队列优化
static void Sd_TransmitMessage(void) {for (instanceIdx = 0u; instanceIdx < SD_INSTANCE_NUM; instanceIdx++) {// 优先发送单播uniSendCnt = Sd_FindoutUnicastMessage(...);if (uniSendCnt > 0u) {Sd_TransmitUnicastMessage(...);}// 后发送多播multiSendCnt = Sd_FindoutMulticastMessage(...);if (multiSendCnt > 0u) {Sd_TransmitMulticastMessage(...);}}
}
十一、安全机制实现
11.1 选项安全检查
static Std_ReturnType Sd_OptionsSecurityCheck(...) {// 子网检查checkPass = Sd_IsIpAddrInSameSubset(...);// 选项冲突检查Sd_OptionsConflictCheck(...);// 必要选项存在检查Sd_NecessaryOptionsExistCheck(...);
}
11.2 会话ID管理
static void Sd_SaveRemoteSessionId(...) {sesIdCtrlPtr->rxMultiSesIdCnt = Sd_NtoHs(header.SessionID);sesIdCtrlPtr->rxMultiRebootFlag = header.RebootFlag;
}
11.3 重启检测
static boolean Sd_RemoteRebootDetecte(...) {if (((0u == lastRebootFlag) && (1u == header.RebootFlag)) ||((1u == header.RebootFlag) && (curSessionId <= lastSessionId)) {isReboot = TRUE;}
}
十二、配置管理机制
12.1 动态配置支持
static uint16 Sd_GetType1ConfigurationOptionLength(...) {// 支持主机名和能力记录if (NULL_PTR != sdInstancePtr->SdInstanceHostname) {cfgOptlen += 10u + strlen(...);}// 记录长度计算for (index = 0u; index < recordNum; index++) {cfgOptlen += 1u + strlen(key) + 1u + strlen(value);}
}
12.2 配置选项构建
static void Sd_BuildType1ConfigurationOption(...) {// 主机名选项keyLen = 8u; // "hostname"valueLen = strlen(sdInstancePtr->SdInstanceHostname);*optAddr = keyLen + valueLen + 1u;ILib_memcpy(optAddr+1, "hostname", 8);optAddr[9] = '=';ILib_memcpy(optAddr+10, hostname, valueLen);// 能力记录for (index = 0u; index < recordNum; index++) {keyLen = strlen(recordPtr->key);valueLen = (recordPtr->value) ? strlen(recordPtr->value) : 0u;*optAddr = keyLen + valueLen + 1u;ILib_memcpy(optAddr+1, recordPtr->key, keyLen);optAddr[keyLen+1] = '=';if (recordPtr->value) {ILib_memcpy(optAddr+keyLen+2, recordPtr->value, valueLen);}}
}
十三、版本特性实现
13.1 多播发送优化
支持连续发送Sd消息(V2.0.24)
static void Sd_IfSpecificRoutingGroupTransmit(void) {for (index = 0u; index < SD_EVENT_HANDLER_NUM; index++) {if (ehRTDataPtr->ifSpecificRoutingTransTcpFlag) {SoAd_IfSpecificRoutingGroupTransmit(ehRTDataPtr->routingGroupIdTcp, ehRTDataPtr->soConIdTcp);}if (ehRTDataPtr->ifSpecificRoutingTransUdpFlag) {SoAd_IfSpecificRoutingGroupTransmit(ehRTDataPtr->routingGroupIdUdp, ehRTDataPtr->soConIdUdp);}}
}
13.2 会话ID管理改进
static Sd_SessionIdCtrlType* Sd_AddRemoteAddrToSessionIdCtrlList(...) {sesIdCtrlPtr->txUniSesIdCnt = 0u; // 单播计数初始化sesIdCtrlPtr->rxMultiSesIdCnt = 0u; // 多播计数初始化
}
十四、编译配置管理
14.1 条件编译控制
#if SD_SERVER_SERVICE_NUM > 0
// 服务器相关代码
#endif#if SD_CLIENT_SERVICE_NUM > 0
// 客户端相关代码
#endif#if SD_CONSUMED_EVENTGROUP_NUM > 0
// 事件组相关代码
#endif
14.2 特性开关
#define SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE STD_ON
#define SD_IPV6_ENABLE STD_OFF
#define SD_BSWM_USED STD_ON
#define SD_DEM_USED STD_ON
十五、运行时数据结构
15.1 服务器运行时(Sd_ServerServiceRTType)
typedef struct {uint32 initialWaitTimer; // 初始等待定时器uint32 repetitionTimer; // 重复发送定时器uint32 mainTimer; // 主定时器Sd_SendQueueType* head; // 发送队列Sd_ServerServiceSetStateType setState; // 目标状态Sd_ServerServicePhaseType phase; // 当前阶段Sd_TTLType ttl; // 生存时间uint8 repetitionCount; // 重复计数
} Sd_ServerServiceRTType;
15.2 客户端运行时(Sd_ClientServiceRTType)
typedef struct {TcpIp_SockAddrType serverUdpAddr; // 服务器UDP地址TcpIp_SockAddrType offerEntryRemoteAddr; // 提供者地址PduIdType offerEntryRxPduId; // PDU IDSd_TTLType ttl; // 生存时间Sd_SoConManageType tcpSoCon; // TCP连接管理Sd_SoConManageType udpSoCon; // UDP连接管理uint32 mainTimer; // 主定时器uint8 repetitionCount; // 重复计数boolean isSubscribed; // 订阅状态boolean isAnsweredWithAck; // 是否收到确认
} Sd_ClientServiceRTType;
十六、接口函数实现
16.1 服务状态设置(Sd_ServerServiceSetState)
Std_ReturnType Sd_ServerServiceSetState(...) {#if (STD_ON == SD_DEV_ERROR_DETECT)if (SD_UNINIT == Sd_Status) {SD_REPORT_ERROR(SD_SERVER_SERVICE_SET_STATE_ID, SD_E_NOT_INITIALIZED);return E_NOT_OK;}#endifSchM_Enter_Sd_ExclusiveArea();Sd_ServerRTData[handleId].setState = state;SchM_Exit_Sd_ExclusiveArea();return E_OK;
}
16.2 事件组状态设置(Sd_ConsumedEventGroupSetState)
Std_ReturnType Sd_ConsumedEventGroupSetState(...) {// 查找关联服务for (i = 0u; i < SD_CLIENT_SERVICE_NUM; i++) {if (SdConsumedEventGroupHandleId == handleId) {// 检查服务状态if (SD_CLIENT_SERVICE_RELEASED == cRtDataPtr->setState) {return E_NOT_OK;}// 更新状态consumedEgRTPtr->setState = ConsumedEventGroupState;if (SD_CONSUMED_EVENTGROUP_REQUESTED == ConsumedEventGroupState) {consumedEgRTPtr->isSendSubEvtAfterRequest = FALSE;}}}
}
十七、网络适配层交互
17.1 套接字管理
void Sd_ClientSaveSoConId(...) {// 设置唯一远程地址ret = SoAd_SetUniqueRemoteAddr(...);if (E_OK == ret) {// 打开套接字SoAd_OpenSoCon(...);soConPtr->isSoConOpened = TRUE;}
}
17.2 地址分配处理
void Sd_LocalIpAddrAssignmentChg(...) {// 更新实例IP地址状态Sd_InstanceRTData[idx].ipAddrState = State;// 通知地址变更Sd_SaveRemoteSessionId(...);
}
十八、消息打包发送
18.1 消息打包(Sd_PackageMessage)
static Std_ReturnType Sd_PackageMessage(...) {// 设置协议头Sd_SetHeader(...);// 填充条目长度tLengthField = Sd_HtoNl(entryTotalLen);ILib_memcpy(...);// 填充选项长度tLengthField = Sd_HtoNl(optionTotalLen);ILib_memcpy(...);// 复制条目和选项for (index = 0; index < sendQueCnt; index++) {ILib_memcpy(entryRunPtr, sendQuePtr->entryPtr, sizeof(Sd_Type1EntryType));entryRunPtr->Index1stOptions = optIdxCnt;optIdxCnt += sendQuePtr->optionNum;entryRunPtr = &entryRunPtr[16];}
}
18.2 发送调度(Sd_TransmitMessage)
static void Sd_TransmitMessage(void) {for (instanceIdx = 0u; instanceIdx < SD_INSTANCE_NUM; instanceIdx++) {// 优先发送单播uniSendCnt = Sd_FindoutUnicastMessage(...);if (uniSendCnt > 0u) {Sd_TransmitUnicastMessage(...);}// 然后发送多播multiSendCnt = Sd_FindoutMulticastMessage(...);if (multiSendCnt > 0u) {Sd_TransmitMulticastMessage(...);}}
}
十九、异常处理机制
19.1 消息格式检查(Sd_OptionFormatCheck)
static Std_ReturnType Sd_OptionEachItemFormatCheck(const uint8 optionArray[]) {switch (type) {case SD_CONFIGURATION_OPTION:// 配置选项始终有效ret = E_OK;break;case SD_IPV4_ENDPOINT_OPTION:// 检查长度和协议if ((0x09u == length) && ((SD_L4_PROTO_TCP == l4Proto) || (SD_L4_PROTO_UDP == l4Proto)) {ret = E_OK;}break;}
}
19.2 消息冲突检查(Sd_OptionsConflictCheck)
static Std_ReturnType Sd_OptionsConflictCheck(...) {uint16 ipv4EndpTcpNum = 0;uint16 ipv4EndpUdpNum = 0u;for (index = 0; index < optNumSum; index++) {if (SD_IPV4_ENDPOINT_OPTION == optType) {if (SD_L4_PROTO_TCP == ipv4Opt.L4Proto) {if (ipv4EndpTcpNum >= 1u) {ret = E_NOT_OK; // TCP端点冲突}ipv4EndpTcpNum++;}}}
}
二十、高级特性实现
20.1 会话ID管理
static Sd_SessionIdCtrlType* Sd_FindRemoteAddrSessionIdCtrl(...) {while (sesIdCtrlPtr != NULL_PTR) {if (0 == ILib_memcmp(...)) {break;}sesIdCtrlPtr = sesIdCtrlPtr->next;}
}
20.2 重试机制(SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE)
#if (STD_ON == SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE)
void Sd_ClientServiceResetAllCEgSubsEntrySubsRetryCnt(...) {for (index = 0u; index < eventGroupNum; index++) {consumedEgRTPtr->subsRetryCnt = 0u;consumedEgRTPtr->subsRetryTimer = 0u;consumedEgRTPtr->subsRetryEnable = FALSE;}
}
#endif
20.3 路由控制
static void Sd_EnableUnicastForSubscribedClient(...) {while (ptr != NULL_PTR) {SoAd_EnableSpecificRouting(routingGroupId, ptr->soConId);ptr = ptr->next;}
}
二十一、典型应用场景
21.1 服务发现
void Sd_RxIndication(...) {// 接收消息处理if (Sd_NPtrtoHl(&sdMsg[SD_ENTRIES_ARRAY_LENGTH_INDEX]) + Sd_NPtrtoHl(&sdMsg[SD_ENTRIES_ARRAY_LENGTH_INDEX + entryArrayLen + 4u]) <= PduInfoPtr->SduLength) {// 添加到接收队列Sd_AppendToRxBuffTail(rxQueuePtr);}
}
21.2 事件组订阅
static void Sd_ClientServiceMainPhaseHandle(...) {// 订阅消息发送if (FALSE == consumedEgRTPtr->isAnsweredWithAck) {Sd_BuildSubscribeEventgroupEntry(...);}// 重试机制#if (STD_ON == SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE)if (consumedEgTimerPtr->SdSubscribeEventgroupRetryMax > 0u) {consumedEgRTPtr->subsRetryTimer = ...;consumedEgRTPtr->subsRetryEnable = TRUE;}#endif
}
21.3 网络异常恢复(续)
TCP连接异常恢复
static void Sd_ClientServiceCloseSoCon(Sd_SoConManageType* soConPtr) {if (TRUE == soConPtr->isSoConOpened) {(void)SoAd_CloseSoCon(soConPtr->soConId, TRUE);soConPtr->isSoConOpened = FALSE;soConPtr->isOptRcved = FALSE;SoAd_ReleaseRemoteAddr(soConPtr->soConId);}
}
当检测到TCP连接状态变化为SOAD_SOCON_OFFLINE
时,SD模块会主动关闭当前连接并释放资源。这种机制确保了在网络异常情况下,客户端能够及时清理无效的连接状态,避免系统资源浪费。
UDP连接异常恢复
static void Sd_ResetSoConToWildcard(...) {if (TRUE == resetFlag) {SoAd_ReleaseRemoteAddr(soConId);}
}
对于UDP连接,当检测到没有订阅者使用该连接时,模块会将连接重置为通配符模式。这种设计保证了在订阅关系变更后,系统能自动释放不再需要的资源。
21.4 消息重传机制
订阅事件组重试
#if (STD_ON == SD_SUBSCRIBE_EVENTGROUP_RETRY_ENABLE)
static void Sd_ClientServiceResetAllCEgSubsEntrySubsRetryCnt(...) {cEgRTPtr->subsRetryCnt = 0u;cEgRTPtr->subsRetryTimer = 0u;cEgRTPtr->subsRetryEnable = FALSE;
}
#endif
当订阅事件组请求未收到ACK确认时,模块会根据配置启动重试机制。通过subsRetryTimer
和subsRetryCnt
字段跟踪重试次数,确保在达到最大重试次数后停止尝试。
21.5 安全检查机制
IP地址子网检查
static Std_ReturnType Sd_IsIpAddrInSameSubset(...) {// 子网掩码计算for (index = 0u; index < clrByte; index++) {netmaskArray[tAddrLen - index] = 0x00;}// 地址比较cmpResult = ILib_memcmp(addr1AndResult, addr2AndResult, addrLen);if (0 == cmpResult) {ret = E_OK;}
}
模块通过子网掩码对通信双方的IP地址进行校验,确保只有同一子网内的设备可以建立连接。这种机制有效防止了跨子网的非法访问。
21.6 版本兼容性处理
协议版本检查
void Sd_Init(...) {// 头部字段填充header.ProtocolVersion = 0x01u;header.InterfaceVersion = 0x01u;header.MessageType = 0x02u;header.ReturnCode = 0x00u;
}
初始化过程中,模块会设置标准的协议版本和接口版本,确保与其他节点的兼容性。版本不匹配的消息会被自动丢弃,防止协议不一致导致的问题。
21.7 内存管理优化
内存池初始化
SD_LOCAL_INLINE uint8 Sd_InitMemoryPool(uint32 memPoolSize, void* memPool) {return ILib_MemHeapInit(memPool, memPoolSize);
}
模块采用静态内存池管理机制,通过Sd_InitMemoryPool
初始化内存池,避免动态内存分配带来的不确定性,提高系统可靠性。
22. 应用案例分析
22.1 车载娱乐系统服务发现
在车载娱乐系统中,多个ECU需要动态发现彼此提供的服务。例如,导航ECU需要发现音频处理ECU提供的音频播放服务:
// 导航ECU客户端配置
const Sd_ClientServiceType NavClientService = {.SdClientServiceId = 0x0100, // 导航服务ID.SdClientServiceInstanceId = 0x0001, // 实例ID.SdClientServiceMajorVersion = 0x01, // 主版本.SdClientServiceMinorVersion = 0x00000001, // 次版本.SdClientServiceTimerRef = &NavTimerConfig,.SdClientServiceTcpRef = &NavTcpConnection,.SdClientServiceUdpRef = &NavUdpConnection
};// 音频ECU服务配置
const Sd_ServerServiceType AudioServerService = {.SdServerServiceId = 0x0100, // 服务ID.SdServerServiceInstanceId = 0x0001, // 实例ID.SdServerServiceMajorVersion = 0x01, // 主版本.SdServerServiceMinorVersion = 0x00000001, // 次版本.SdServerServiceAutoAvailable = TRUE, // 自动可用.SdServerServiceTimerRef = &AudioTimerConfig,.SdServerServiceTcpRef = &AudioTcpConnection,.SdServerServiceUdpRef = &AudioUdpConnection
};
初始化后,导航ECU会周期性发送FindService请求,音频ECU响应OfferService消息,建立服务连接。
22.2 自动驾驶系统的事件组订阅
自动驾驶系统中,多个传感器节点需要订阅主控单元发布的事件组:
// 雷达事件组配置
const Sd_EventHandlerType RadarEventHandler = {.SdEventHandlerEventGroupId = 0x0200, // 事件组ID.SdEventHandlerTimerRef = &RadarTimerConfig,.SdEventHandlerTcp = &RadarTcpConfig,.SdEventHandlerUdp = &RadarUdpConfig
};// 主控单元处理订阅
static void Sd_RxSubscribeEventgroupHandle(...) {// 检查必要选项optionCheck = Sd_NecessaryOptionsExistCheck(...);// 构建ACK响应Sd_BuildSubscribeEventgroupAckEntry(...);// 管理订阅者TTLSd_SubscribeClientTTLManage(...);
}
主控单元通过TTL管理订阅者生命周期,确保失效订阅及时清理,维护系统稳定性。
22.3 网络拓扑变化处理
当车辆网络拓扑变化时,模块能自动适应:
void Sd_LocalIpAddrAssignmentChg(...) {for (idx = 0u; idx < SD_INSTANCE_NUM; idx++) {if (txPduSoConId == SoConId) {Sd_InstanceRTData[idx].ipAddrState = State;}}
}static void Sd_ServerServiceDownPhaseEnter(...) {// 重新初始化连接for (index = 0u; index < soConIdNum; index++) {(void)SoAd_OpenSoCon(soConIdList[index]);}
}
当IP地址重新分配时,模块会自动重新初始化相关连接,确保服务发现机制持续有效。
23. 模块优势与局限性
23.1 优势分析
- AUTOSAR标准兼容:完全遵循AUTOSAR R19-11规范,确保与其他AUTOSAR组件的互操作性。
- 高效内存管理:采用静态内存池,避免动态分配带来的不确定性。
- 多协议支持:同时支持IPv4和IPv6(通过编译开关)。
- 安全增强:通过子网检查防止跨网络访问。
- 灵活配置:允许通过配置文件调整定时参数、内存池大小等关键参数。
23.2 局限性探讨
- IPv6支持有限:当前实现中IPv6支持被禁用,限制了下一代网络的应用。
- 内存占用:预分配的运行时数据结构可能在低内存系统中造成资源浪费。
- 错误处理机制:虽然提供了DET和DEM接口,但具体错误恢复策略需依赖外部实现。
- 并发处理:发送队列采用链表结构,高并发场景下可能影响性能。
24. 未来优化方向
24.1 IPv6全面支持
// 当前配置
#define SD_IPV6_ENABLE STD_OFF// 未来优化
#define SD_IPV6_ENABLE STD_ON
启用IPv6支持需要完善IPv6相关选项处理函数,如Sd_SetIPv6EndpointOption
和Sd_SetIPv6MulticastOption
。
24.2 内存管理优化
// 当前内存池配置
#define SD_RX_MEMORY_POOL_SIZE 1024
#define SD_TX_MEMORY_POOL_SIZE 2048// 优化方向
typedef struct {uint8* pool;uint32 size;uint32 used;
} Sd_MemoryPoolType;SD_LOCAL_INLINE void* Sd_MallocEx(uint32 size, Sd_MemoryPoolType* memPool) {if (memPool->used + size <= memPool->size) {void* ptr = memPool->pool + memPool->used;memPool->used += size;return ptr;}return NULL_PTR;
}
引入更智能的内存管理策略,提高内存利用率。
24.3 错误恢复增强
// 当前错误处理
#if (SD_DEM_USED == STD_ON)
Dem_ReportErrorStatus(demEventPtr->EventId, DEM_EVENT_STATUS_FAILED);
#endif// 增强方向
typedef enum {SD_RECOVERY_NONE,SD_RECOVERY_RETRY,SD_RECOVERY_REINIT,SD_RECOVERY_FALLBACK
} Sd_RecoveryStrategyType;typedef struct {Sd_RecoveryStrategyType strategy;uint8 maxAttempts;uint32 retryInterval;
} Sd_ErrorRecoveryConfigType;
增加多样化的错误恢复策略,提升系统鲁棒性。
25. 总结
AUTOSAR SD模块实现了完整的服务发现和事件组订阅机制,其设计特点包括:
- 分层架构:严格区分头部、条目、选项等数据结构,提高代码可维护性。
- 状态机驱动:采用明确的状态机管理服务生命周期,确保逻辑清晰。
- 安全增强:通过子网检查和选项冲突检测防止非法访问。
- 资源管理:内存池和连接管理机制保障系统稳定性。
- 事件驱动:与BSWM模块集成,实现状态变更的通知机制。
模块在汽车以太网通信中发挥着基础性作用,其设计充分考虑了汽车电子系统的特殊需求。尽管存在IPv6支持不完整等局限,但通过合理的配置和优化,可以满足大多数车载场景的需求。随着车载网络的不断发展,该模块需要持续演进,特别是在内存管理、错误恢复和协议扩展方面,以适应更复杂的网络环境。
本文中的源代码实现来源于小满开源项目。