1.5.C++项目:仿mudou库实现并发服务器之socket模块的设计

news2024/11/28 23:37:20

项目完整版在:

一、socket模块:套接字模块

在这里插入图片描述

二、提供的功能

Socket模块是对套接字操作封装的一个模块,主要实现的socket的各项操作。

socket 模块:套接字的功能
创建套接字
绑定地址信息
开始监听
向服务器发起连接
获取新连接
接受数据
发送数据
关闭套接字
创建一个监听链接
创建一个客户端连接
设置套接字选项——开启地址端口重用!
设置套接字阻塞属性——设置为非阻塞!

三、实现思想

(一)功能

对socket套接字的操作进行封装。

(二)意义

对socket套接字的操作进行封装。

(三)功能设计

  1. 创建套接字
  2. 绑定地址信息
  3. 开始监听
  4. 向服务器发起连接
  5. 获取新连接
  6. 接受数据
  7. 发送数据
  8. 关闭套接字
  9. 创建一个监听链接
  10. 创建一个客户端连接

四、代码

#define MAX_LISTEN 1024
class Socket {
        private:
                int _sockfd;
        public:
                Socket() :_sockfd(-1) {}
                Socket(int fd) : _sockfd(fd) {} 
                ~Socket() {Close(); }
                int fd() {return _sockfd;}
                // 1.创建套接字
                bool Create() {
                
                        //int socket (int domain,int type,int protocol);
                        _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
                        if (_sockfd < 0) {
                                ERR_LOG("CREATE SOCKET FAILED !!");
                                return false;
                        }
                        return true;
                } 
                // 2.绑定地址信息
                bool Bind(const std::string &ip,uint16_t port) {
	       
                        struct sockaddr_in addr;
                        addr.sin_family = AF_INET;
                        addr.sin_port = htons(port);
                        addr.sin_addr.s_addr = inet_addr(ip.c_str());
                        socklen_t len = sizeof(struct sockaddr_in);
                        // int bind(int sockfd,struct sockaddr * addr,socklen_t len);
                        int ret = bind(_sockfd,(struct sockaddr*)&addr,len);
                        if (ret < 0) {
                                ERR_LOG("BIND ADDRESS FAILED!!!!");
                                return false;
                        }
                        return true;
                }
                 // 3.开始监听
                bool Listen(int backlog = MAX_LISTEN) {
                        // int listen(int backlog)
                        int ret = listen(_sockfd,backlog);
                        if (ret < 0) {
                                ERR_LOG("SOCKET LISTEN FAILED!!");
                                return false;
                        }
                        return true;
                }
                 // 4. 向服务器发起连接
                bool Connect(const std:: string& ip,uint16_t port) {
                
                        struct sockaddr_in addr;
                        addr.sin_family = AF_INET;
                        addr.sin_port = htons(port);
                        addr.sin_addr.s_addr = inet_addr(ip.c_str());
                        socklen_t len = sizeof(struct sockaddr_in);
                        // int bind(int sockfd,struct sockaddr * addr,socklen_t len);
                        int ret = connect(_sockfd,(struct sockaddr*)&addr,len);
                        if (ret < 0) {
                                ERR_LOG("CONNECT ADDRESS FAILED!!!!");
                                return false;
                        }
                        return true;
                } 
                // 5. 获取新连接
                int Accept() {
                
                        // int accept(int sockfd,struct sockaddr* addr,socklen_t *len) /
                        int newfd = accept(_sockfd,NULL,NULL);
                        if (newfd < 0) {
                                ERR_LOG("SOCKET ACCEPT FAILED!!!!");
                                return false;
                        }
                        return newfd;
                }
                ssize_t Recv(void *buf,size_t len,int flag = 0){
                        // 6.接收数据
                        //有符号长整型 
                        //ssize_t Recv(int sockfd,void* buf,size_t len,int flag);
                        ssize_t ret = recv(_sockfd,buf,len,flag);
                        if (ret <= 0) {
                                // EAGAIN 当前socket的接收缓冲区没有数据来,在非阻塞二点情况下才会有这个错误
                                // ENTER 当前socket的阻塞等待,被信号打断了
                                if (errno == EAGAIN || errno == EINTR) {
                                        return 0; // 没收到数据
                                }
                                ERR_LOG("SOCKET RECV FAILED!!");
                                return -1; // 出错
                        }
                        return ret;
                }
                ssize_t nonBlockRecv(void* buf,size_t len) {
                        return Recv(buf,len,MSG_DONTWAIT); // MSG_DONTWAIT 表示当前接受为非阻塞
                }
	        // 7.发送数据
                ssize_t Send(const void* buf,size_t len,int flag = 0) {
                        // ssize_t send(int sockfd,void *data,size_t len,int flag) 
                        ssize_t ret = send(_sockfd,buf,len,flag);
                        if (ret < 0) {
                                ERR_LOG("SOCKET SEND FAILED!!");
                                return -1; // 出错
                        }
                        return ret; // 实际发送数据长度!!
                }
                ssize_t nonBlockSend(void* buf,size_t len) {
                        return Send(buf,len,MSG_DONTWAIT); // MSG_DONTWAIT 表示当前接受为非阻塞
                }
	        // 8.关闭套接字
                void Close() {
                        if (_sockfd != -1) {
                                close(_sockfd);
                                _sockfd = -1;
                        }
                
                }
	        // 9.创建一个服务端链接
                bool createServer(uint16_t port, const std::string &ip = "0.0.0.0", bool block_flag = false) {
                        // 1.创建套接字 2. 绑定地址 3.开始监听 4.设置非阻塞 5.启动地址重用
                        if (Create() == false) return false;
                        if (Bind(ip,port) == false) return false;
                        if (Listen() == false) return false;
                       if (block_flag) NonBlock();
                        ReuseAddress();
                        return true;
                }
                // 10.创建一个客户端链接 
                bool createClient(uint16_t port, const std::string &ip) {
                        if (Create() == false) return false;
                        if (Connect(ip,port) == false) return false;
                        return true;
                }

