目次
引言
获取套接字
绑定套接字
表明答应监听
单例模式计划
完备代码示例
个人主页:东洛的克莱斯韦克-CSDN博客
引言
有关套接字编程的细节和更多的系统调用课参考《UNIX环境高级编程》一书,可以在如下网站搜索电子版,该书在第16章详细的介绍了各种接口。
Jiumo Search 鸠摩搜索 - 文档搜索引擎 (jiumodiary.com)
而在实际的编程中,总是用系统调用的接口难免会有些繁琐。我们可以根据本身的需求,用面向对象的思想封装出接口简便的类。
也可以把类计划成单例,以组件的形式供上层使用。而上层坐拥下三层协议栈,无需关心网络通信的细节。
获取套接字
起首要用socket接口获取套接字文件形貌符
- int fd = socket(AF_INET, SOCK_STREAM, 0)
复制代码 AF_INET表示IPv4因特网域
SOCK_STREAM表示该套接字的范例是全双工,面向字节省和链接的
第三个参数 0 表示根据前两个参数选择默认的协议,此时选择的就是TCP/IPv4协议栈
绑定套接字
- bind(_socket_fd, (const struct sockaddr *)&address, (socklen_t)sizeof(address))
复制代码 绑定套接字之前先用 struct sockaddr_in 结构体添补地址信息。
IPv4因特网域用struct sockaddr_in结构体添补,IPv6因特网域用struct sockaddr_in6结构体添补,为了使差异的地址格式能和套接字绑定,必要把对应的结构体强转成通用地址结构struct sockaddr。
- struct sockaddr_in address;
- memset(&address, 0, sizeof(address)); // 把结构体初始化为0
- address.sin_family = AF_INET; // IPv4协议家族
- address.sin_addr.s_addr = INADDR_ANY; // 服务器选择任意IP地址接收请求
- address.sin_port = htons(_port); // 端口号信息,网络序列
复制代码 添补字段时,必要用htons()函数把端标语改为网络字节序列。在添补之前最好初始化结构体。
INADDR_ANY表示套接字可以接收上层进程地点服务器的任意一个IP地址(公网IP),一台服务器大概会配置多个IP地址。
表明答应监听
第一个参数是网络文件形貌符。
第二个参数提供了一个提示给系统,表明这个套接字所期望的、还未处理的(即还在等待被接受的连接)连接请求的最大队列长度。换句话说,它告诉系统内核为这个套接字分配多大的空间来存储尚未处理的连接请求。第二个参数不是严格服从的。
单例模式计划
我们必要把类的构造函数,拷贝函数,赋值重载设为私有。在类似添加一个该类范例的指针,该指针是静态的而且是私有成员。
那么只给外面袒露一个获取该指针的接口,而且只能被获取一次。
获取指针的接口就必要加锁,防止并发问题。【Linux】用5万字满意你对线程的所有♥幻想♥——【线程概念】【线程安全】【多线程并发】【互斥量】【条件变量】【信号量】【锁的原理】【各种锁】【生产者消费者模型】【读者写者问题】-CSDN博客
完备代码示例
套接字代码已经在网络环境中测试过了~
日志代码
- //日志打印
- #pragma once
- #include <iostream>
- #include <string>
- #include <ctime>
- #define INFO 1
- #define WARNING 2
- #define ERROR 3
- #define FATAL 4
- #define LOG(level, message) Log(#level, message, __FILE__, __LINE__)
- void Log(std::string level, std::string message, std::string file_name, int line)
- {
- std::cerr << "[" << level << "]" << "[" << time(nullptr) << "]" << "[" << message << "]" << "[" << file_name << "]" << "[" << line << "]" << std::endl;
- }
复制代码 套接字代码
- #pragma once // 防止头文件被重复包罗#include <sys/socket.h>#include <cstdlib>#include <arpa/inet.h>#include <netinet/in.h>#include <string.h>#include <memory>#include <pthread.h>#include "log.hpp"#define BACKLOG 5 // 全连接队列最小值pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;class tcp_serve{public: static tcp_serve *git_tcp_object(int port) // 获取单例实例 { if (tcp_ptr == nullptr) { pthread_mutex_lock(&mutex); // 加锁 if (tcp_ptr == nullptr) { tcp_ptr = new tcp_serve(port); tcp_ptr->initserve(); } pthread_mutex_unlock(&mutex); // 解锁 } return tcp_ptr; } int git_socket_fd() { return _socket_fd; }private: void initserve() { Socket(); Bind(); Listen(); } tcp_serve(int port) : _port(port), _socket_fd(-1) { } ~tcp_serve() { } tcp_serve(const tcp_serve &x); const tcp_serve &operator=(const tcp_serve &x); void Socket() { int fd = socket(AF_INET, SOCK_STREAM, 0); // 用IPv4协议家族,TCP协议 if (-1 == fd) { LOG(FATAL, "创建套接字失败"); exit(1); } // 创建套接字失败 _socket_fd = fd; LOG(INFO, "创建套接字乐成"); } void Bind() { struct sockaddr_in address;
- memset(&address, 0, sizeof(address)); // 把结构体初始化为0
- address.sin_family = AF_INET; // IPv4协议家族
- address.sin_addr.s_addr = INADDR_ANY; // 服务器选择任意IP地址接收请求
- address.sin_port = htons(_port); // 端口号信息,网络序列 int opt = 1; if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) < 0) { LOG(WARNING, "端口不能在短时间内连续绑定"); } // 防止TIME_WAIT状态导致绑定端口失败 LOG(INFO, "端口复用设置乐成"); if (-1 == bind(_socket_fd, (const struct sockaddr *)&address, (socklen_t)sizeof(address))) { LOG(FATAL, "绑定套接字失败"); exit(2); // 绑定套接字失败 } LOG(INFO, "套接字绑定乐成"); } void Listen() { if (-1 == listen(_socket_fd, BACKLOG)) { LOG(FATAL, "声明本身可连接失败"); exit(3); } // 请求链接失败 LOG(INFO, "套接字答应监听链接"); }private: int _port; // 端口 int _socket_fd; // 套接字文件形貌符 static tcp_serve *tcp_ptr;};tcp_serve *tcp_serve::tcp_ptr = nullptr;
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |