当前位置: 首页 > news >正文

好用的h5网站烟台制作网站的公司

好用的h5网站,烟台制作网站的公司,国家企业信用公示信息年报入口,怎么样开发小程序TcpServer 类的设计与实现#xff1a;构建高性能的 TCP 服务器 在现代网络编程中#xff0c;构建一个高效、稳定的 TCP 服务器是许多网络应用的基础。本文将详细介绍一个基于 C 的 TcpServer 类的设计与实现#xff0c;该类提供了创建 TCP 服务器、处理客户端连接、数据传输…TcpServer 类的设计与实现构建高性能的 TCP 服务器 在现代网络编程中构建一个高效、稳定的 TCP 服务器是许多网络应用的基础。本文将详细介绍一个基于 C 的 TcpServer 类的设计与实现该类提供了创建 TCP 服务器、处理客户端连接、数据传输和接收等功能。通过这个类我们可以更容易地理解和实现 TCP 通信的细节。 1. TcpServer 类概述 TcpServer 类是一个用于创建和管理 TCP 服务器的类。它封装了套接字创建、绑定、监听、客户端连接处理、数据发送和接收等操作使得网络通信更加简洁和易于管理。 2. 类构造与析构 构造函数 TcpServer::TcpServer(int _port) 和 TcpServer::TcpServer(std::string _host, int _port) 初始化服务器的主机地址和端口并创建套接字。 TcpServer::TcpServer(int _port) : TcpServer(0.0.0.0, _port) { }TcpServer::TcpServer(std::string _host, int _port) : host(_host), port(_port) {std::cout create tcp server start. std::endl;socket_fd socket(AF_INET, SOCK_STREAM, 0);if (socket_fd -1) {std::cout socket create error!;return;}int ret set_epoll_mode(socket_fd, O_NONBLOCK);if (ret 0) {std::cout epoll_mode failed: ret std::endl;close(socket_fd);return;}server_addr.sin_family AF_INET;inet_pton(AF_INET, host.c_str(), server_addr.sin_addr);server_addr.sin_port htons(port);int opt 1;setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));isCreate true;std::cout create tcp server ok. std::endl; }析构函数 TcpServer::~TcpServer() 虚析构函数确保派生类的析构函数被正确调用。 TcpServer::~TcpServer() { }3. 服务器启动与停止 启动服务器 TcpServer::Start() 绑定套接字到指定端口并开始监听。 void TcpServer::Start() {if (running || !isCreate) {std::cout TcpServer start failed! running running , port port std::endl;return;}auto ret bind(socket_fd, (struct sockaddr *)server_addr, sizeof(server_addr));if (ret -1) {std::cout bind faild: ret std::endl;close(socket_fd);return;}ret listen(socket_fd, SOMAXCONN);if (ret -1) {std::cout Listen failed: ret std::endl;close(socket_fd);return;}std::cout server open: host : port std::endl;epoll_start(); }停止服务器 TcpServer::Stop() 关闭服务器并释放资源。 void TcpServer::Stop() {this-Close(); }4. 资源管理 关闭连接 TcpServer::Close() 关闭套接字和 epoll 文件描述符释放资源。 void TcpServer::Close() {isCreate false;running false;socket_event.data.fd socket_fd;int ret epoll_ctl(epoll_fd, EPOLL_CTL_DEL, socket_fd, socket_event);ret close(socket_fd);std::cout socket_fd已关闭: ret std::endl;for (TcpClient *client : clients)client-Close();ret close(epoll_fd);std::cout TcpServer epoll_fd已关闭: ret std::endl; }5. 非阻塞模式设置 设置非阻塞模式 TcpServer::set_epoll_mode() 设置套接字为非阻塞模式。 int TcpServer::set_epoll_mode(int sock_fd, int mode) {int flags fcntl(sock_fd, F_GETFL, 0);if (flags -1) {std::cout epoll_mode failed: sock_fd std::endl;return -1;}return fcntl(sock_fd, F_SETFL, flags | mode); }6. 客户端连接处理 客户端接受线程 TcpServer::client_accept_thread() 处理客户端连接和数据事件。 void TcpServer::client_accept_thread() {struct epoll_event client_events[1024];while (running) {int ret epoll_wait(epoll_fd, client_events, 1024, -1);if (ret 0) {if (errno EAGAIN || errno EWOULDBLOCK)continue;else {std::cerr epoll_wait failed: ret : errno : strerror(errno) std::endl;break;}}for (int n 0; n ret; n) {if (client_events[n].data.fd socket_fd) {client_connect();} else {struct epoll_event client_event client_events[n];auto client std::find_if(clients.begin(), clients.end(), [client_event](const TcpClient *_client){ return (_client-client_fd client_event.data.fd); });if (client clients.end())continue;int ret (*client)-data_receive(*client);if (ret 0) {clients.erase(client);delete *client;}}}}std::cout 服务已关闭不再提供任何服务 std::endl;isDispose true; }客户端连接 TcpServer::client_connect() 接受客户端连接并添加到 epoll 监控。 void TcpServer::client_connect() {struct sockaddr_in client_addr;socklen_t addr_len sizeof(client_addr);int client_fd accept(socket_fd, (struct sockaddr *)client_addr, addr_len);std::cout accept: client_fd : strerror(errno) std::endl;if (client_fd 0)return;TcpClient *client new TcpClient;client-running true;client-connected true;client-client_fd client_fd;client-local_addr client_addr;int ret set_epoll_mode(client_fd, O_NONBLOCK);if (ret -1) {std::cout 服务器接受客户端-set_epoll_mode failed: strerror(errno) std::endl;client-Close();return;}client-add_epoll_event(client_fd, epoll_fd, EPOLLIN | EPOLLET);client-DataReceived [this](void *sender, DataReceiveEventArgs *e){DataReceived.Invoke(this, e);};client-recv_data new char[client-recv_data_length];clients.push_back(client);std::cout 新的客户端已接入: inet_ntoa(client_addr.sin_addr) : htons(client_addr.sin_port) std::endl; }7. epoll 事件处理 启动 epoll TcpServer::epoll_start() 创建 epoll 实例并添加监听套接字。 void TcpServer::epoll_start() {epoll_fd epoll_create1(0);if (epoll_fd -1) {std::cout poll_create1 failed: epoll_fd std::endl;close(socket_fd);return;}socket_event.events EPOLLIN;socket_event.data.fd socket_fd;int ret epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, socket_event);if (ret -1) {std::cout epoll_ctl failed: ret std::endl;close(epoll_fd);return;}running true;std::thread th std::thread(TcpServer::client_accept_thread, this);th.detach(); }完整的代码: TcpServer.h 头文件 #pragma once#include iostream #include vector #include list #include string #include sys/socket.h #include netinet/in.h #include sys/epoll.h #include sys/fcntl.h #include arpa/inet.h #include algorithm #include unistd.h #include thread #include DataReceiveEventArgs.h #include TcpClient.hclass TcpServer { public:TcpServer(int _port);TcpServer(std::string _host, int _port);~TcpServer();public:EventHandlerDataReceiveEventArgs DataReceived;public:void Start();void Stop();void Close();bool IsDispose();private:void epoll_start(); // epoll初始化创建epollint set_epoll_mode(int sock_fd, int mode); // epoll模式--创建socket时为非阻塞模式void client_accept_thread();void client_connect();sockaddr_in get_remote_addr(int sock);private:int socket_fd;int epoll_fd;std::string host 0.0.0.0;int port 0;bool running false;bool isCreate false;int send_buff_size 1024 * 1024;int recv_buff_size 1024 * 1024;struct sockaddr_in server_addr;std::listTcpClient * clients;// 将监听套接字添加到 epoll 中监控 EPOLLIN 表示有数据可读事件struct epoll_event socket_event;bool isDispose false; };TcpServer.cpp #include TcpServer.hTcpServer::TcpServer(int _port) : TcpServer(0.0.0.0, _port) { }TcpServer::TcpServer(std::string _host, int _port) : host(_host), port(_port) {std::cout create tcp server start. std::endl;// AF_INET 表示使用 IPv4 协议// SOCK_STREAM 表示套接字的类型表示 面向连接的流式套接字socket_fd socket(AF_INET, SOCK_STREAM, 0);// std::cout create tcp server socket_fd: socket_fd std::endl;if (socket_fd -1){std::cout socket ceate error!;return;}// 文件描述符为非阻塞模式int ret set_epoll_mode(socket_fd, O_NONBLOCK);if (ret 0){std::cout epoll_mode failed: ret std::endl;close(socket_fd);return;}server_addr.sin_family AF_INET;// ip字符串转intinet_pton(AF_INET, host.c_str(), server_addr.sin_addr);//server_addr.sin_addr.s_addr ntohl(server_addr.sin_addr.s_addr);server_addr.sin_port htons(port);// 以下设置表示当调用close关闭客户端时立即释放端口不等待// 在TCP服务端客户端调用 close(client_fd) 关闭连接后如果你尝试重新连接时出现端口没有完全释放的情况通常是由于 TCP 连接的 TIME_WAIT 状态没有及时清理。这是 TCP 协议的正常行为。// 在TCP连接关闭后端口会进入 TIME_WAIT 状态。这个状态的目的是确保最后的数据包能够正确到达。如果新的连接尝试在该端口上进行而该端口仍然处于 TIME_WAIT 状态就会出现端口被占用的情况。// TIME_WAIT 状态通常会持续一段时间默认是4分钟即240秒这可以通过操作系统的内核参数来修改。// struct linger linger_opt;// linger_opt.l_onoff 1; // 启用// linger_opt.l_linger 1; // 立即关闭// // 此方法亲测无效// // setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, linger_opt, sizeof(linger_opt));int opt 1;setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));isCreate true;std::cout create tcp server ok. std::endl; }TcpServer::~TcpServer() { }void TcpServer::Start() {if (running || !isCreate){std::cout TcpServer start failed! running running , port port std::endl;// close(socket_fd);return;}// 绑定套接字到指定端口auto ret bind(socket_fd, (struct sockaddr *)server_addr, sizeof(server_addr));if (ret -1){std::cout bind faild: ret std::endl;close(socket_fd);return;}// 开始监听ret listen(socket_fd, SOMAXCONN);if (ret -1){std::cout Listen failed: ret std::endl;close(socket_fd);return;}std::cout server open: host : port std::endl;epoll_start(); }void TcpServer::Stop() {this-Close(); }void TcpServer::Close() {isCreate false;running false;// 1. 删除socket_fd的epoll事件socket_event.data.fd socket_fd;int ret epoll_ctl(epoll_fd, EPOLL_CTL_DEL, socket_fd, socket_event);// 2. 关闭监听套接字ret close(socket_fd);std::cout socket_fd已关闭: ret std::endl;// 3. 从 epoll 中移除所有连接的客户端文件描述符for (TcpClient *client : clients)client-Close();// 4. 关闭 epoll 文件描述符ret close(epoll_fd);std::cout TcpServer epoll_fd已关闭: ret std::endl; }bool TcpServer::IsDispose() {return isDispose; }int TcpServer::set_epoll_mode(int sock_fd, int mode) {/*O_NONBLOCK非阻塞模式如果设置了这个标志表示该套接字或文件是非阻塞的执行读写操作时不会阻塞调用进程或线程。套接字在没有数据可读或可写时不会让程序等待而是立即返回。O_RDWR、O_WRONLY、O_RDONLY访问模式表示套接字的打开方式。O_APPEND追加模式指示文件或套接字在写操作时会追加数据。*/int flags fcntl(sock_fd, F_GETFL, 0); // 获取当前套接字的文件状态标志if (flags -1){std::cout epoll_mode failed: sock_fd std::endl;return -1;}// 设置套接字为非阻塞模式return fcntl(sock_fd, F_SETFL, flags | mode); }void TcpServer::client_accept_thread() {struct epoll_event client_events[1024];while (running){// 阻塞等待事件int ret epoll_wait(epoll_fd, client_events, 1024, -1);if (ret 0){if (errno EAGAIN || errno EWOULDBLOCK)continue;else{std::cerr epoll_wait failed: ret : errno : strerror(errno) std::endl;break;}}// 处理返回的事件for (int n 0; n ret; n){if (client_events[n].data.fd socket_fd){// 如果是监听套接字的事件,有新的客户端连接client_connect();}else{struct epoll_event client_event client_events[n];auto client std::find_if(clients.begin(), clients.end(), [client_event](const TcpClient *_client){ return (_client-client_fd client_event.data.fd); });if (client clients.end())continue;// 客户端有数据int ret (*client)-data_receive(*client);if (ret 0){clients.erase(client);delete *client;}}}}std::cout 服务已关闭不再提供任何服务 std::endl;isDispose true; }void TcpServer::client_connect() {struct sockaddr_in client_addr;socklen_t addr_len sizeof(client_addr);int client_fd accept(socket_fd, (struct sockaddr *)client_addr, addr_len); // 接受连接std::cout accept: client_fd : strerror(errno) std::endl;if (client_fd 0)return;TcpClient *client new TcpClient;client-running true;client-connected true;client-client_fd client_fd;client-local_addr client_addr;// 设置客户端套接字为非阻塞模式int ret set_epoll_mode(client_fd, O_NONBLOCK);if (ret -1){std::cout 服务器接受客户端-set_epoll_mode failed: strerror(errno) std::endl;client-Close();return;}// client.SetSendBuffSize(send_buff_size);// client.SetRecvBuffSize(recv_buff_size);// 将新客户端套接字添加到 epoll 中监听可读事件// client-create_epoll();client-add_epoll_event(client_fd, epoll_fd, EPOLLIN | EPOLLET);client-DataReceived [this](void *sender, DataReceiveEventArgs *e){DataReceived.Invoke(this, e);};// client-start_receive();client-recv_data new char[client-recv_data_length];clients.push_back(client);std::cout 新的客户端已接入: inet_ntoa(client_addr.sin_addr) : htons(client_addr.sin_port) std::endl; }void TcpServer::epoll_start() {// 创建epollepoll_fd epoll_create1(0);if (epoll_fd -1){std::cout poll_create1 failed: epoll_fd std::endl;close(socket_fd);return;}// 监听可读事件socket_event.events EPOLLIN;// 将监听套接字的文件描述符传给 epollsocket_event.data.fd socket_fd;// 将监听套接字添加到 epoll 中监控 EPOLLIN 事件表示有数据可读int ret epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, socket_event);if (ret -1){std::cout epoll_ctl failed: ret std::endl;close(epoll_fd);return;}running true;std::thread th std::thread(TcpServer::client_accept_thread, this);th.detach(); } 8. 总结 本文详细介绍了 TcpServer 类的设计与实现包括构造与析构、服务器启动与停止、资源管理、非阻塞模式设置、客户端连接处理以及 epoll 事件处理。通过这个类我们可以更容易地理解和实现 TCP 通信的细节。这个类提供了一个简洁的接口来管理 TCP 服务器使得网络编程更加高效和易于维护。 TcpServer 类的设计注重模块化和可扩展性允许开发者根据具体需求进行定制和扩展。通过使用 epoll 事件模型TcpServer 类能够支持高并发的客户端连接适用于需要处理大量并发连接的网络应用。此外类中的非阻塞模式设置和资源管理机制确保了服务器的稳定性和高效性。 总的来说TcpServer 类为构建高性能的 TCP 服务器提供了一个强大的基础。通过这个类开发者可以快速构建和部署 TCP 服务器满足各种网络应用的需求。
http://www.hkea.cn/news/14373459/