                // 11. 设置套接字选项——开启地址端口重用!
                void ReuseAddress() {
                        // int setsockopt(int fd,int leve,int optname,void *val,int vallen)
                        int val = 1;
                        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&val, sizeof(int));
                        val = 1;
                        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, (void*)&val, sizeof(int));
                }
                // 12. 设置套接字阻塞属性——设置为非阻塞! 
                void NonBlock() {
                        int flag = fcntl(_sockfd, F_GETFL, 0);
                        fcntl(_sockfd, F_SETFL, flag | O_NONBLOCK);
                }

};

五、测试

(一)tcp_cli.cc

#include "../source/server.hpp"

int main() {
    Socket cli_sock;
    cli_sock.createClient(8500,"127.0.0.1");
    std::string str = "nihao";
    cli_sock.Send(str.c_str(),str.size());
    char buf[1024] = {0};
    cli_sock.Recv(buf,1023);
    DBG_LOG("%s",buf);
    return 0;
}

(二)tcp_srv.cc

#include "../source/server.hpp"

int main() {
    Socket lst_sock;
    bool ret = lst_sock.createServer(8500);
    while (1) {
        int newfd = lst_sock.Accept();
        if (newfd < 0) {
            continue;
        }
        Socket cli_sock(newfd);
        char buf[1024] = {0};
        int ret = cli_sock.Recv(buf,1023);
            if(ret < 0) {
            cli_sock.Close();
        }
        cli_sock.Send(buf,ret);
        cli_sock.Close();
    }
    lst_sock.Close();
    return 0;
}

(三)makefile

all:client server
client:tcp_cli.cc
	g++ -std=c++11 $^ -o $@
