【计算机网络】基于Tcp的echo和Sock封装

文章目录

  • 前言
  • 基于Tcp的echo
    • 成员变量
    • 成员函数
  • 封装SOCK类
    • 成员变量
    • 成员函数
  • 结语

前言

上一篇文章我们用Udp简单实现了一个网络聊天室,今天我们一起来学习使用TCP套接字。

基于Tcp的echo

成员变量

//端口号
uint16_t _port;
//要执行的回调
func_t _func;
//listen套接字
int _socklisten;

成员函数

  • Init
    完成套接字的创建、绑定、监听
void initServer()
{// 1 创建socket接口,打开网络文件_socklisten = socket(AF_INET, SOCK_STREAM, 0);if (_socklisten < 0){logMessage(Error, "create socket error");exit(SOCKED_ERR);}logMessage(Info, "create socket success");// 2 给服务器指明IP地址和Portstruct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);      // host to network shortlocal.sin_addr.s_addr = INADDR_ANY; // bind本主机任意ipif (bind(_socklisten, (sockaddr*)&local, sizeof(local)) < 0){logMessage(Error, "bind socket error code:%d info:%s", errno, strerror(errno));exit(BIND_ERR);}logMessage(Info, "bind socket success");// 3 监听if (listen(_socklisten, backlog) < 0){logMessage(Error, "listen socket error");exit(LISTEN_ERR);}logMessage(Info, "listen socket success");
}
  • start
    我们分为四个版本来实现最终的业务:
    • 1、service 测试使用,不多讲解

    • 2、多进程版本
      使用多进程的方式,可以让多个进程处理不同的service请求,但使用这个方式需要考虑两个问题:

      • a、子进程要不要等待?谁来等待?
        子进程当然需要等待,但我们不希望是父进程,因为父进程还要去处理其他客户端的事情,这里就有两种方式来解决这个问题:

        1. 使用信号忽略掉SIGCHLD
          signal(SIGCHLD,SIG_IGN);
        2. 托孤给bash进程
          父进程退出,子进程就变成了孤儿进程。
      • b、子进程和父进程不需要的fd是不是都需要关闭?
        父进程的fd必须要关掉,而子进程的fd可以选择关掉。如果父进程不关闭用于通信的fd,很快就会导致fd越来越多,进而发生文件描述符泄露

    • 3、源生线程版本
      源生线程这里最需要注意的就是线程任务需要传入的参数很多,因此我们要构建一个ThreadData类

      ThreadDate *td = new ThreadData(sock, clientip, clientport, this);
      在线程任务内再通过类型转换想办法执行类内要执行的函数。
      若不想回收线程,可以使用pthread_detach(pthread_self());

    • 4、线程池版本
      线程池主要解决简短、频繁的请求。在多线程章节我们再详细聊聊线程池的设计。

