Doip 执行过程分析

doip_server_init()
********************************************************************************************************************
doip_server_create()
->doip_select_create() 分配并创建select操作相关结构体变量
-> 初始化eventl操作链表并将其加入链表队列, 初始化内部通知需要用到的fd;
-> doip_init_notify()
- doip_internal_socket() 使用loopback方式创建用于内部通信的socket
notify_fd[0] = connector; /* tcp client /
notify_fd[1] = acceptor; /
tcp server */
设置客户端为可读属性 ,并将客户端fd加入select事件
->创建doip client结构体并填充结构体内容,然后初始化client结构体链表并加入Doip server结构体链表
->创建free client结构体并填充结构体内容,然后初始化client结构体链表并加入Doip server结构体链表
->创建server config结构体并填充结构体内容:
cfg->mcts = 10;
cfg->tester_sa = DOIP_ADDR_TESTER; //0x0E82 测试设备地址
cfg->physical_la = DOIP_ADDR_ECU_PHY; // 0x0111 ECU物理地址
cfg->functional_la = DOIP_ADDR_ECU_FUNC; //0xE400 ECU功能逻辑地址
server->config = cfg;


doip_server_manager_create()
->创建 doip_server_manager 结构体,并初始化分配存储空间
->创建 doip_node_tcp_table_t tcp连接节点结构体,并将该结构体加入doip_server_manager的Tcp node链表
->创建 doip_node_udp_table_t udp连接节点结构体,并将该结构体加入doip_server_manager的Udp node链表
->创建 doip_create_timer_manager() 定时器管理结构体, 并初始化doip_server_manage的链表
doip_create_timer_manager()
doip_thread_create(doip_pthread_func, manager, DOIP_TIMER_REQ_THREAD)
-> 分配doip_thread_t结构体并填充结构体内容
-> 初始化线程的条件唤醒属性条件
-> 设置线程属性及互斥锁
-> 线程的arg参数指向timer_manager结构体
-> pthread_create(&thread->thread, &thread->attr, doip_thread_main, thread);
创建线程函数doip_thread_main ,该线程函数实际上又调用了线程结构体中thread->main_fun(thread, thread->arg)函数
最终执行线程函数 doip_timer_func(doip_thread_t *thread, void *arg)
doip_timer_func(doip_thread_t *thread, void *arg)
- 轮询是否有新的定时器加入定时器管理链表,如果有新定时器加入,则直接轮询manager的定时器链表是否有定时器函
数需要执行,先将待执行的定时器函数从链表中移除,若有定时器函数需要执行,则检查其是否满足定时时间,若没有达
到定时时间则更新时间为当前时间并将其重新加入定时器链表队列;若定时器时间到则执行定时器回调函数。(该定时器
函数的执行存在时间误差)
疑问点:链表中第一个定时器函数的定时时间未超时,则继续把该定时器加入到链表头部,会不会造成定时器链表中其它
定时器函数周期到达后,会不会出现不能被及时执行的情况。

      **********************************************************************************************************************
      doip_request_ip_addr_assignment()
                  -> doip_add_ipv4_tcp_socket(global_server)
                            @新建doip tcp server端的socket,并绑定监听Doip端口13400
                            ->doip_event_source_create()函数创建select操作需要的所有资源,并绑定accept操作到select操作资源
                                /* 创建event相关资源,并返回该event source */
source->base.interface = &fd_source_interface;
source->base.fd = fd;
source->base.sel_ptr = sel_ptr;
source->base.data = data;
source->func = func;
source->fd = fd;
return (doip_event_source_t *)source;
执行完上述过程后,source->func = doip_tcp_socket_data();

/* 将该event source加入服务端,并与server端event关联 */
doip_source_add()函数将source加入select事件操作

之前创建的doip_net_run()线程函数会轮询检查server端的select事件,若有事件发生,则调用
source->interface->dispatch(source, &ep[i]),即调用fd_source_interface()函数;fd_source_interface()函数
调用doip_event_source_fd_dispatch(), 其doip_event_source_fd_dispatch()调用
fd_source->func(fd_source->fd, mask, source->data)函数,即调用doip_tcp_socket_data();

doip_tcp_socket_data()函数调用accept()接收client socket连接,调用doip_client_create(server, server->sel_net, client_fd)
函数,doip_client_create()调用doip_event_source_create()函数将连接的client fd加入select 监测事件;调用doip_source_add
函数设置client fd的event为可读属性;调用 doip_add_connection_table()函数,记录建立连接的client fd的ip、port及socket
信息,并启动client socket定时器,若超过一定时间client没有发送数据到服务端,则断开该client 连接。