server:tcp_srv.cc
	g++ -std=c++11 $^ -o $@

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

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

相关文章

WordPress外贸建站Astra免费版教程指南(2023)

在WordPress的外贸建站主题中&#xff0c;有许多备受欢迎的主题&#xff0c;如AAvada、Astra、Hello、Kadence等最佳WordPress外贸主题&#xff0c;它们都能满足建站需求并在市场上广受认可。然而&#xff0c;今天我要介绍的是一个不断颠覆建站人员思维的黑马——Astra主题。 …

【计算机网络】DNS原理介绍

文章目录 DNS提供的服务DNS的工作机理DNS查询过程DNS缓存 DNS记录和报文DNS记录DNS报文针对DNS服务的攻击 DNS提供的服务 DNS&#xff0c;即域名系统(Domain Name System) 提供的服务 一种实现从主机名到IP地址转换的目录服务&#xff0c;为Internet上的用户应用程序以及其他…

网页采集工具-免费的网页采集工具

在当今数字化时代&#xff0c;网页采集已经成为了众多领域的必备工具。无论是市场研究、竞争情报、学术研究还是内容创作&#xff0c;网页采集工具都扮演着不可或缺的角色。对于许多用户来说&#xff0c;寻找一个高效、免费且易于使用的网页采集工具太不容易了。 147SEO工具的强…

ElasticSearch更新数据后查不到的问题

一、前言 上一篇文章还是2个星期前写的&#xff0c;近段时间有点懒&#xff0c;本来这篇也不太愿意动笔写&#xff0c;但这两天关注数据&#xff0c;发现新的一年已经收获了4个粉丝&#xff0c;首先感谢大家的关注&#xff0c;我以后还是会尽量多写一点。这篇文章讲一下今天我…

从零手搓一个【消息队列】BrokerServer 创建核心类, 数据库设计与实现

文章目录 一、创建核心类1, 交换机2, 交换机类型3, 队列4, 绑定5, 交换机转发 & 绑定规则6, 消息7, 消息属性 二、数据库设计1, 使用 SQLite2, 使用 MyBatis2.1, 创建 Interface2.2, 创建 xml 文件 三、硬盘管理 -- 数据库1, 创建 DataBaseManager 类2, init() 初始化数据库…

【ONE·Linux || 多线程(一)】

总言 多线程&#xff1a;进程线程基本概念、线程控制、互斥与同步。 文章目录 总言1、基本概念1.1、补充知识1.1.1、堆区细粒度划分1.1.2、虚拟地址到物理空间的转化 1.2、如何理解线程、进程1.2.1、如何理解线程&#xff1f;1.2.2、如何理解进程&#xff1f; 1.3、实践操作1.…

职业规划,什么是职业兴趣 - 我喜欢做什么?

能够在工作岗位上面做出成绩的人&#xff0c;都是结合自身兴趣&#xff0c;对职业进行合理规划的那一类。尤其是步入中年以后&#xff0c;能够创造出巨大价值的人&#xff0c;无一例外都是喜欢自己职业的人。没有将兴趣融入工作的人&#xff0c;只能够忍受默默无闻地活着&#…

liunx的攻击

1.场景和分析 2.病毒分析 3.解决步骤

Linux学习记录——삼십일 socket编程---TCP套接字

文章目录 TCP套接字简单通信1、服务端1、基本框架2、获取连接 2、客户端3、多进程4、多线程5、线程池6、简单的日志系统7、守护进程8、其它 TCP套接字简单通信 本篇gitee 学习完udp套接字通信后&#xff0c;再来看TCP套接字。 四个文件tcp_server.hpp&#xff0c; tcp_serve…

黑豹程序员-放大招-架构师学习路线图

文章目录 全栈软件架构师技术路线六环能力图一、开发基础二、增强软件三、海量数据四、软件智能五、并发增强六、桌面开发 全栈软件架构师技术路线 六环能力图 作为软件开发&#xff0c;我们的任务就是开发软件业务系统。 如果要做好一个软件系统需要的技能是非常多的。我归纳…

