工作中学到的一些小点

简介: 工作中学到的一些小点

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读取时,开头有四个字节表示长度。

相关文章
|
开发者
试着做点儿有趣的事情
一个游戏怎样才算是做完了?这是个因人而异的问题。有些游戏还没有做出来就做完了,因为开发者不想再做了。有的游戏看上去做完了,但是后续还在不停的更新,那我们就说这个游戏其实还没有做完。至于如何算是做完了,我觉得这应该交由该游戏的制作者来决定。
86 0
|
小程序 数据安全/隐私保护 计算机视觉
切勿外传,我要把我的写作“小心思”放出来了!| 年终总结之学习篇🚩
切勿外传,我要把我的写作“小心思”放出来了!| 年终总结之学习篇🚩
177 0
切勿外传,我要把我的写作“小心思”放出来了!| 年终总结之学习篇🚩
|
存储 缓存 负载均衡
10大高性能开发宝石,我要消灭一半程序员!
10大高性能开发宝石,我要消灭一半程序员!
148 0
10大高性能开发宝石,我要消灭一半程序员!
|
Java C语言
计算机教育中缺失的一课,劝学弟学妹们一句,一定要趁早补上,工作后会事半功倍!
各位学弟学妹们好,作为稍微年长的我(岁月是把杀猪刀啊),今天就给大家补补课。 在大学里的,我们上的计算机专业课程一般都是像操作系统、编译原理、计算机组成原理、计算机网络这些理论课程,还有一些像C语言、Java、.Net这些可以实践的课程,甚至还有可能让你焊一个收音机,但是对于一些基本习惯却很容易被忽略,需要学弟学妹们自行摸索。
216 0
计算机教育中缺失的一课,劝学弟学妹们一句,一定要趁早补上,工作后会事半功倍!
文字处理技术:搞明白了表格是如何参与文字方向的
文字处理技术:搞明白了表格是如何参与文字方向的
106 0
|
设计模式 算法 架构师
狂补计算机基础知识,让我上了瘾,想要尽快和同龄人拉开差距,必须这么干,才有戏!!!!
狂补计算机基础知识,让我上了瘾,想要尽快和同龄人拉开差距,必须这么干,才有戏!!!!
172 0
|
分布式计算 大数据 MaxCompute
三七女生节,看程序媛们选好口红色号,踩上高跟鞋,特别美丽,特别凶狠,特别温柔~
口红,尿不湿,代码;撒娇,卖萌,撕叉;烈焰红唇倾斜45度角写代码;我爱你,你用知性保持着最致命的吸引力!
2112 0
|
Java C++
自学编程的人,都是怎么找到自己的第一份工作的?
转载自:程序之心 每年毕业这么多大学生,很多被培训机构弄去培训了,但是更多的还是选择在大学期间,自力更生去自学,自学的人很多都觉得没有方向太难了,自学怎么坚持下去,自学完了怎么去找到自己的第一份工作。
学习UI设计没有学历能找到工作吗?
​最近很多学员问我,说我没有学历,也不是什么科班出身,也不是本科毕业,更不是名校毕业等等各有说法,然后在学习你们的UI设计,到最后学出来了,能找到工作吗?针对这个问题,来和大家从各方面来探讨一下,到底没有学历能不能从事UI设计工作? 首先我们先从实际的工作需求来看,我们以拉勾网为例,为什么是这个网站,拉勾网是一家专门做互联网招聘的网站,对,只做互联网公司的招聘,UI设计师就职基本都是互联网公司,IT行业。
1687 0
|
程序员 Android开发 架构师
程序员应该把懒作为目标
作为一个合格的程序员, 应该把懒作为目标。 如果你写了足够多的代码的话, 就会发现有很多代码其实是重复的劳动, 比如说写Android界面的时候,你会发现经常要写 View view = (View) findViewById(R.id.xxxx); 这样的代码 频繁的时候可能一个 Activity或者 Fragment要出现十几行的 findViewById… 作为程序员, 这个时候应该找一些能提高效率的东西,让我们懒起来。
817 0