C++中套接字库sockpp的使用详解

 更新时间:2023年11月15日 11:29:38   作者:fengbingchun  
sockpp是一个开源、简单、现代的C++套接字库,这篇文章主要为大家详细介绍一下套接字库sockpp的使用,文中的示例代码讲解详细,感兴趣的小伙伴可以学习一下

sockpp是一个开源、简单、现代的C++套接字库,地址为:https://github.com/fpagliughi/sockpp,最新发布版本为0.8.1,license为BSD-3-Clause。目前支持Linux、Windows、Mac上的IPv4、IPv6和Unix域套接字。其它*nix和POSIX系统只需很少的修改或无需修改即可工作。

1.套接字基类包装(wrap)系统套接字句柄,并维持其生命周期。当C++对象超出范围时,它会关闭底层套接字句柄。套接字对象通常是可移动的,但不可复制。可以使用 std::move()将套接字从一个作用域(或线程)传输到另一个作用域。

2.库中的所有代码都位于sockpp C++命名空间内。

3.TCP和其它"流"网络应用程序通常设置为服务器或客户端。接受器用于创建TCP/流服务器。它绑定一个地址并侦听已知端口以接受传入连接。 当连接被接受时,会创建一个新的流式套接字。该新套接字可以直接处理或移动到线程(或线程池)进行处理。

相反,要创建TCP客户端,需要创建连接器对象并将其连接到已知地址(通常是主机和套接字)的服务器。连接后,套接字是一种流式套接字,可以直接用于读写。

对于IPv4,sockpp::tcp_acceptor和sockpp::tcp_connector类分别用于创建服务器和客户端。它们使用sockpp::inet_address类来指定由32位主机地址和16位端口号组成的端点地址。

sockpp::tcp_acceptor通常位于一个循环中接受新连接,并将它们传递给另一个进程、线程或线程池以与客户端交互。

TCP客户端稍微简单一些,创建一个sockpp::tcp_connector对象并连接,然后可以直接读写数据。

4.每个套接字类的默认构造函数不执行任何操作,只是将底层句柄设置为INVALID_SOCKET。它们不创建套接字对象。

5.套接字对象不是线程安全的。想要有多个线程从套接字读取或写入套接字的应用程序应该使用某种形式的序列化,例如std::mutex来保护访问。套接字可以安全地从一个线程移动到(moved)另一个线程。这是服务器的一种常见模式,它使用一个线程接受传入连接,然后将新套接字传递给另一个线程或线程池进行处理。

由于套接字无法复制,唯一的选择是将套接字移动到这样的函数。这是一种常见的模式,尤其是在客户端应用程序中,让一个线程从套接字读取数据,另一个线程向套接字写入数据。在这种情况下,底层套接字句柄可以被认为是线程安全的(一个读线程和一个写线程)。但即使在这种情况下,sockpp::socket对象仍然不是线程安全的,特别是由于缓存的错误值(cached error value)。写入线程可能会看到读取线程上发生的错误,反之亦然。

这种情况的解决方案是使用socket::clone()方法来复制套接字。这将使用系统的dup()函数或类似的函数创建另一个带有套接字句柄的重复副本的套接字。这样做的另一个好处是套接字的每个副本都可以保持独立的生命周期。在两个对象超出范围之前,底层套接字不会关闭。

在Windows和Linux上编译的sockpp的shell脚本如下:

#! /bin/bash
 
