比较好奇libsrt库的socket通讯如何实现的,就随意翻了翻socket通讯部分的代码,发现了一些技巧,特此记录。
libsrt库主要由C++开发的,看:
个别的是.c文件。
libsrt库的examples中的test-c-client.c和test-c-server.c共同组成了一个简单的srt客户端和server端:
只要是写过socket的,这些再简单不过了。
追踪:
继续追:
发现通讯部分都是调用的uglobal().xxxx();
没看uglobal()函数之前,疯狂的猜测: 1、难道是x实现的? 2、难道是xx实现的? 3、难道是xxx实现的?
看了代码才知道,原来用到了单例模式:
言归正传:
如果是Java的话,最常见单例模式的如下所写:
public class SingleTon {
private static final SingleTon instance = new SingleTon();
private SingleTon() {
}
public static SingleTon getInstance(){
return instance;
}
}
libsrt中C++的单例这样写的:
CUDTUnited& srt::CUDT::uglobal()
{
static CUDTUnited instance;
return instance;
}
这段代码就是实现了一个超级简单的单例,还运用了一个C++的特性:函数内的静态局部变量。
这段代码主要是把这个特性给整明白就可以了,我还有GPT-4o都觉得有如下好处:
请GPT-4o老师生成一个示例,展示为什么将静态变量写在函数内部更有优势:
#include <iostream>
#include <mutex>
// Singleton class example
class CUDTUnited {
public:
// Public method to access the singleton instance
static CUDTUnited& getInstance() {
static CUDTUnited instance; // Local static instance
return instance;
}
void connect(int u, const char* name, int namelen, bool forced_isn) {
std::cout << "Connecting: " << name << std::endl;
}
private:
// Private constructor to prevent instantiation
CUDTUnited() { std::cout << "CUDTUnited instance created." << std::endl; }
// Delete copy constructor and assignment operator
CUDTUnited(const CUDTUnited&) = delete;
CUDTUnited& operator=(const CUDTUnited&) = delete;
};
// Usage example
void exampleUsage() {
CUDTUnited& instance = CUDTUnited::getInstance();
instance.connect(1, "example", 7, true);
}
int main() {
exampleUsage();
exampleUsage(); // The instance will not be created again
return 0;
}
在上述代码中:
首次调用 getInstance 时,会输出 “CUDTUnited instance created.” 和 “Connecting: example”。 再次调用 exampleUsage 时,只会输出 “Connecting: example”,因为实例只会被创建一次。
对比:"函数外部静态变量"如果将静态变量写在函数外部,无法享受上述所有的好处,例如:
#include <iostream>
// Singleton instance declared outside of the function
static CUDTUnited instance; // Will be created at program startup
class CUDTUnited {
public:
static CUDTUnited& getInstance() {
return instance;
}
void connect(int u, const char* name, int namelen, bool forced_isn) {
std::cout << "Connecting: " << name << std::endl;
}
private:
CUDTUnited() { std::cout << "CUDTUnited instance created." << std::endl; }
CUDTUnited(const CUDTUnited&) = delete;
CUDTUnited& operator=(const CUDTUnited&) = delete;
};
void exampleUsage() {
CUDTUnited& instance = CUDTUnited::getInstance();
instance.connect(1, "example", 7, true);
}
int main() {
exampleUsage();
exampleUsage(); // The instance will not be created again
return 0;
}
在这种情况下:
程序启动时,无论是否使用 CUDTUnited 实例,都会创建实例。这可能会浪费资源。 线程安全问题:需要手动保证多线程环境下的线程安全,增加代码复杂性。
因此,将静态变量写在函数内部是单例模式实现的一种推荐方法,特别是从C++11开始,它提供了更好的延迟初始化和线程安全支持。