工作中学到的一些小点

news2024/10/7 2:28:17

1.结构体对齐
记得之前面试的时候被问过这个问题【汗】
这个结构体占多大

struct sExample {
	char c;
	int n;
};

占8字节,问有没有办法让它占5个字节?

#pragma pack(push)	//保存对齐状态
#pragma pack(1)		//设定为1字节对齐

struct sExample {
	char c;
	int n;
};
#pragma pack(pop)	//恢复对齐状态

为什么要加保存和恢复对齐状态?为了不影响别人

#pragma pack(2)

#pragma pack(push)	//保存对齐状态
#pragma pack(1)		//设定为1字节对齐

struct sExample {
	char c;
	int n;
};
#pragma pack(pop)	//恢复对齐状态

struct sDemo {
	char c;
	int n;
};

原来是按2字节对齐的,对sExample设置完后,不要改变原来的对齐方式
这里sizeof(sExample)是5,sizeof(sDemo)是6
(反思,为什么当时学c语言的时候没学过这个?)
2.组播
组播和单播不一样,所以为什么叫组播呢?这个问题其实当时在学校写计算机网络课设的时候就碰到了,当时写的聊天室,实验要求是用组播,但我用的单播,课设也过了,所以这个问题不了了之。

组播技术指的是单个发送者对应多个接收者的一种网络通信。
IP 组播技术有效地解决了单点发送多点接收的问题,实现了 IP 网络中点到多点的高效数据传送,能够大量节约网络带宽、降低网络负载。

组播地址是分类编址的IPV4地址中的D类地址,又叫多播地址,他的前四位必须是1110,所以网络地址的取值范围是224-239(11100000-11101111)

224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其他地址供路由协议使用
224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet
224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效
239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效

一个例子:
服务端:

#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")

#define DEFAULT_BUFLEN 512

using namespace std;

int main()
{
	//Declare and initialize variables
	WSADATA wsaData = { 0 };
	int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		wprintf(L"WSAStartup failed: %d\n", iResult);
		return -1;
	}

	//创建socket
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock == INVALID_SOCKET) {
		wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
		WSACleanup();
		return -1;
	}

	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(8889);

	iResult = bind(sock, (sockaddr*)(&addr), sizeof(addr));
	if (iResult == SOCKET_ERROR) {
		wprintf(L"bind function failed with error: %ld\n", WSAGetLastError());
		WSACleanup();
		return -1;
	}

	struct ip_mreq imr;
	imr.imr_multiaddr.s_addr = inet_addr("234.2.2.2");
	imr.imr_interface.s_addr = INADDR_ANY;
	//加入组播组
	iResult = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(imr));
	if (iResult == SOCKET_ERROR) {
		wprintf(L"setsockopt function failed with error: %ld\n", WSAGetLastError());
		WSACleanup();
		return -1;
	}

	char recvbuf[DEFAULT_BUFLEN] = "";
	int recvbuflen = DEFAULT_BUFLEN;

	sockaddr_in client;
	int clientLen;
	clientLen = sizeof(client);
	memset(&client, 0, clientLen);

	iResult = recvfrom(sock, recvbuf, recvbuflen, 0, (sockaddr*)(&clientLen), &clientLen);
	if (iResult > 0)
		printf("Bytes received: %d\n%s\n", iResult, recvbuf);
	else if (iResult == 0)
		printf("Connection closed\n");
	else
		printf("recv failed: %d\n", WSAGetLastError());

	closesocket(sock);
	WSACleanup();

	system("pause");
	return 0;
}

客户端:

#include <iostream>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <stdio.h>

#pragma comment (lib, "Ws2_32.lib")

#define DEFAULT_BUFLEN 512

using namespace std;

int main()
{
	//Declare and initialize variables
	WSADATA wsaData = { 0 };
	int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (iResult != 0) {
		wprintf(L"WSAStartup failed: %d\n", iResult);
		return -1;
	}

	//创建socket
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sock == INVALID_SOCKET) {
		wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
		WSACleanup();
		return -1;
	}

	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("234.2.2.2");
	addr.sin_port = htons(8889);

	const char *sendbuf = "hello, server";
	iResult = sendto(sock, sendbuf, (int)strlen(sendbuf), 0, (sockaddr*)(&addr), sizeof(addr));
	if (iResult == SOCKET_ERROR) {
		wprintf(L"send failed with error: %d\n", WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}
	printf("send: %d\n", iResult);

	closesocket(sock);
	WSACleanup();

	system("pause");
	return 0;
}

3.网络传输中大小端问题
大小端也是面试中经常被问到的问题。
网络传输中确实需要注意大小端的问题,最近在极客时间上看的网络编程实战中也提到了这个问题。发送端发送时需要将发送的内容转成网络字节序的形式,因为你也不知道接受的主机是大端还是小端,如果你俩都是小端机,万事大吉。但如果发和收的字节序不一样就会出现问题,因此双方都应该以网络字节序交流。
那怎么理解这个事呢?比如现在要发送0x0102,占两个字节,在我电脑(小端机)上内存存放如下:
在这里插入图片描述

