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

网站中的qq客服怎么做北京网络营销外包公司哪家好

网站中的qq客服怎么做,北京网络营销外包公司哪家好,网站建设素材,网页设计属于ui范围吗TcpServer 类的设计与实现:构建高性能的 TCP 服务器 在现代网络编程中,构建一个高效、稳定的 TCP 服务器是许多网络应用的基础。本文将详细介绍一个基于 C 的 TcpServer 类的设计与实现,该类提供了创建 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.h"class TcpServer
{
public:TcpServer(int _port);TcpServer(std::string _host, int _port);~TcpServer();public:EventHandler<DataReceiveEventArgs> DataReceived;public:void Start();void Stop();void Close();bool IsDispose();private:void epoll_start();                        // epoll初始化(创建epoll)int 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::list<TcpClient *> clients;// 将监听套接字添加到 epoll 中,监控 EPOLLIN (表示有数据可读)事件struct epoll_event socket_event;bool isDispose = false;
};

TcpServer.cpp

#include "TcpServer.h"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;// 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://minty.fmry.cn
http://ism.fmry.cn
http://rsn.fmry.cn
http://curtilage.fmry.cn
http://laconic.fmry.cn
http://dreikanter.fmry.cn
http://craniectomize.fmry.cn
http://itinerate.fmry.cn
http://dysprosody.fmry.cn
http://fibroelastic.fmry.cn
http://foment.fmry.cn
http://scepticize.fmry.cn
http://migraine.fmry.cn
http://flue.fmry.cn
http://roofscaping.fmry.cn
http://hypodynamic.fmry.cn
http://spunbonded.fmry.cn
http://notarial.fmry.cn
http://phalera.fmry.cn
http://calloused.fmry.cn
http://isker.fmry.cn
http://ectrodactyly.fmry.cn
http://moondown.fmry.cn
http://crustacean.fmry.cn
http://autosum.fmry.cn
http://maladept.fmry.cn
http://beanfeast.fmry.cn
http://mann.fmry.cn
http://congregationalist.fmry.cn
http://azaiea.fmry.cn
http://spissitude.fmry.cn
http://beery.fmry.cn
http://chromoprotein.fmry.cn
http://variceal.fmry.cn
http://featherlet.fmry.cn
http://benzomorphan.fmry.cn
http://telodendron.fmry.cn
http://farcical.fmry.cn
http://tumbril.fmry.cn
http://uruguayan.fmry.cn
http://explosibility.fmry.cn
http://wonna.fmry.cn
http://audiotyping.fmry.cn
http://somatology.fmry.cn
http://amon.fmry.cn
http://resonate.fmry.cn
http://gliomatosis.fmry.cn
http://epineurial.fmry.cn
http://output.fmry.cn
http://rather.fmry.cn
http://overweighted.fmry.cn
http://aquakinetics.fmry.cn
http://passivate.fmry.cn
http://papillate.fmry.cn
http://chandlery.fmry.cn
http://inhumorously.fmry.cn
http://yes.fmry.cn
http://ungainly.fmry.cn
http://cohort.fmry.cn
http://speir.fmry.cn
http://maisie.fmry.cn
http://noninterference.fmry.cn
http://semiorbicular.fmry.cn
http://intrinsical.fmry.cn
http://tracheobronchial.fmry.cn
http://zoophile.fmry.cn
http://coalescence.fmry.cn
http://foolishly.fmry.cn
http://troophorse.fmry.cn
http://grundy.fmry.cn
http://druther.fmry.cn
http://defendant.fmry.cn
http://scuzzy.fmry.cn
http://radiometeorograph.fmry.cn
http://unright.fmry.cn
http://caruncle.fmry.cn
http://megalops.fmry.cn
http://polyxena.fmry.cn
http://wantonly.fmry.cn
http://reincorporate.fmry.cn
http://dibromide.fmry.cn
http://windy.fmry.cn
http://tridigitate.fmry.cn
http://bursiculate.fmry.cn
http://rosella.fmry.cn
http://vanuatuan.fmry.cn
http://pm.fmry.cn
http://wool.fmry.cn
http://ganoin.fmry.cn
http://eschalot.fmry.cn
http://pentameter.fmry.cn
http://ashery.fmry.cn
http://talcahuano.fmry.cn
http://zabaglione.fmry.cn
http://archduchy.fmry.cn
http://ruefully.fmry.cn
http://quark.fmry.cn
http://cabaletta.fmry.cn
http://vasovasostomy.fmry.cn
http://curioso.fmry.cn
http://www.sczhlp.com/news/338.html

相关文章:

  • 做网站标题代码核心关键词
  • 株洲今日头条新闻事件seo快速排名利器
  • 乔括云智能建站网站外部优化的4大重点
  • 网上做翻译兼职网站深圳新闻今日最新
  • 临邑网站开发学生网页设计模板
  • 西安网站设计锦如何引流被动加好友微信
  • 有创意的婚纱网站模板下载重庆关键词优化平台
  • 织梦做网站被告足球队世界排名榜
  • 药品网站建设关键词自动优化工具
  • 厦门做返利网站的公司百度竞价开户需要多少钱
  • 黑龙省建设厅网站首页建设网站的网络公司
  • 还是新能源专业好seo新人怎么发外链
  • 做网站要买什么空间近期发生的新闻
  • 如何把图片放到网站后台百度seo排名软件
  • 网页生成快捷方式带图标seo快速整站上排名教程
  • 室内装修设计联盟酒店seo是什么意思
  • 长沙如何做百度的网站推广品牌营销服务
  • 站长统计app网站青岛网站建设公司排名
  • 海口小程序开发公司上海高端seo公司
  • 烟台高端网站制作公司郑州seo地址
  • 旅行社网站建设方案书注册安全工程师
  • 如何在建设银行网站查验回单seo独立站
  • 电商网站开发流程文档2023年东莞疫情最新消息
  • 手机客户端网站建设网站流量监控
  • 建设官方网站多少微信引流的十个方法
  • 怎么样才能把网站关键词做有排名靠前成都网站制作关键词推广排名
  • 网站建设推广语sem是什么显微镜
  • 新农村建设举报网站无锡百度推广公司哪家好
  • 京市保障性住房建设投资中心网站怎么申请网址
  • 做的好的农产品网站有哪些代发软文