实习日记(5-18)Socket与MQTT

小记

这里淘到一篇讲Socket的博客:
https://www.jianshu.com/p/066d99da7cbd
这一篇也不错:https://www.cnblogs.com/hissia/p/5730135.html

简单梳理一下:

什么是Socket

一张图让你知道Socket在哪里用到:
在这里插入图片描述
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

它是计算机之间进行通信的一种约定或一种方式。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。
  我的理解就是Socket就是该模式的一个实现:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
  Socket()函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

网络通讯
网络通讯中如何标识主机唯一

TCP/IP协议已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机

网络通讯中如何标识进程唯一

传输层协议+端口可以唯一标识主机中的应用程序(进程),因此,我们利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互

Socket通讯两种方式
  • SOCK_STREAM:表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。
  • SOCK_DGRAM:表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。
      例如:QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响

这里跟TCP、UDP很像

TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。

UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。

关于TCP是一种流模式的协议,UDP是一种数据报模式的协议,这里要说明一下,TCP是面向连接的,也就是说,在连接持续的过程中,socket中收到的数据都是由同一台主机发出的(劫持什么的不考虑),因此,知道保证数据是有序的到达就行了,至于每次读取多少数据自己看着办。

而UDP是无连接的协议,也就是说,只要知道接收端的IP和端口,且网络是可达的,任何主机都可以向接收端发送数据。这时候,如果一次能读取超过一个报文的数据,则会乱套。比如,主机A向发送了报文P1,主机B发送了报文P2,如果能够读取超过一个报文的数据,那么就会将P1和P2的数据合并在了一起,这样的数据是没有意义的。

Socket常用函数接口及其原理

tcpscoket实现图解:
在这里插入图片描述

udpscoket图解:
在这里插入图片描述

socket调用库函数主要有:

创建套接字 

        Socket(af,type,protocol)

建立地址和套接字的联系 

        bind(sockid, local addr, addrlen)

服务器端侦听客户端的请求 

        listen( Sockid ,quenlen)

建立服务器/客户端的连接 (面向连接TCP) 

        客户端请求连接 

        Connect(sockid, destaddr, addrlen)

        服务器端等待从编号为Sockid的Socket上接收客户连接请求 

        newsockid=accept(Sockid,Clientaddr, paddrlen)

发送/接收数据 

        面向连接:

        send(sockid, buff, bufflen) 
        recv( )

        面向无连接:

        sendto(sockid,buff,,addrlen) 
        recvfrom( )

释放套接字 

        close(sockid)

具体内容还是需要去看上面的博客

TcpSocket和UdpSocket

Tcp:
服务器的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,然后调用listen在相应的socket上监听,当accpet接收到一个连接服务请求时,将生成一个新的socket。服务器显示该客户机的IP地址,并通过新的socket向客户端发送字符串" hi,I am server!"。最后关闭该socket。

客户端的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,请求连接服务器,通过新的socket向客户端发送字符串" hi,I am client!"。最后关闭该socket。

Udp:
服务器的工作流程:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,接收到一个客户端时,服务器显示该客户端的IP地址,并将字串返回给客户端。

客户端的工作流程:首先调用socket函数创建一个Socket,填写服务器地址及端口号,从标准输入设备中取得字符串,将字符串传送给服务器端,并接收服务器端返回的字符串。最后关闭该socket。

笔记

C 枚举

在C语言中,枚举是之中基本数据类型
枚举格式:

enum 枚举名 {枚举元素1,枚举元素2,……};

实例:
假如一周有七天,不用枚举定义如下:

#define MON  1
#define TUE  2
#define WED  3
#define THU  4
#define FRI  5
#define SAT  6
#define SUN  7

使用枚举定义如下:

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

注意:
第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

enum season {spring, summer=3, autumn, winter};

在这个例子中 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5

枚举实例
    enum day
    {
        saturday=1,
        sunday,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    };
    int week;
    printf("week:");
    scanf("%d", &week);
    switch (week)
    {
        case saturday:
            printf("saturday");
            break;
        case sunday:
            printf("sunday");
            break;
    }

在这里插入图片描述
注意:
应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。

单精度和双精度

单精度:float
双精度:double
在32位系统中,float占4个字节,double占8个字节。

    float a=1.1;
    double b=1.1;
    printf("float_length:%d",sizeof(a));
    printf("\n");
    printf("double_length:%d",sizeof(b));
    printf("\n");

在这里插入图片描述
双精度精确度高,可以精确到小数点后15位有效数,单精度只能精确到7位

定点数和浮点数

定点数:
小数点固定的位于实数所有数字中间的某个位置。货币的表达就可以使用这种方式,比如 99.00 或者 00.99 可以用于表达具有四位精(Precision)小数点后有两位的货币值。
浮点数:
用一个尾数(Mantissa ),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.45 用十进制科学计数法可以表达为 1.2345 × 102 ,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果。

MQTT协议
MQTT协议是干嘛的

MQTT教程:https://www.runoob.com/w3cnote/mqtt-intro.html

自己梳理一下:

MQTT (Message Queue Telemetry Transport),翻译成中文就是,遥测传输协议,其主要提供了订阅/发布两种消息模式,更为简约、轻量,易于使用,特别适合于受限环境(带宽低、网络延迟高、网络通信不稳定)的消息分发,属于物联网(Internet of Thing)的一个标准传输协议。

MQTT是应用层的协议。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器的通信协议。

MQTT和TCP、WebSocket的关系可以用下图一目了然:
在这里插入图片描述
MQTT协议专注于网络、资源受限环境,建立之初不曾考虑WEB环境。HTML5 Websocket是建立在TCP基础上的双通道通信,和TCP通信方式很类似,适用于WEB浏览器环境。虽然MQTT基因层面选择了TCP作为通信通道,但我们添加个编解码方式,MQTT over Websocket也可以的。这样做的好处,MQTT的使用范畴被扩展到HTML5、桌面端浏览器、移动端WebApp、Hybrid等,多了一些想像空间。这样看来,无论是移动端,还是WEB端,MQTT都会有自己的使用空间。

MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

在这里插入图片描述

MQTT实现

实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。

MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:

有三种消息发布服务质量:

“至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。qos=0

“至少一次”,确保消息到达,但消息重复可能会发生。qos=1

“只有一次”,确保消息到达一次。在一些要求比较严格的计费系统中,可以使用此级别。在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到一次。qos=2

Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload);

payload,可以理解为消息的内容,是指订阅者具体要使用的内容。

MQTT协议数据包结构

在MQTT协议中,一个MQTT数据包由:固定头(Fixed header)、可变头(Variable header)、消息体(payload)三部分构成。MQTT数据包结构如下:

  • 固定头(Fixed header)。存在于所有MQTT数据包中,表示数据包类型及数据包的分组类标识。
  • 可变头(Variable header)。存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容。
  • 消息体(Payload)。存在于部分MQTT数据包中,表示客户端收到的具体内容。

具体还是要看上述博客中

  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值