先发送低地址的数据0x02,再发送高地址的数据0x01,但如果我的电脑是大端机,则会先发送0x01再发送0x02,效果截然不同。因此,系统中提供了一组函数用来转换:

uint16_t htons (uint16_t hostshort)
uint16_t ntohs (uint16_t netshort)
uint32_t htonl (uint32_t hostlong)
uint32_t ntohl (uint32_t netlong)

函数中的 n 代表的就是 network,h 代表的是 host,s 表示的是 short,l 表示的是 long,分别表示 16 位和 32 位的整数。
值得关注的是,占一个字节的char类型不需要转,因为它只占一个字节,而字节是最小的存储单位。

//一种判断主机大小端的方法:
short j = 0x1234;
if (reinterpret_cast<char &>(j) == 0x12) {
	cout << "The byte order is big-endian" << endl;
}
else {
	cout << "The byte order is little-endian" << endl;
}

4.get_value

template<typename T>
T getValue(const char *buf, T offset) {
	return *((T*)(buf + offset));
}

int main()
{
	const char *buf = "123";
	char value = getValue<char>(buf, 0);
	short sValue = getValue<short>(buf, 1);

	cout << value << endl;
	cout << sValue << endl;
}

输出:

1
13106

5.QByteArray

QByteArray byteArray("gaoyuelong");
qDebug() << byteArray.size();

输出:10

    QByteArray byteArray;

    QDataStream dataStream(&byteArray, QIODevice::WriteOnly);
    dataStream << "gaoyuelong";
    //byteArray的size为15 包含开头用来记录长度的四字节
    qDebug() << byteArray.size();

    QDataStream dataStream1(&byteArray, QIODevice::ReadOnly);

    int iLength = 0;
    dataStream1 >> iLength;
    qDebug() << iLength;

    //data() + 4跳过开头的四字节
    char *data = byteArray.data() + 4;
    while (*data) {
        qDebug() << "[" << *data << "]";
        ++data;
    }

输出:

15
11
[ g ]
[ a ]
[ o ]
[ y ]
[ u ]
[ e ]
[ l ]
[ o ]
[ n ]
[ g ]

需要注意使用dataStream1读取时,开头有四个字节表示长度。

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

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

相关文章

qt串口配置(端口号列表选择/自动保存/初始化模板)复制粘贴直接用

一、前言 废话不多说&#xff0c;写这个作为串口模板&#xff0c;后续会继续补充其他模板&#xff0c;有相识功能直接复制模板里东西到程序中&#xff0c;直接使用&#xff0c;无需大的调整&#xff0c;为自己模板记录&#xff0c;也提供给需要的朋友们。 二、环境 qt5.7 win…

R15.3-15.3-15.3-15.3A_哈威泵_样本及应用

R15.3-15.3-15.3-15.3A_哈威泵_样本及应用R11.8-11.8-11.8-11.8-BABSL_水泥行业用主用于钢厂&#xff0c;油田&#xff0c;水利&#xff0c;飞机&#xff0c;压铸机等重型液压设备。 对油泵R11.8-11.8-11.8-11.8-BABSL_水泥行业用的维护保养应注意以下方面&#xff1a; 1.会腐…

项目需求及架构设计

第2章 项目需求及架构设计 2.1 项目需求分析 用户行为数据采集平台搭建 用户行为数据会以文件的形式存储在服务器&#xff0c;这个阶段需要考虑&#xff1a;采集用户行为数据使用的工具,需要提供详细的设计需求 如&#xff1a;flume&#xff0c;flume采用的 source、channel、…

HDFS的Shell操作

该文章主要为完成实训任务及总结&#xff0c;详细实现过程及结果见【参考文章】 参考文章&#xff1a;https://howard2005.blog.csdn.net/article/details/127170478 文章目录一、 三种Shell命令方式二、FileSystem Shell文档三、常用Shell命令四、实例练习1、创建目录2、查看目…

这位00后经历人生重大变故后,选择了智能家居,选择了Aqara绿米

作者 | 布斯 编辑 | 小沐 出品 | 智哪儿 zhinaer.cn编者按&#xff1a;虽然概念由来已久&#xff0c;但智能家居如今依然属于新兴产业。而这样一个当今在全国范围遍地开花的新型商业存在&#xff0c;已经创造了许多的就业岗位与创业机会&#xff0c;也隐藏着许多让人回味的故事…

Profinet总线模拟输出模块

上电后&#xff0c;耦合器自动识别所有与之相连的 I/O 模块&#xff0c;并根据模块的类型、数据宽度和模块在节点中的位置创建内部本地过程映像。 如果添加、更改或移除 I/O 模块&#xff0c;会建立新的过程映像&#xff0c;过程数据地址会改变。在添加 I/O 模块时&#xff0c…