void start()
{while (true){struct sockaddr_in client;socklen_t len = sizeof(client);// 4 获取连接,acceptint sock = accept(_socklisten, (struct sockaddr *)&client, &len);if (sock < 0){logMessage(Warning, "获取连接失败,code:%d,error string:%s", errno, strerror(errno));continue;}std::string clientip = inet_ntoa(client.sin_addr);uint16_t clientport = ntohs(client.sin_port);// 5 获取连接成功开始进行业务处理logMessage(Info, "获取连接成功:%d from %d,client:%s-%d", sock, _socklisten, clientip.c_str(), clientport);// 1 test//  service(sock,clientip,clientport);// 2 多进程//  pid_t id = fork();//  if(id < 0)//  {//      logMessage(Warning,"创建线程失败 code: %d error:%s",errno,strerror(errno));//      continue;//  }//  else if(id == 0)//  {//      //子进程可以选择关闭不需要的fd//      close(_socklisten);//      if(fork() > 0) exit(0);//     //现在是孙子进程被bash1领养了,不需要等待了//     service(sock,clientip,clientport);//     exit(0);//  }// //父进程必须关闭不用的fd防止fd泄露// close(sock);// 3 源生线程// pthread_t tid;// ThreadDate *td = new ThreadDate(sock, clientip, clientport, this);// pthread_create(&tid, nullptr, threadRoutine, td);// 4 线程池版本Task t(sock,clientip,clientport,std::bind(&TcpServer::service,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));ThreadPool<Task>::GetInstance()->pushTask(t);}
}

封装SOCK类

成员变量

仅需要一个成员变量,在服务端它可以是监听fd,在客户端他可以被当作通信fd使用。

int _sock;

成员函数

  • Socket
    和udp一样,套接字需要先被创建出来。
void Socket()
{_sock = socket(AF_INET, SOCK_STREAM, 0);if (_sock < 0){logMessage(Error, "create socket error id:%d info:%s", errno, strerror(errno));exit(SOCKET_ERR);}
}

  • Bind
    和udp一样,套接字需要bind对应的ip+端口号

void Bind(const uint16_t port)
{struct sockaddr_in local;  local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;if (bind(_sock, (sockaddr *)&local, sizeof(local)) < 0){logMessage(Error, "Bind error id:%d info:%s", errno, strerror(errno));exit(BIND_ERR);}logMessage(Info, "Bind success");}

  • listen
    将TCP套接字设置为监听状态,使其可以接收客户端的连接请求。gbacklog是最大的等待被接受的连接请求数,而不是最多的连接数,一般而言这个队列长度是gbacklog+1.
void Listen()
{if (listen(_sock, gbacklog) < 0){logMessage(Error, "Listen error id:%d info:%s", errno, strerror(errno));exit(LISTEN_ERR);}logMessage(Info, "Bind success");
}

  • accept
    用于接受客户端的连接请求,并创建一个新的套接字与客户端通信
// 将客户端信息存起来
int Accept(std::string *clientip, uint16_t *clientport)
{sockaddr_in temp;socklen_t len = sizeof(temp);int sock = accept(_sock, (sockaddr *)&temp, &len);if (sock < 0){logMessage(Error, "Accept error id:%d info:%s", errno, strerror(errno));}else {*clientip = inet_ntoa(temp.sin_addr);*clientport = ntohs(temp.sin_port);}logMessage(Info, "accept success");return sock;
}

  • Connect
    客户端向服务端发起连接请求

int Connect(const std::string serverip,const uint16_t& serverport)
{sockaddr_in server;memset(&server,0,sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());return connect(_sock,(sockaddr*)&server,sizeof(server));
}

  • Fd、Close
int Fd()
{return _sock;
}void Close()
{close(_sock);
}

结语

至此,Tcp的Sock封装我们就全部搞定了,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/28569.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3学习--使用pandas 数据透视表分析数据--入门示例

什么是透视表&#xff1f; 透视表是一种可以对数据动态排布并且分类汇总的表格格式&#xff0c;可以以多种方式和视角查看数据特征 Pandas库提供了一个名为pivot_table的函数&#xff0c;它将一个特性的值汇总在一个整洁的二维表中。 使用示例 pivot_table函数说明 pandas.…

The label parameter should be set so this animate*AsState can be better

The label parameter should be set so this animate*AsState can be better inspected in the Animation Preview. Compose提示&#xff1a; The label parameter should be set so this animate*AsState can be better inspected in the Animation Preview. 需要添加label标…

爬虫010_列表高级_添加_append_extend_修改_查询_in_not int_删除_del_pop_remove---python工作笔记029

然后再来看列表操作 首先添加append方法 然后插入,坐标是要插入的下标,右边是插入的内容 看结果 1,2,3,4,5,6 然后这个extend,是逐个插入,放到后边 然后是修改,直接对下标赋值 看结果</

从安装 Seata 开始的分布式事务之旅 springboot集成seata

从安装 Seata 开始的分布式事务之旅 介绍什么是 Seata&#xff1f; 安装 Seata Server下载 Seata Server 发行版配置Seata解压文件配置Seata的yml文件把配置文件config.txt加载到nacos上修改config.txt文件加载到nacos上 启动Seata服务正常启动查看启动日志打开控制台页面 启动…

深入探究不同类型代理及其在网络安全与爬虫中的应用

1. 代理技术概述 代理技术是一种通过中间服务器来转发网络请求和响应的方法。通过使用代理服务器&#xff0c;用户可以隐藏真实的网络身份、加强网络连接安全&#xff0c;以及实现更高效的数据传输。不同类型的代理服务器在实现方式和用途上存在差异&#xff0c;下面我们将重点…

pytest常用执行参数详解

1. 查看pytest所有可用参数 我们可以通过pytest -h来查看所有可用参数。 从图中可以看出&#xff0c;pytest的参数有很多&#xff0c;下面是归纳一些常用的参数&#xff1a; -s&#xff1a;输出调试信息&#xff0c;包括print打印的信息。 -v&#xff1a;显示更详细的信息。 …

中电金信:ChatGPT一夜爆火,知识图谱何以应战?

随着ChatGPT的爆火出圈 人工智能再次迎来发展小高潮 那么作为此前搜索领域的主流技术 知识图谱前路又将如何呢&#xff1f; 事实上&#xff0c;ChatGPT也并非“万能”&#xff0c;作为黑箱模型&#xff0c;ChatGPT很难验证生成的知识是否准确。并且ChatGPT是通过概率模型执行推…

Python web实战之Django 的 RESTful API 设计详解

关键词: Python, Web 开发, Django, RESTful API 1 API的一些事儿 1.1 什么是API&#xff1f; API是应用程序编程接口&#xff08;Application Programming Interface&#xff09;的缩写。它是一种定义了不同软件组件之间交互方式的规范。API允许不同的应用程序之间进行通信和…

Kafka3.0.0版本——Broker(上下线)示例

目录 一、Broker&#xff08;上下线&#xff09;示例1.1、三台服务器信息1.2、先启动zookeeper集群&#xff0c;再启动kafka集群1.3、zookeeper客户端工具prettyZoo查看brokers中ids1.4、停止某一台kafka服务&#xff0c;再次查看brokers中ids1.5、重新启动停止的kafka服务&…

【剑指Offer 30】包含min函数的栈,Java解密。

LeetCode 剑指Offer 75道练习题 文章目录 剑指Offer:包含min函数的栈示例:限制:解题思路:剑指Offer:包含min函数的栈 【题目描述】 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。 示…

Python爬虫在电商数据挖掘中的应用

作为一名长期扎根在爬虫行业的专业的技术员&#xff0c;我今天要和大家分享一些有关Python爬虫在电商数据挖掘中的应用与案例分析。在如今数字化的时代&#xff0c;电商数据蕴含着丰富的信息&#xff0c;通过使用爬虫技术&#xff0c;我们可以轻松获取电商网站上的产品信息、用…

vue实现pdf预览功能

背景&#xff1a;材料上传之后点击预览实现在浏览器上预览的效果 效果如下&#xff1a; 实现代码如下&#xff1a; //预览和下载操作 <el-table-column fixed"right" label"操作" width"210"><template #default"scope">…

Hbase-热点问题(数据存储倾斜问题)

1. 危害 某一台regionserver消耗过多&#xff0c;承受过多的并发量&#xff0c;时间长机器性能下降&#xff0c;甚至宕机 2. 解决 可以通过设计rowkey预分区的方法解决 比如可以预分区120个&#xff0c;1月的数据存到1-10分区&#xff0c;每个月的数据存到10个分区&#xff…

初识React: 基础(概念 特点 高效原因 虚拟DOM JSX语法 组件)

1.什么是React? React是一个由Facebook开源的JavaScript库&#xff0c;它主要用于构建用户界面。React的特点是使用组件化的思想来构建界面&#xff0c;使得代码的可复用性和可维护性大大提高。React还引入了虚拟DOM的概念&#xff0c;减少了对真实DOM的直接操作&#xff0c;…

GaussDB数据库SQL系列-表连接(JOIN)

目录 一、前言 二、GaussDB JOIN 1、LEFT JOIN 2、LEFT JOIN EXCLUDING INNER JOIN 3、RIGHT JOIN 4、LEFT JOIN EXCLUDING INNER JOIN 5、INNER JOIN 6、FULL OUTER JOIN 7、FULL OUTER JOIN EXCLUDING INNER JOIN 三、GaussDB 实验示例 1、初始化实验表 2、LEFT …

无涯教程-Perl - getc函数

描述 此函数从FILEHANDLE中读取下一个字符(如果未指定,则从STDIN中读取),并返回值。 语法 以下是此函数的简单语法- getc FILEHANDLEgetc返回值 此函数返回错误或文件结尾的undef以及从FILEHANDLE读取的字符值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl$k…

【git】Git 回退到指定版本:

文章目录 方法一: 使用 git reset 命令方法二&#xff1a;使用 git revert 命令方法三&#xff1a;使用 git checkout 命令常见的错误及其解决办法如下&#xff1a; 方法一: 使用 git reset 命令 命令可以将当前分支的 HEAD 指针指向指定的提交&#xff0c;从而回退代码到指定版…

PS透明屏,在科技展示中,有哪些优点展示?

PS透明屏是一种新型的显示技术&#xff0c;它将传统的显示屏幕与透明材料相结合&#xff0c;使得屏幕能够同时显示图像和透过屏幕看到背后的物体。 这种技术在商业展示、广告宣传、产品展示等领域有着广泛的应用前景。 PS透明屏的工作原理是利用透明材料的特性&#xff0c;通…

SDXL-Stable Diffusion改进版

文章目录 1. 摘要2. 算法&#xff1a;2.1 结构&#xff1a;2.2 微小的条件机制2.3 多宽高比训练2.4 改进自编码器2.5 所有组合放到一起2.6 主流方案比较 3. 未来工作4. 限制 论文&#xff1a; 《SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis…

解决网关不定时出现Refresh routes error !!!

最近跟踪服务器日志,经常发现如下异常 ERROR o.s.c.g.r.CachingRouteLocator - [handleRefreshError,94] - Refresh routes error !!! org.springframework.expression.spel.SpelEvaluationException: EL1005E: Type cannot be found org.springframework.util.StreamUtils …