sylar-from-scratch----hook模块

27 阅读2分钟

image.png image.png

FdCtx文件句柄上下文类

管理文件句柄类型(是否socket)、是否阻塞、是否关闭、读、写超时时间。在用户态记录了fd的读写超时和非阻塞信息,其中非阻塞包括用户显示设置的非阻塞userNonblock和hook内部设置的非阻塞sysNonblock,区分二者可以有效用对用户对fd设置/获取NONBLOCK模式的情形。

hook类

通过hook模块,可以使一些不具异步功能的API,展现出异步的性能。其实质是对系统调用API进行一次封装,将其封装成一个与原始系统调用API同名的接口,应用在调用这个接口时,会先执行封装中的操作,再执行原始的系统调用API。
hook的目的是在不重新编写代码的情况下,把老代码中的socket IO相关的API都转成异步,以提高性能。hook与IO协程调度是密切相关的,其开启控制为调度线程粒度。如果不使用IO协程调度器,hook没有任何意义。
hook的重点是在替换API的底层实现的同时完全模拟其原本的行为,因为调用方是不知道hook细节的,在调用被hook的API时,如果其行为与原本行为不一致,就会给调用方造成困惑。

动态链接中的hook实现

hook的实现机制是通过动态库的全局符号接入功能,用自定义的接口替换掉同名的系统调用接口,由于系统调用接口基本上是由C标准函数库libc提供的,所以就是用自定义的动态库来覆盖掉libc中的同名符号。
由于动态库的全局符号介入问题,全局符号表只会记录第一次识别到的符号,后续的同名符号都被忽略,但这并不表示同名符号所在的动态库完全不会被加载,因为有可能其它的符号会用到。以libc库举例,若用户连接libc库之前链接了一个指定的库,并且这个库实现了read/write接口,那么在程序运行时,程序调用的read/write接口就是指定库里的,而不是libc库里的。libc库仍然会被加载,因为libc库是程序的运行时库,程序不可能不依赖libc里的其它接口。因为libc库也加载了,所以通过一定的手段,仍然可以从libc中拿到属于libc的read/write接口,这就为hook创建了条件。程序可以定义自己的read/write接口,在接口内部先实现一次相关操作,再调用libc里的read/write接口。
www.midlane.top/wiki/pages/… juejin.cn/post/724183…