C++学习笔记(52)

345、封装 socket 一、demo7.cpp
/*
* 程序名:demo7.cpp,此程序用于演示封装 socket 通讯的客户端
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;
class ctcpclient // TCP 通讯的客户端类。
{
private:
int m_clientfd; // 客户端的 socket,-1 表示未连接或连接已断开;>=0 表示有效的
socket。
string m_ip; // 服务端的 IP/域名。
unsigned short m_port; // 通讯端口。
public:
ctcpclient():m_clientfd(-1) {}
// 向服务端发起连接请求,成功返回 true,失败返回 false。
bool connect(const string &in_ip,const unsigned short in_port)
{
if (m_clientfd!=-1) return false; // 如果 socket 已连接,直接返回失败。
m_ip=in_ip; m_port=in_port; // 把服务端的 IP 和端口保存到成员变量中。
// 第 1 步:创建客户端的 socket。
if ( (m_clientfd = socket(AF_INET,SOCK_STREAM,0))==-1) return false;
// 第 2 步:向服务器发起连接请求。
struct sockaddr_in servaddr; // 用于存放协议、端口和 IP 地址的结构体。
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET; // ①协议族,固定填 AF_INET。
servaddr.sin_port = htons(m_port); // ②指定服务端的通信端口。
struct hostent* h; // 用于存放服务端 IP 地址(大端序)的结构体的
指针。
if ((h=gethostbyname(m_ip.c_str()))==nullptr ) // 把域名/主机名/字符串格式的 IP转换成结
构体。
{
::close(m_clientfd); m_clientfd=-1; return false;
}
memcpy(&servaddr.sin_addr,h->h_addr,h->h_length); // ③指定服务端的 IP(大端序)。
// 向服务端发起连接清求。
if (::connect(m_clientfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
{
::close(m_clientfd); m_clientfd=-1; return false;
}
return true;
}
// 向服务端发送报文,成功返回 true,失败返回 false。
bool send(const string &buffer) // buffer 不要用 const char *
{
if (m_clientfd==-1) return false; // 如果 socket 的状态是未连接,直接返回失败。
if ((::send(m_clientfd,buffer.data(),buffer.size(),0))<=0) return false;
return true;
}
// 接收服务端的报文,成功返回 true,失败返回 false。
// buffer-存放接收到的报文的内容,maxlen-本次接收报文的最大长度。
bool recv(string &buffer,const size_t maxlen)
{ // 如果直接操作 string 对象的内存,必须保证:1)不能越界;2)操作后手动设置数据的大小。
buffer.clear(); // 清空容器。
buffer.resize(maxlen); // 设置容器的大小为 maxlen。
int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0); // 直接操作 buffer 的内存。
if (readn<=0) { buffer.clear(); return false; }
buffer.resize(readn); // 重置 buffer 的实际大小。
return true;
}
// 断开与服务端的连接。
bool close()
{
if (m_clientfd==-1) return false; // 如果 socket 的状态是未连接,直接返回失败。
::close(m_clientfd);
m_clientfd=-1;
return true;
} ~ctcpclient(){ close(); }
};
int main(int argc,char *argv[])
{
if (argc!=3)
{
cout << "Using:./demo7 服务端的 IP 服务端的端口\nExample:./demo7 192.168.101.138
5005\n\n";
return -1;
}
ctcpclient tcpclient;
if (tcpclient.connect(argv[1],atoi(argv[2]))==false) // 向服务端发起连接请求。
{
perror("connect()"); return -1;
}
// 第 3 步:与服务端通讯,客户发送一个请求报文后等待服务端的回复,收到回复后,再发下一
个请求报文。
string buffer;
for (int ii=0;ii<10;ii++) // 循环 3 次,将与服务端进行三次通讯。
{
buffer="这是第"+to_string(ii+1)+"个超级女生,编号"+to_string(ii+1)+"。";
// 向服务端发送请求报文。
if (tcpclient.send(buffer)==false)
{
perror("send"); break;
}
cout << "发送:" << buffer << endl;
// 接收服务端的回应报文,如果服务端没有发送回应报文,recv()函数将阻塞等待。
if (tcpclient.recv(buffer,1024)==false)
{
perror("recv()"); break;
}
cout << "接收:" << buffer << endl;
sleep(1);
}
}
二、demo8.cpp
/*
* 程序名:demo8.cpp,此程序用于演示封装 socket 通讯的服务端
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;
class ctcpserver // TCP 通讯的服务端类。
{
private:
int m_listenfd; // 监听的 socket,-1 表示未初始化。
int m_clientfd; // 客户端连上来的 socket,-1 表示客户端未连接。
string m_clientip; // 客户端字符串格式的 IP。
unsigned short m_port; // 服务端用于通讯的端口。
public:
ctcpserver():m_listenfd(-1),m_clientfd(-1) {}
// 初始化服务端用于监听的 socket。
bool initserver(const unsigned short in_port)
{
// 第 1 步:创建服务端的 socket。
if ( (m_listenfd=socket(AF_INET,SOCK_STREAM,0))==-1) return false;
m_port=in_port;
// 第 2 步:把服务端用于通信的 IP 和端口绑定到 socket 上。
struct sockaddr_in servaddr; // 用于存放协议、端口和 IP 地址的结构体。
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET; // ①协议族,固定填 AF_INET。
servaddr.sin_port=htons(m_port); // ②指定服务端的通信端口。
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); // ③如果操作系统有多个 IP,全部的 IP 都
可以用于通讯。
// 绑定服务端的 IP 和端口(为 socket 分配 IP 和端口)。
if (bind(m_listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
{
close(m_listenfd); m_listenfd=-1; return false;
}
// 第 3 步:把 socket 设置为可连接(监听)的状态。
if (listen(m_listenfd,5) == -1 )
{
close(m_listenfd); m_listenfd=-1; return false;
}
return true;
}
// 受理客户端的连接(从已连接的客户端中取出一个客户端),
// 如果没有已连接的客户端,accept()函数将阻塞等待。
bool accept()
{
struct sockaddr_in caddr; // 客户端的地址信息。
socklen_t addrlen=sizeof(caddr); // struct sockaddr_in 的大小。
if ((m_clientfd=::accept(m_listenfd,(struct sockaddr *)&caddr,&addrlen))==-1) return
false;
m_clientip=inet_ntoa(caddr.sin_addr); // 把客户端的地址从大端序转换成字符串。
return true;
}
// 获取客户端的 IP(字符串格式)。
const string & clientip() const
{
return m_clientip;
}
// 向对端发送报文,成功返回 true,失败返回 false。
bool send(const string &buffer)
{
if (m_clientfd==-1) return false;
if ( (::send(m_clientfd,buffer.data(),buffer.size(),0))<=0) return false;
return true;
}
// 接收对端的报文,成功返回 true,失败返回 false。
// buffer-存放接收到的报文的内容,maxlen-本次接收报文的最大长度。
bool recv(string &buffer,const size_t maxlen)
{
buffer.clear(); // 清空容器。
buffer.resize(maxlen); // 设置容器的大小为 maxlen。
int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0); // 直接操作 buffer 的内存。
if (readn<=0) { buffer.clear(); return false; }
buffer.resize(readn); // 重置 buffer 的实际大小。
return true;
}
// 关闭监听的 socket。
bool closelisten()
{
if (m_listenfd==-1) return false;
::close(m_listenfd);
m_listenfd=-1;
return true;
}
// 关闭客户端连上来的 socket。
bool closeclient()
{
if (m_clientfd==-1) return false;
::close(m_clientfd);
m_clientfd=-1;
return true;
} ~ctcpserver() { closelisten(); closeclient(); }
};
int main(int argc,char *argv[])
{
if (argc!=2)
{
cout << "Using:./demo8 通讯端口\nExample:./demo8 5005\n\n"; // 端口大于 1024,
不与其它的重复。
cout << "注意:运行服务端程序的 Linux 系统的防火墙必须要开通 5005 端口。\n";
cout << " 如果是云服务器,还要开通云平台的访问策略。\n\n";
return -1;
}
ctcpserver tcpserver;
if (tcpserver.initserver(atoi(argv[1]))==false) // 初始化服务端用于监听的 socket。
{
perror("initserver()"); return -1;
}
// 受理客户端的连接(从已连接的客户端中取出一个客户端),
// 如果没有已连接的客户端,accept()函数将阻塞等待。
if (tcpserver.accept()==false)
{
perror("accept()"); return -1;
}
cout << "客户端已连接(" << tcpserver.clientip() << ")。\n";
string buffer;
while (true)
{
// 接收对端的报文,如果对端没有发送报文,recv()函数将阻塞等待。
if (tcpserver.recv(buffer,1024)==false)
{
perror("recv()"); break;
}
cout << "接收:" << buffer << endl;
buffer="ok";
if (tcpserver.send(buffer)==false) // 向对端发送报文。
{
perror("send"); break;
}
cout << "发送:" << buffer << endl;
}
}
 

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

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

相关文章

DHASH感知算法计算视频相邻帧的相似度

一个朋友想用python来读取视频帧&#xff0c;根据帧和帧之间相似度判断剪辑痕迹&#xff1b;但是最后发现并没什么用…… 原理就是遍历地读取图像相邻帧&#xff0c;将图像相邻帧前处理后&#xff0c;缩小什么的&#xff0c;计算d_hash,然后计算其汉明距离&#xff0c;然后把汉…

webstorm的缩进设置(过度缩进解释)

在编写前端代码时 缩进规范一般被认为是2个空格 而非默认的4个空格 当我们通过webstorm去编写前端代码时 我们可以通过setting->Code Style->html/css/js指定的界面中去设置tab/indent/continuation indent 具体的话 我们将html/css/js操作界面中的tab/indent设置为2个空…

LEED绿色建筑认证

LEED&#xff08;Leadership in Energy and Environmental Design&#xff09;绿色建筑评估体系是由美国绿色建筑协会&#xff08;USGBC&#xff09;建立并推行的一项权威评估标准。 一、LEED体系概述 LEED体系是目前在世界各国的各类建筑环保评估、绿色建筑评估以及建筑可持…

Redis 5 种基本数据类型的前两个详解

Redis 共有 5 种基本数据类型&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;集合&#xff09;、Hash&#xff08;散列&#xff09;、Zset&#xff08;有序集合&#xff09;。 这 5 种数据类型是直接提供给用户使用的&…

提交gitlab

1.gitlab上新建项目 2.git clone url把新项目拉下来 3.git add ./* 把需要提交的文件全部新增 4.git config --global user.email “yetuo.zhuqxsk.local” 身份认证一下 5.git commit -m “asr语音识别-对外服务” 提交 6.git push origin 推送进去 git init git add . git c…

SAP ABAP 代码搜索工具 CODE_SCANNER

SAP ABAP 代码搜索工具 CODE_SCANNER 作为一个熟练的 ABAP 经常要查一下某个function有没有被别的程序调用&#xff0c;或者查看某个function在参考别的程序的调用方法。这就会经常用到 CODE_SCANNER 这个TCODE。 例子一&#xff1a;例如查询 某个smartform 被哪个程序调用了&…

网页打不开、找不到服务器IP地址

现象&#xff1a;网络连接ok&#xff0c;软件能正常使用&#xff0c;当网页打不开。 原因&#xff1a;DNS 配置错误导致网站域名无法正确解析造成。 影响DNS设置的&#xff1a;VPN软件、浏览器DNS服务选择、IPv4属性被修改。 1、VPN代理未关闭 2、浏览器DNS解析选择 3、以太…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【285-296】

文章目录 285. 为什么需要继承286. 继承原理图287. 继承快速入门288. 289. 290. 291. 292. 继承使用细节1,2,3,4,5288.1 继承给编程带来的便利288.2 继承的深入讨论/细节问题 293. 继承本质详解294. 继承课堂练习1295. 继承课堂练习2296. 继承课堂练习3 285. 为什么需要继承 28…

同城O2O系统源码与跑腿配送平台的架构设计与开发方案详解

今天&#xff0c;笔者将与您一同深入探讨同城O2O系统的源码及跑腿配送平台的架构设计与开发方案&#xff0c;助力开发者和企业在这一领域的实践与探索。 一、O2O系统概述 在同城O2O模式中&#xff0c;用户可以通过手机应用或网页平台下单&#xff0c;而配送员则根据订单信息迅…

[图形学]smallpt代码详解(1)

一、简介 本文介绍了著名的99行代码实现全局光照的光线跟踪代码smallpt。 包括对smallpt的功能介绍、编译运行介绍&#xff0c;和对代码的详细解释。希望能够帮助读者更进一步的理解光线跟踪。 二、smallpt介绍 1.smallpt是什么 smallpt(small Path Tracing) 是一个全局光照…

鸿蒙NEXT开始公测,哪些机型可以升级?鸿蒙版微信界面简洁

华为 Harmony OS NEXT 于10月8日正式开启公测&#xff0c;对鸿蒙 NEXT 系统感兴趣&#xff0c;想要第一时间尝鲜鸿蒙系统的话&#xff0c;千万不要错过本篇文章&#xff01; 哪些手机可以参与鸿蒙 NEXT 公测&#xff1f; 首批参与鸿蒙 NEXT 公测的机型有华为 Mate 60 系列、华…

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知&#xff0c;并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…

Java8新特性, 函数式编程及Stream流用法大全

用了多少年的java8了&#xff0c;Lambda表达式和stream流也经常用&#xff0c;但是也仅限于某些用法比较熟练&#xff0c;看见了 Function、Consumer 等函数式接口还是一脸懵逼&#xff0c;现在来全面总结一下java8这些新特性&#xff0c;也为自己后续查找做个备忘。如果你只是…

【C++】模板(初识):函数模板、类模板

本篇主要介绍C中的模板初阶的一些知识。模板分为函数模板和类模板&#xff0c;我们一个一个来看。 1.函数模板 1.1函数模板概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实际的参数类型产生函数特定版本。…

Golang

Golang&#xff0c;通常被称为Go&#xff0c;是由Google开发的一种开源编程语言。它最早由Robert Griesemer、Rob Pike和Ken Thompson在2007年设计并于2009年发布。Golang的设计目标是提高编写简单、高效和并发程序的能力&#xff0c;因此非常适合用于构建高并发的网络服务、分…

滚雪球学MySQL[4.4讲]:数据库的性能调优详解

全文目录&#xff1a; 前言1. 数据库性能调优的重要性2. 数据库性能调优策略2.1 索引优化2.1.1 创建合适的索引示例&#xff1a;创建单列索引和联合索引 2.1.2 避免过度索引2.1.3 使用覆盖索引示例&#xff1a;覆盖索引 2.2 查询优化2.2.1 使用EXPLAIN分析查询示例&#xff1a;…

C++:图的最短路径问题

一、简介 在非网图中&#xff0c;最短路径是指两顶点之间经历的边数最少的路径。在网图中&#xff0c;最短路径是指两顶点之间经历的边上权值之和最少的路径。 路径上的第一个顶点称为源点&#xff0c;最后一个顶点称为终点。 最短路径问题是图的一个比较典型的应用问题。例如&…

QT 通过鼠标事件实现图片的拖动和缩放

通过鼠标拖动来移动图片&#xff0c;并使用鼠标滚轮来缩放图片。 1、实现步骤&#xff1a; 1、移动图片&#xff1a; 使用QPoint记录图片的偏移量&#xff0c;当鼠标拖动时更新这个偏移量&#xff0c;在paintEvent()中根据偏移量绘制图片。2、缩放图片&#xff1a; 使用滚轮…

人工智能平台 PAI-DSW内置通义灵码实操

人工智能平台 PAI&#xff08;Platform for AI&#xff0c;原机器学习平台PAI&#xff09;是 AI Native 的大模型与 AIGC 工程平台&#xff0c;提供包含数据集管理、算力管理、模型工具链、模型开发、模型训练、模型部署、AI资产管理在内的功能模块&#xff0c;内置100种大模型…

02_23 种设计模式之《抽象工厂模式》

文章目录 一、抽象工厂模式抽象工厂模式的结构应用场景 示例代码&#xff08;C&#xff09;注意事项 一、抽象工厂模式 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;隶属于设计模式中的创建型模式&#xff0c;用于产品族的构建。抽象工厂是指当有多个抽象角…