if [ $# != 2 ]; then
    echo "Error: requires two parameters: 1: windows or linux; 2: release or debug"
    echo "For example: $0 windows debug"
    exit -1
fi
 
if [ $1 != "windows"  ] && [ $1 != "linux" ]; then
    echo "Error: the first parameter can only be windows or linux"
    exit -1
fi
 
if [ $2 != "debug" ] && [ $2 != "release" ]; then
    echo "Error: the second parameter can only be debug or release"
    exit -1
fi
 
if [ $1 == "windows" ] && [ $2 == "debug" ]; then
    cmake \
        -G"Visual Studio 17 2022" -A x64 \
        -DCMAKE_BUILD_TYPE=Debug \
        -DCMAKE_CONFIGURATION_TYPES=Debug \
        -DSOCKPP_BUILD_SHARED=OFF \
        -DSOCKPP_BUILD_STATIC=ON \
        -DSOCKPP_BUILD_EXAMPLES=ON \
        -DCMAKE_INSTALL_PREFIX=install/debug \
        -Bbuild \
        .
    
    cmake --build build/ --target install --config debug
fi
 
if [ $1 == "windows" ] && [ $2 == "release" ]; then
    cmake \
        -G"Visual Studio 17 2022" -A x64 \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_CONFIGURATION_TYPES=Release \
        -DSOCKPP_BUILD_SHARED=OFF \
        -DSOCKPP_BUILD_STATIC=ON \
        -DSOCKPP_BUILD_EXAMPLES=ON \
        -DCMAKE_INSTALL_PREFIX=install/release \
        -Bbuild \
        .
 
    cmake --build build/ --target install --config release
fi
 
if [ $1 == "linux" ] && [ $2 == "debug" ]; then
    cmake \
        -DCMAKE_BUILD_TYPE=Debug \
        -DSOCKPP_BUILD_SHARED=OFF \
        -DSOCKPP_BUILD_STATIC=ON \
        -DSOCKPP_BUILD_EXAMPLES=ON \
        -DCMAKE_INSTALL_PREFIX=install/debug \
        -Bbuild \
        .
    
    cmake --build build/ --target install --config debug
fi
 
if [ $1 == "linux" ] && [ $2 == "release" ]; then
    cmake \
        -DCMAKE_BUILD_TYPE=Release \
        -DSOCKPP_BUILD_SHARED=OFF \
        -DSOCKPP_BUILD_STATIC=ON \
        -DSOCKPP_BUILD_EXAMPLES=ON \
        -DCMAKE_INSTALL_PREFIX=install/release \
        -Bbuild \
        .
 
    cmake --build build/ --target install --config release
fi
 
rc=$?
if [[ ${rc} != 0 ]]; then
    echo "Error: please check: ${rc}"
	exit ${rc}
fi

以下为IPv4的测试代码:

1.客户端测试代码如下:

int test_sockpp_client()
{
    sockpp::initialize();
 
    sockpp::tcp_connector conn({host, port});
	if (!conn) {
		std::cerr << "Error: connecting to server at: "
			<< sockpp::inet_address(host, port)
			<< ", message: " << conn.last_error_str() << std::endl;
		return -1;
	}
 
    std::cout << "created a connection from: " << conn.address() << std::endl;
	std::cout << "created a connection to " << conn.peer_address() << std::endl;
 
    // set a timeout for the responses
    if (!conn.read_timeout(std::chrono::seconds(5))) {
        std::cerr << "Error: setting timeout on TCP stream: " << conn.last_error_str() << std::endl;
    }
 
    const std::vector<std::string> addr{"csdn", "github", "gitlab"};
    std::unique_ptr<unsigned char[]> buf(new unsigned char[len]);
    int index{0};
 
	std::atomic<bool> quit{ false };
	std::thread th([&quit] {
		std::this_thread::sleep_for(std::chrono::seconds(20));
		quit = true;
	});
 
	while (true) {
		if (quit) break;
 
        auto ret = conn.write(addr[index]);
        if (ret != addr[index].size()) {
            std::cerr << "Error: writing to the TCP stream: " << conn.last_error_str() << std::endl;
            break;
        }
 
		memset(buf.get(), 0, len);
        ret = conn.read(buf.get(), len);
        if (ret == -1) {
            std::cerr << "Error: reading from TCP stream: " << conn.last_error_str() << std::endl;
            break;
        }
 
        std::cout << addr[index] << ": " << buf.get() << std::endl;
 
        if (++index == addr.size()) index = 0;
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
 
	th.join();
    return 0;
}

2.服务器端测试代码如下:

int test_sockpp_server()
{
    sockpp::initialize();
 
    sockpp::tcp_acceptor acc(port);
	if (!acc) {
		std::cerr << "Error: creating the acceptor: " << acc.last_error_str() << std::endl;
		return -1;
	}
 
	while (true) {
		sockpp::inet_address peer;
		// accept a new client connection
		sockpp::tcp_socket sock = acc.accept(&peer);
		std::cout << "received a connection request from: " << peer << std::endl;
		if (!sock) {
			std::cerr << "Error: accepting incoming connection: " << acc.last_error_str() << std::endl;
		}
		else {
			// create a thread and transfer the new stream to it
			std::thread th2(run_echo, std::move(sock));
			th2.detach();
		}
	}
 
    return 0;
}

3.辅助code如下所示:

namespace {
 
constexpr char* host{"127.0.0.1"};
constexpr in_port_t port{ 8888 };
constexpr int len {64};
 
void run_echo(sockpp::tcp_socket sock)
{
	std::cout << "thread id: " << std::this_thread::get_id() << std::endl;
 
	std::map<std::string, std::string> addr;
	addr["csdn"] = "https://blog.csdn.net/fengbingchun";
	addr["github"] = "https://github.com/fengbingchun";
 
	std::unique_ptr<unsigned char[]> buf(new unsigned char[len]);
 
	while (true) {
		memset(buf.get(), 0, len);
		auto ret = sock.read(buf.get(), len);
		if (ret == -1) {
			std::cerr << "Error: reading from TCP stream: " << sock.last_error_str() << std::endl;
            break;
		}
 
		auto it = addr.find(std::string((char*)buf.get()));
		if (it != addr.end()) {
			sock.write(it->second);
		}
		else
			sock.write("unkonwn");
	}
}
 
} // namespace

Windows上执行结果如下所示:模拟1个服务器端,3个客户端

Linux上执行结果如下图所示:模拟1个服务器端,3个客户端

GitHubhttps://github.com/fengbingchun/OpenSSL_Test

到此这篇关于C++中套接字库sockpp的使用详解的文章就介绍到这了,更多相关C++套接字库sockpp内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言中函数指针与软件设计经验总结

    C语言中函数指针与软件设计经验总结

    今天小编就为大家分享一篇关于C语言中函数指针与软件设计经验总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 简单了解设计模式中的装饰者模式及C++版代码实现

    简单了解设计模式中的装饰者模式及C++版代码实现

    这篇文章主要介绍了简单了解设计模式中的装饰者模式及C++版代码实现,ConcreteComponent的引用(指针)也可以达到修饰的功能,需要的朋友可以参考下
    2016-03-03
  • C语言新手入门速通手册

    C语言新手入门速通手册

    C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。C 语言是一种广泛使用的计算机语言,它与 Java 编程语言一样普及,二者在现代软件程序员之间都得到广泛使用
    2022-04-04
  • C++中memset函数用法详解

    C++中memset函数用法详解

    这篇文章主要介绍了C++中memset函数用法,结合实例形式详细分析了memset函数的功能、使用方法与相关注意事项,需要的朋友可以参考下
    2016-06-06
  • 手把手教你实现漂亮的Qt 登录界面

    手把手教你实现漂亮的Qt 登录界面

    最近在使用Qt5,Qt Creator做一个管理系统类的项目,需要用到登录界面,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Visual Studio Code 从简介、安装到配置所需插件详细介绍

    Visual Studio Code 从简介、安装到配置所需插件详细介绍

    这篇文章给大家介绍到vs与vs code的区别,并且会详细介绍vscode的安装步骤,和我所了解过的插件配置,感兴趣的朋友跟随小编一起看看吧
    2020-03-03
  • C语言中的分支循环其嵌套语句

    C语言中的分支循环其嵌套语句

    这篇文章主要介绍了C语言中的分支循环其嵌套语句,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java C++ 算法题解leetcode1582二进制矩阵特殊位置

    Java C++ 算法题解leetcode1582二进制矩阵特殊位置

    这篇文章主要为大家介绍了Java C++ 算法题解leetcode1582二进制矩阵特殊位置示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • C++ 引用和指针的区别对比分析

    C++ 引用和指针的区别对比分析

    在C++ 中,指针(Pointer)和引用(Reference)都用于间接访问变量,但是它们在语法和语义上都有显著的差异,下面通过本文给大家介绍C++ 引用和指针的区别,感兴趣的朋友一起看看吧
    2025-10-10
  • C++与C语言的区别你知道吗

    C++与C语言的区别你知道吗

    这篇文章主要为大家详细介绍了C++与C的区别,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03

最新评论