之前创建的doip_net_run()线程函数会轮询检查server端的select事件,若有事件发生,则调用
source->interface->dispatch(source, &ep[i]),即调用fd_source_interface()函数;fd_source_interface()函数
调用doip_event_source_fd_dispatch(), 其doip_event_source_fd_dispatch()调用
fd_source->func(fd_source->fd, mask, source->data)函数,即调用doip_client_connection(),如果存在可读事件则
调用doip_connection_read()函数,读取完数据之后调用doip_tcp_header_unpack()解析数据包,若payload数据长度大于0,
则调用doip_recv_payload()接收负载数据,若是以太网数据则调用doip_net_unpack()函数,doip_net_unpack()函数启动客户端Tcp
的连接定时器,并调用doip_net_unpack_exec()解析收到的以太网数据包中应答类型及负载数据类型,以UDS诊断请求为例,其会
调用 doip_unpack_diagnostic()先返回doip的uds正响应,再执行Dcm_MainFunction()调用Dcm_ServiceHandle(),
Dcm_ServiceHandle()中获取 Dcm_ServiceTable,并判断DCM相应标志,最终调用Dcm_ServiceTable中对应的具体执行函数。

doip_client_connection()调用过程:
doip_client_connection
-> doip_connection_read
-> doip_tcp_header_unpack
-> doip_recv_payload
-> doip_net_unpack
-> doip_timer_restart 或者 doip_timer_start
-> doip_net_unpack_exec
-> doip_unpack_diagnostic
-> doip_node_tcp_list_find_by_fd
-> 判断Doip及UDS各个前提条件是否满足
-> 若满足,执行doip_pack_diagnostic_positive_ack
-> Dcm_MainFunction
-> Dcm_ServiceHandle
-> dcmComStatus.curServicePtr = Dcm_ServiceTable
-> 判断SID是否存在,判断当前会话是否支持该UDS
-> 判断当前安全级别是否支持该服务
-> dcmComStatus.curServicePtr->serviceFct()
-> 例如 Dcm_RecvMsg28 处理函数
———————————————————————————————————————————————————————————
2023 03 21
———————————————————————————————————————————————————————————

                                         source->interface->dispatch(source, &ep[i]);
                                         ->doip_tcp_socket_data()
                                                      ->doip_client_create(server, server->sel_net, client_fd)
                                                                 -> doip_connection_create(fd)
                                                                      /* 填充连接到服务端的客户端信息 */
                                                                  -> doip_event_source_create(sel_ptr, fd, doip_client_connection, client)  
                                                                      /* 填充client->source内容 */
                                                                                 ->doip_client_connection(int fd, uint32_t mask, void *data)
                                                                                     /*  根据mask标志位,确认是读取数据还是写入数据
                                                                                      * 若是读取数据,则调用如下函数
                                                                                      */
                                                                                              ->doip_connection_read(conn)
                                                                                                       ->doip_net_unpack(link_data)
                                                                                                               @判断doip报文长度是否有效,无效则返回,有效调用如下函数
                                                                                                                ->doip_net_unpack_exec(link_data, pos)                                                   
                                                                                                                @ doip报文类型判断,并生成相应的报文信息

                                                      ->doip_source_add(server->sel_net, s->source, DOIP_EVENT_READABLE)
                                                     @添加Server端Socket fd到select监听fd组,并设置Server端fd为Read可读属性

                                             @解析连接到Server端的Client的IP地址、端口,
                                                      -> accept(fd, (struct sockaddr *) &addr, &length)
                                                           @等待客户端连接,执行完accept函数后server端生成一个client_fd
                                                      -> doip_client_create
                                                           @ client->connection:与客户端通信时用的fd
                                                           @ client->server:客户端建立连接时对应的Server结构体信息
                                                           @ client->source:客户端用于select操作相关的结构体信息
                                                           @ 创建Client的fd,type等信息结构体,添加到Doip server端的net_client_list链表,
                                                      -> doip_source_add
                                                           @ 设置Server端的Socket fd的select可读、可写属性,并将客户端的fd加入select操作组
                                                      -> doip_add_connection_table(addr_data)
                                                           @ 将接收到的客户端的连接信息添加到Server端的connection_table

                                                      -> doip_source_add(server->sel_net, s->source, DOIP_EVENT_READABLE)
                                                     @添加Server端Socket fd到select监听fd组,并设置Server端fd为Read可读属性
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值