【MySQL】MySQL执行计划与SQL调优提高查询效率(优化篇)(实战篇)(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

Pixel Difference Networks for Efficient Edge Detection论文笔记

文章目录一、背景知识二、Pixel Difference Convolution&#xff08;PDC&#xff09;1.CPDC2.APDC3.RPDC三、轻量化边缘检测网络A. Block_x_yB. CSAMC. CDCMD. 1*1卷积层E. 深度监督&#xff08;deep supervision&#xff09;F. 损失函数四、实验结果1. 消融实验2.网络可扩展性…

SpringAMQP简介及简单使用

一、SpringAMQP简介 SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能&#xff1a; 自动声明…

Maven基础概念

仓库 仓库用于存储资源&#xff0c;包含各种jar包。 仓库分类&#xff1a; 本地仓库&#xff1a;自己电脑作为仓库&#xff0c;连接远程仓库获取资源。远程仓库&#xff1a;非本地的仓库&#xff0c;为本地仓库提供资源。中央仓库&#xff1a;由Maven团队维护&#xff0c;存…

【Servlet】4:详解请求对象 HttpServletRequest

目录 | 请求对象 HttpServletRequest接口 HttpServletRequest的基本概述 请求对象获取 URL & Method 请求对象获取 参数名 请求对象获取 参数值 参数值乱码问题 本文章属于后端全套笔记的第三部分 &#xff08;更新中&#xff09;【后端入门到入土&#xff01;】Java…

CAN电压测试

CAN总线&#xff1a; 一般用在汽车&#xff0c;伺服驱动器&#xff0c;步进驱动器&#xff0c;舵机&#xff0c;分布式io等设备上。 有以太网转CAN和4G网转CAN。 当然得到数据后&#xff0c;可以往RS485等上面转。 只需要2根线&#xff1a; H和L线&#xff0c;终端再并联120…

Linux history 命令相关使用以及配置

Linux history 命令相关使用以及配置 Linux history 新手学习 shell 的时候都知道 history 命令能帮助我们查看之前运行的命令集合&#xff0c;通过这个能够帮我们回忆之前的命令&#xff0c;以及进行各种排错等等。 比如我们直接输入 history 进行查看&#xff1a; histor…

Flutter高仿微信-第20篇-支付-充值

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; /*** Author : wangning* Email : maoning20080809163.…

Android AIDL跨进程通信基础(多端情况)

简介 AIDL建议在来自不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL&#xff0c;其他情况下你都可以选择其他方法&#xff0c;如使用 Messenger&#xff0c;也能跨进程通信。可见 AIDL 是处理多线程、多客户端并发访问的&#xff0c;而 Messenger 是单线程…

年末盘点时间——用Python绘制饼状图对商品库存进行分析

人生苦短&#xff0c;我用python 存货盘点最重要的是什么&#xff0c;盘点比例要达到&#xff0c; 比如说要达到80%&#xff0c;于是就拿着企业给导的进销存明细表&#xff0c; 于是就开始筛选大金额的存货作为选择的样本&#xff0c; 这样就够比例了。 可是实际盘点的时候…

手把手教你在ARM板上写一个驱动程序!

摘要&#xff1a;搞嵌入式有两个方向&#xff0c;一个是嵌入式软件开发(MCU方向)&#xff0c;另一个是嵌入式软件开发(Linux方向)。其中MCU方向基本是裸机开发和RTOS开发。而Linux开发方向又分为驱动开发和应用开发。其中应用开发相比于驱动开发来说简单一些&#xff0c;因为搞…

初阶指针---从入门到入坟

今天我们来见识一下c语言里让万千少年少女从入门到入坟的一道大门槛——指针 目录 1.指针是什么&#xff1f; 2.指针和指针类型 3.野指针 4. 指针运算 5. 指针和数组 6. 二级指针 7. 指针数组 1.指针是什么&#xff1f; 指针理解的2个要点&#xff1a; 1. 指针是内存中一…

C语言:计算阶乘与计算从1加到100的代码对比:都要用到3个变量,不同之处在于表达式

计算1 到 100 之间所有整数之和 #include <stdio.h> int main() {int i1,total0;while(i<100)//不能在 while 后面加分号{totali;i;//循环内要有使循环趋近于假的操作}printf("%d\n",total);return 0; } 和下面对比&#xff0c;只不过是100用输入j来代替了 …

将windows的显示器作为linux的扩展屏

这里写自定义目录标题前言WinLinuxRequirementsBuild and install运行前言 测试的linux系统为ubuntu 18.04测试的windows系统为win10将windows的显示器作为linux的扩展屏&#xff0c;需要使用微软的Miracast技术。windows自带就不多说了&#xff0c;linux使用的是这个开源软件…