C++学习笔记(51)

三、IP 地址和通讯端口
在计算机中,IPv4 的地址用 4 字节的整数存放,通讯端口用 2 字节的整数(0-65535)存放。
例如:192.168.190.134 3232284294 255.255.255.255
192 168 190 134
大端:11000000 10101000 10111110 10000110
小端:10000110 10111110 10101000 11000000
四、如何处理大小端序
在网络编程中,数据收发的时候有自动转换机制,不需要程序员手动转换,只有向 sockaddr_in 结
体成员变量填充数据时,才需要考虑字节序的问题。
344、万恶的结构体
一、sockaddr 结构体
存放协议族、端口和地址信息,客户端和 connect()函数和服务端的 bind()函数需要这个结构体。
struct sockaddr {
unsigned short sa_family; // 协议族,与 socket()函数的第一个参数相同,填 AF_INET。
unsigned char sa_data[14]; // 14 字节的端口和地址。
};
二、sockaddr_in 结构体
sockaddr 结构体是为了统一地址结构的表示方法,统一接口函数,但是,操作不方便,所以定义了
等价的 sockaddr_in 结构体,它的大小与 sockaddr 相同,可以强制转换成 sockaddr。
struct sockaddr_in {
unsigned short sin_family; // 协议族,与 socket()函数的第一个参数相同,填 AF_INET。
unsigned short sin_port; // 16 位端口号,大端序。用 htons(整数的端口)转换。
struct in_addr sin_addr; // IP 地址的结构体。192.168.101.138
unsigned char sin_zero[8]; // 未使用,为了保持与 struct sockaddr 一样的长度而添加。
};
struct in_addr { // IP 地址的结构体。
unsigned int s_addr; // 32 位的 IP 地址,大端序。
};
三、gethostbyname 函数
根据域名/主机名/字符串 IP 获取大端序 IP,用于网络通讯的客户端程序中。
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name; // 主机名。
char **h_aliases; // 主机所有别名构成的字符串数组,同一 IP 可绑定多个域名。
short h_addrtype; // 主机 IP 地址的类型,例如 IPV4(AF_INET)还是 IPV6。
short h_length; // 主机 IP 地址长度,IPV4 地址为 4,IPV6 地址则为 16。
char **h_addr_list; // 主机的 ip 地址,以网络字节序存储。
};
#define h_addr h_addr_list[0] // for backward compatibility. 转换后,用以下代码把大端序的地址复制到 sockaddr_in 结构体的 sin_addr 成员中。
memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);
四、字符串 IP 与大端序 IP 的转换
C 语言提供了几个库函数,用于字符串格式的 IP 和大端序 IP 的互相转换,用于网络通讯的服务端程
序中。
typedef unsigned int in_addr_t; // 32 位大端序的 IP 地址。
// 把字符串格式的 IP 转换成大端序的 IP,转换后的 IP 赋给 sockaddr_in.in_addr.s_addr。
in_addr_t inet_addr(const char *cp);
// 把字符串格式的 IP 转换成大端序的 IP,转换后的 IP 将填充到 sockaddr_in.in_addr 成员。
int inet_aton(const char *cp, struct in_addr *inp);
// 把大端序 IP 转换成字符串格式的 IP,用于在服务端程序中解析客户端的 IP 地址。
char *inet_ntoa(struct in_addr in);
五、demo5.cpp
/*
* 程序名:demo5.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;
int main(int argc,char *argv[])
{
if (argc!=3)
{
cout << "Using:./demo5 服务端的 IP 服务端的端口\nExample:./demo5 192.168.101.138
5005\n\n";
return -1;
}
// 第 1 步:创建客户端的 socket。
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd==-1)
{
perror("socket"); return -1;
}
// 第 2 步:向服务器发起连接请求。
struct sockaddr_in servaddr; // 用于存放协议、端口和 IP 地址的结构体。
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET; // ①协议族,固定填 AF_INET。
servaddr.sin_port = htons(atoi(argv[2])); // ②指定服务端的通信端口。
struct hostent* h; // 用于存放服务端 IP 地址(大端序)的结构体的指
针。
if ( (h = gethostbyname(argv[1])) == nullptr ) // 把域名/主机名/字符串格式的 IP 转换成结构
体。
{
cout << "gethostbyname failed.\n" << endl; close(sockfd); return -1;
}
memcpy(&servaddr.sin_addr,h->h_addr,h->h_length); // ③指定服务端的 IP(大端序)。
//servaddr.sin_addr.s_addr=inet_addr(argv[1]); // ③指定服务端的 IP,只能用 IP,不能用域名
和主机名。
if (connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1) // 向服务端发起
连接清求。
{
perror("connect"); close(sockfd); return -1;
}
// 第 3 步:与服务端通讯,客户发送一个请求报文后等待服务端的回复,收到回复后,再发下一
个请求报文。
char buffer[1024];
for (int ii=0;ii<10;ii++) // 循环 3 次,将与服务端进行三次通讯。
{
int iret;
memset(buffer,0,sizeof(buffer));
sprintf(buffer,"这是第%d 个超级女生,编号%03d。",ii+1,ii+1); // 生成请求报文内容。
// 向服务端发送请求报文。
if ( (iret=send(sockfd,buffer,strlen(buffer),0))<=0)
{
perror("send"); break;
}
cout << "发送:" << buffer << endl;
memset(buffer,0,sizeof(buffer));
// 接收服务端的回应报文,如果服务端没有发送回应报文,recv()函数将阻塞等待。
if ( (iret=recv(sockfd,buffer,sizeof(buffer),0))<=0)
{
cout << "iret=" << iret << endl; break;
}
cout << "接收:" << buffer << endl;
sleep(1);
}
// 第 4 步:关闭 socket,释放资源。
close(sockfd);
}
六、demo5.cpp
/*
* 程序名:demo6.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;
int main(int argc,char *argv[])
{
if (argc!=2)
{
cout << "Using:./demo6 通讯端口\nExample:./demo6 5005\n\n"; // 端口大于 1024,
不与其它的重复。
cout << "注意:运行服务端程序的 Linux 系统的防火墙必须要开通 5005 端口。\n";
cout << " 如果是云服务器,还要开通云平台的访问策略。\n\n";
return -1;
}
// 第 1 步:创建服务端的 socket。
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if (listenfd==-1)
{
perror("socket"); return -1;
}
// 第 2 步:把服务端用于通信的 IP 和端口绑定到 socket 上。
struct sockaddr_in servaddr; // 用于存放协议、端口和 IP 地址的结构体。
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET; // ①协议族,固定填 AF_INET。
servaddr.sin_port=htons(atoi(argv[1])); // ②指定服务端的通信端口。
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); // ③如果操作系统有多个 IP,全部的 IP 都可
以用于通讯。
//servaddr.sin_addr.s_addr=inet_addr("192.168.101.138"); // ③指定服务端用于通讯的 IP(大
端序)。
// 绑定服务端的 IP 和端口。
if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
{
perror("bind"); close(listenfd); return -1;
}
// 第 3 步:把 socket 设置为可连接(监听)的状态。
if (listen(listenfd,5) == -1 )
{
perror("listen"); close(listenfd); return -1;
}
// 第 4 步:受理客户端的连接请求,如果没有客户端连上来,accept()函数将阻塞等待。
int clientfd=accept(listenfd,0,0);
if (clientfd==-1)
{
perror("accept"); close(listenfd); return -1;
}
cout << "客户端已连接。\n";
// 第 5 步:与客户端通信,接收客户端发过来的报文后,回复 ok。
char buffer[1024];
while (true)
{
int iret;
memset(buffer,0,sizeof(buffer));
// 接收客户端的请求报文,如果客户端没有发送请求报文,recv()函数将阻塞等待。
// 如果客户端已断开连接,recv()函数将返回 0。
if ( (iret=recv(clientfd,buffer,sizeof(buffer),0))<=0)
{
cout << "iret=" << iret << endl; break;
}
cout << "接收:" << buffer << endl;
strcpy(buffer,"ok"); // 生成回应报文内容。
// 向客户端发送回应报文。
if ( (iret=send(clientfd,buffer,strlen(buffer),0))<=0)
{
perror("send"); break;
}
cout << "发送:" << buffer << endl;
}
// 第 6 步:关闭 socket,释放资源。
close(listenfd); // 关闭服务端用于监听的 socket。
close(clientfd); // 关闭客户端连上来的 socket。
}
 

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

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

相关文章

Redis 五种数据类型的操作命令

一、五种数据类型的介绍 五种数据类型如图所示&#xff1a; Redis 是一个开源的键值存储系统&#xff0c;它支持多种数据结构&#xff0c;每种数据结构都有其特定的用例和底层实现。以下是 Redis 的五种主要数据类型&#xff0c;以及它们适合存储的数据类型和底层实现&#xf…

智慧出行:数字孪生三维可视化大屏交通管控系统

智慧出行已成为现代城市发展的重要支柱&#xff0c;数字孪生技术在交通领域的应用不断深化。结合三维可视化技术&#xff0c;打造功能强大的大屏交通管控系统&#xff0c;将对城市交通管理带来巨大变革。该系统通过实时监测和数据分析&#xff0c;提供精准的交通状况显示和预测…

FPUA(1)DIY个人计算机

文章目录 1.需求确定2.硬件选型2.1CPU2.2关于主板2.3硬盘2.4电源2.5散热2.6机箱2.7其他 3.选型成果展示4.组装过程5.欢迎关注技术文章 电脑作为程序员生产力最重要的生产工具&#xff0c;电脑的性能对工作效率有很大影响。电脑组装的每一个环节多少都懂一些&#xff0c;但真正的…

java判断一个字符串是否是回文字符串

代码功能 接收用户输入的字符串&#xff0c;检查该字符串是否为回文&#xff08;即正序和倒序读取都相同&#xff09;&#xff0c;然后输出检查结果。 代码 import java.util.Scanner;public class PalindromeChecker {public static void main(String[] args) {Scanner sc…

微积分-反函数6.6(反三角函数)

在本节中&#xff0c;我们应用 6.1 节的思想来找到所谓反三角函数的导数。在这个任务中&#xff0c;我们遇到了一些困难&#xff1a;由于三角函数不是一对一的&#xff0c;它们没有反函数。这个困难通过限制这些函数的定义域&#xff0c;使其成为一对一的函数&#xff0c;从而得…

软件著作权

软件著作权申请材料 材料一&#xff1a;操作手册 or 设计说明书 操作手册必须有截图&#xff0c;且执行步骤须连贯&#xff0c;从登录开始&#xff0c;到主界面展示&#xff0c;各个界面跳转&#xff0c;以及主要功能介绍&#xff0c;都要符合软件使用者的使用逻辑。文字不能…

气象大模型预测的原理与实践 免费提供气象预测数据

随着气象科学的发展&#xff0c;天气预测技术在过去几十年里取得了显著进步。如今&#xff0c;气象大模型成为了天气预报的核心工具之一。这些模型依赖于复杂的数学、物理和计算方法来模拟大气运动与天气现象&#xff0c;并且在实时数据的支持下&#xff0c;可以预测未来几小时…

YOLO11涨点优化:注意力魔改 | SimAM(无参Attention),一种轻量级的自注意力机制,效果秒杀CBAM、SE

💡💡💡SimAM是一种轻量级的自注意力机制,其网络结构与Transformer类似,但是在计算注意力权重时使用的是线性层而不是点积 💡💡💡本文改进:分别加入到YOLO11的backbone、neck、detect,助力涨点 改进1结构图: 改进2结构图: 改进3结构图: ​ 《YOLOv

OpenHarmony(鸿蒙南向开发)——轻量系统内核(LiteOS-M)【内核通信机制】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 事件 基本概念 事件&#xff08;Event&#xff09;是一种任务间的…

NVIDIA 多实例 GPU

单个 GPU 中包含七个独立实例。 文章目录 前言一、优势1. 扩展 GPU 的使用范围2. 优化 GPU 利用率3. 运行同步工作负载二、 技术原理1. 根据需要调配和配置实例2. 安全、并行运行工作负载三、Blackwell GPU 中的 MIG四、为 IT 和开发运营而打造1. 从数据中心部署到边缘2. 利用容…

【一分钟学C++】指针和引用

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~ 公众号&#xff1a; C学习与探索 | 个人主页&#xff1a; rainInSunny | 个人专栏&#xff1a; Learn OpenGL In Qt 文章目录 指针普通指针函数指针注意事项 引用左值引用右值引用注意事项 指针和引用区别 指针 普通指针 指针是一个…

宝兰德加入中国交通运输协会信息专业委员会,携手共绘交通行业信息化新篇章

近日&#xff0c;中国交通运输协会信息专业委员会&#xff08;以下简称信专委&#xff09;第四届会员代表大会暨第四届一次理事会扩大会议在北京成功举行。宝兰德受邀出席会议&#xff0c;会议总结了第三届理事会的工作&#xff0c;修改了信专委工作规则&#xff0c;选举产生了…

Android Camera系列(四):TextureView+OpenGL ES+Camera

别人贪婪时我恐惧&#xff0c;别人恐惧时我贪婪 Android Camera系列&#xff08;一&#xff09;&#xff1a;SurfaceViewCamera Android Camera系列&#xff08;二&#xff09;&#xff1a;TextureViewCamera Android Camera系列&#xff08;三&#xff09;&#xff1a;GLSur…

一键生成PPT在线使用的保姆级教程:告别加班就靠它

已经过完24年所有的法定节假日的你&#xff0c;上班状态还好吗&#xff1f; 小编人倒是挺飘忽的&#xff0c;就那种人在工位&#xff0c;魂仍在青青大草原的感觉&#xff0c;都是牛马却失去了自由奔跑的权利...... 尤其是还要面对节前一堆没完成的工作&#xff0c;手动完成不…

Day-1 java入门

什么是JAVA? Java是美国的sun 公司(Stanford University Network)在1995年推出的一门计算机高级编程语言。 sun公司于2009年被Oracle(甲骨文)公司收购。 普遍认同Java的联合创始人之一:詹姆斯 高斯林 (James Gosling)为ava之父。 JAVA三大技术平台 Java SE(Java Standa…

大模型 + 在线运行 + ISRealsoft ⇒ 编程运行验证一体化

最近在撰写《计算机的错误计算》系列内容。其中用到三种在线工具&#xff0c;分别是大语言模型、在线运行软件以及 ISRealsoft 在线软件。 系列主要介绍各种软硬件关于数值计算的误差或错误计算。比如&#xff0c;各种数学库 math 中涉及的函数的误差&#xff0c;或算术表达式&…

用伪代码Prompt让LLM进行图推理,生成更精准内容

最近有研究发现&#xff0c;当LLM面对结构化数据&#xff0c;特别是图数据时&#xff0c;LLM的表现却不尽如人意。这几天&#xff0c;来自希腊和法国的研究团队提出了一种创新方法——利用伪代码提示来增强LLM的图推理能力。我基于这项研究先写了一个伪代码的SYSYTEM PROMPT运行…

【智能算法应用】正切搜索算法求解二维路径规划问题

摘要 本文提出了基于正切搜索算法的二维路径规划方法&#xff0c;用于解决包含障碍物的复杂路径规划问题。通过在二维平面中建立障碍物模型和路径目标点&#xff0c;利用正切搜索算法进行路径搜索&#xff0c;找出从起点到终点的最优路径。实验结果显示&#xff0c;该算法在不…

5. PH47 代码框架软件开发环境搭建

5.1. 概述 PH47 软件开发环境搭建比较简单&#xff0c;但毫无疑问非常重要。主要涉及到 stm32 编译链接工具 Keil&#xff1b;代码编辑器 Visual Studio 或者 VS code。 若需要更进一步进行 PH47 框架在不同 stm32 芯片间移植&#xff0c;那么还需要Stm32CubeMx 初始化代码生成…

Python 如何使用 SQLAlchemy 进行复杂查询

Python 如何使用 SQLAlchemy 进行复杂查询 一、引言 SQLAlchemy 是 Python 生态系统中非常流行的数据库处理库&#xff0c;它提供了一种高效、简洁的方式与数据库进行交互。SQLAlchemy 是一个功能强大的数据库工具&#xff0c;支持结构化查询语言&#xff08;SQL&#xff09;…