我正在尝试修改iperf以支持另一个协议(UDT)。UDT API是这样编写的,它反映了标准的BSD调用:
socket(...);
bind(...);
listen(...);
然后,我需要做的是有条件地与UDT库链接,以便iperf中的这些调用将使用UDT代码,而不是TCP堆栈的套接字接口。这能做到吗?我总是可以加载库,并使用UDT::命名空间获得另一个条件路径,但1)TCP路径会有很多重复,2)会有很多更改,可能不需要。如果我不清楚,请告诉我,任何关于如何实现这种动态链接的建议都将不胜感激。
编辑:
使用下面提到的dlopen()家族,我可以获得以下程序流:
解析cmd行params->如果请求UDT,则加载库libudt->获取并存储所有UDT BSD函数的句柄(绑定、侦听等)
在这一点上,我的所有UDT函数都存储了函数指针。假设我将它们全部存储在一个名为udt_calls的结构中。现在,我对现有的代码有一个问题,它只会调用以下代码:
bind(...)
而不是:
udt_calls->bind(...)
有没有一种干净的方法可以用我现在加载的udt_calls结构中的函数指针全局覆盖整个程序中的任何BSD调用?
是的,这是可以做到的。您需要使用动态库加载。在Windows中,这是使用LoadLibrary
完成的。在Linux或Unix中,它是使用dlopen
和朋友来完成的。
您需要阅读文档并查看这些函数的示例。一个简单的总结是,您创建了一堆函数指针(通常在结构中完成,在Windows上有一些技巧可以将它们加载到C++虚拟函数类中)。然后使用动态加载函数打开一个库,然后分配函数指针指向库中的函数。
然后,使用函数指针(或C++虚拟函数)进行函数调用。
编辑:看起来在Unix中也有使用C++虚拟基类的方法。
编辑:我相信大多数系统都会让操作系统库使用"弱"符号。这意味着您可以定义自己的同名全局符号,并覆盖操作系统库版本。尝试在您自己的程序中声明全局函数指针,以提供bind
和listen
的全局版本。
另一种选择可能是在结构中声明指针,然后使用预处理器定义,如:
#define bind udt_calls->bind