相关文章:

  • 机电建设工程施工网站网站制作能在家做吗
  • 如何在360网站网页上做笔记万户网络公司如何
  • 教育培训学校网站建设策划网站的标题符号
  • 歌曲网站源码h5制作网页
  • 施工企业在施工现场搭设临时设施保定seo
  • 苍山网站建设四川seo整站优化
  • 哪一个网站有做实验的过程培训机构网站
  • asp做的网站频繁报错 参数错误seo研究中心vip课程
  • 网站开发公司 杭州抖音网站表白怎么做
  • 厦门找一家做网站的公司好做一个网上商城需要多少钱
  • 鸿扬家装网站建设广东深圳职业技术学校
  • 做西班牙语网站shopee东南亚跨境电商平台
  • 专题网站建设意义何在深圳珠宝网站设计
  • 多语种网站创意字体设计生成器
  • 做重视频网站wordpress备份文章
  • 家居网站建设素材wordpress怎么建表格
  • 自己能建设网站京东网上购物商城购物
  • 网站设计是用ps做图吗seo综合查询怎么回事
  • 社区网站开发进度表郑州百姓网免费征婚
  • 专业做高端网站做文案应该关注的网站推荐
  • 有哪些网站可以做设计竞标网站小视频怎么做代理
  • 顺德网站建设效果wordpress不显示媒体库图片
  • 响应式科技公司网站模板如何用asp编写网站后台
  • 南宁网站建设咨询云尚网络网站友链查询源码
  • c2c网站开发策划品牌推广费用预算
  • 界面设计是做什么的windows优化大师的特点
  • 深圳联雅网站建设公司注册步骤流程
  • 网站修改东莞建设造价信息网站
  • 全景网站制作教程天津搜索引擎优化公司
  • 电子商务网站的运营一般需要做哪些准备wordpress 多说 代码