分布式链路追踪--SkyWalking7.0.0+es7.0.0

分布式链路追踪–SkyWalking ​ 微服务的出现&#xff0c;的确解决了一些业务痛点&#xff0c;但是也造成了新的问题比如随着调用链的拉长&#xff0c;如果想要知道请求为什么这么慢&#xff0c;这个请求到底经历了哪些环节&#xff0c;又依赖了哪些东西&#xff0c;在微服务架…

基于Java的婚纱影楼管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

Bluespec SytemVerilog 握手协议接口转换

01、引言 由于接口控制信号上的差异&#xff0c;要实现Bluespec SystemVerilog(BSV)生成的代码和外部Verilog代码之间的正确交互是一件比较麻烦同时容易出错的事情。在BSV中, 模块之间的交互都是基于Action或ActionValue这两类method完成。下图展示了使用BSV设计的某一模块的接…

综合应用QGIS软件,实现商场选址分析

一、实验要求 ①离城市主要交通道路50米内&#xff0c;保证商场交通的便利性。 ②在居民区100米内&#xff0c;便于居民步行到商场。 ③距离停车场100米内&#xff0c;便于顾客停车。 ④距离其他商场500米范围之外&#xff0c;减少竞争压力。 二、实验数据 ①城市地区主要…

机器学习算法基础--层次聚类法

文章目录 1.层次聚类法原理简介2.层次聚类法基础算法演示2.1.Single-linkage的计算方法演示2.2.Complete-linkage的计算方法演示2.3.Group-average的计算方法演示 3.层次聚类法拓展算法介绍3.1.质心法原理介绍3.2.基于中点的质心法3.3.Ward方法 4.层次聚类法应用实战4.1.层次聚…

Java21 新特性

文章目录 1. 概述2. JDK21 安装与配置3. 新特性3.1 switch模式匹配3.2 字符串模板3.3 顺序集合3.4 记录模式&#xff08;Record Patterns&#xff09;3.5 未命名类和实例的main方法&#xff08;预览版&#xff09;3.6 虚拟线程 1. 概述 2023年9月19日 &#xff0c;Oracle 发布了…

【Linux】完美解决ubuntu18.04下vi不能使用方向键和退格键

今天在刚安装完ubuntu18.04&#xff0c;发现在使用vi命令配置文件时使用方向键并不能移动光标&#xff0c;而是出现一堆奇怪的英文字母&#xff0c;使用退格键也不能正常地删除内容&#xff0c;用惯了CentOS的我已经感觉到ubuntu没有centos用着丝滑&#xff0c;但是没办法&…

C++ -- 学习系列 std::deque 的原理与使用

一 deque 是什么? std::deque 是 c 一种序列式容器&#xff0c;其与 vector 类似&#xff0c;其底层内存都是连续的&#xff0c;不同的地方在于&#xff0c; vector 是一端开口&#xff0c;在一端放入数据与扩充空间&#xff0c;而 deque 是双端均开口&#xff0c;都可以放…

lv5 嵌入式开发-10 信号机制(下)

目录 1 信号集、信号的阻塞 2 信号集操作函数 2.1 自定义信号集 2.2 清空信号集 2.3 全部置1 2.4 将一个信号添加到集合中 2.5 将一个信号从集合中移除 2.6 判断一个信号是否在集合中 2.7 设定对信号集内的信号的处理方式(阻塞或不阻塞) 2.8 使进程挂起&#xff08;…

NLP 01(介绍)

一、NLP 自然语言处理 (Natural Language rrocessing,简称NLP) 是计算机科学与语言学中关注于计算机与人类语言间转换的领域。 1.1 发展 规则&#xff1a;基于语法 自然语言处理的应用场景: 语音助手 机器翻译 搜索引擎 智能问答