BC26 还有一组专用于 TCP 通信的 AT 指令:《BC26_TCP/IP_AT_Commands_Manual_V1.1》,之前已经有了 Socket 可以进行 TCP 通信,现在又出一个 TCP/IP。或许就是 C# 中的 Socket 与 TCPClient 之间的关系吧,也有可能是早期出了一个简单版本的可用于 TCP 编程的 Socket,之后又出一个功能更为强大的 TCP/IP,而为了兼容老程序,保留了 Socket 而已。总之,前面弄过的东西需要再来一遍。当然 TCP/IP 指令一样可以用于 UDP 通信,本文就不再讲解 UDP 了。

概述(本节译自原文档)

Quectel BC26 模块嵌入了 TCP/IP 协议栈,它使得主机可以直接通过 AT 指令访问 Internet。这大大减少了对 PPP 和外部 TCP/IP 协议栈的依赖,从而将成本降到最低。

Quectel BC26 模块提供了以下 socket 服务:TCP 客户端和 UDP 客户端。

数据访问模式

BC26 模块支持以下两种类型的数据访问模式:

  • 缓存访问模式
  • 直接推送模式

当通过AT+QIOPEN打开一个 socket 服务,可通过参数<access_mode>来指定数据访问模式。在 socket 服务开始后,AT+QISWTMD可用于改变数据访问模式。

  1. 在缓存访问模式中,数据可通过AT+QISEND/AT+QISENDEX指令发送。当接收到数据时,模块将缓存数据并报告一个 URC,格式为:+QIURC:“recv”,<connectID>[,<current_recv_length>]。主机可使用AT+QIRD读取数据。

注意:在缓存访问模式中,如果缓存不为空,模块将不会报告新的 URC,直到所有收到的数据被AT+QIRD从缓存中读取。

  1. 在直接推送模式中,数据可通过AT+QISEND/AT+QISENDEX指令发送。接收到的数据将直接通过以下 URC 输出:
+QIURC: “recv”,<connectID>,<current_recv_length><CR><LF><data>

命令介绍

首先介绍本文所使用到的命令。

AT+QIOPEN=<contextID>,<connectID>,<service_type>,<IP_address>,<remote_port><local_port>,<access_mode>

打开一个 Socket 服务。

  • <contextID>:上下文 ID,范围 1-3,用来干啥的我也不懂,一般情况下设为 1 就行了。
  • <connectID>:Socket 服务编号,其实就是之前讲过的,BC26 最多支持 5 个 Socket,编号 1-4。
  • <service_type>:协议类型,"TCP"或"UDP"。
  • <IP_address>:远程服务器十进制点分隔 IP 地址。
  • <remote_port>:远程服务器端口。
  • <local_port>:可以指定本地通信端口,一般设为 0,表示让程序自动分配。
  • <access_mode>:Socket 服务数据访问模式,0 为缓存访问模式;1 为直接推送模式。

AT+QISTATE=<query_type>,<connectID>

检查 Socket 服务的连接状态。

  • <query_type>:指是通过<contextID>(0)还是通过<connectID>(1)来查询连接状态。一般情况下都是用 1,即<connectID>进行查询。
  • <connectID>:选择 5 个 socket 中的一个查询,范围 0-4。

AT+QISEND=<connectID>,<send_length>,<data>

向服务器发送数据。

  • <send_length>:发送数据的长度,以字节为单位
  • <data>:发送的数据

AT+QISEND=<connectID>

向服务器发送变长数据。发送此命令后,服务器会响应一个>,此时输入要发送的数据,并按快捷键【Ctrl + Z】即可发送给服务器。

AT+QISENDEX=<connectID>,<send_length>,<hex_string>

十六进制字符串格式发送数据,如AT+QISENDEX=0,5,3031323334,是向 0 号 Socket 发送长度为 5 的字符串“01234”。

AT+QIRD=<connectID>,<read_length>

从接收缓存中读取数据。

  • <read_length>:接收的长度,最大值为 512 字节,一般设置为 512 更方便,它会自动按缓存中的数据长度接收。

AT+QICFG="showlength"[,<show_length_mode>]

设置在收到服务器信息时,显示的 URC 中是否包含数据长度信息。

  • <show_length_mode>:设为 0 表示不显示,设为 1 表示显示。

AT+QICFG="viewmode"[,<view_mode>]

设置在读取接收缓存中的数据时的显示格式。

  • <view_mode>

    • 0:格式为:数据长度,剩余长度,数据
    • 1:格式为:数据长度,数据

AT+QICLOSE=<connectID>

关闭连接。

AT+QPING=<contextID>,<host>

Ping 一个远程服务器。

  • <host>:远程主机域名或 IP 地址

AT+QNTP=<contextID>,<server>

从远程服务器同步时间。

  • <server>:远程时间服务器域名或 IP 地址。

服务器端

本文使用的例子较多,经常重新连接,不能再象上一个程序那样,每一个连接就要重启一次程序。这次程序改为可接收多个连接。

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Text; namespace TCPSocket
{
class Program
{
static void Main(string[] args)
{ //设置服务器 IP,如果是腾讯云,必须使用内网地址,而不是公网 IP。
IPAddress ip = IPAddress.Parse("172.16.0.11");
IPEndPoint point = new IPEndPoint(ip, 5000); //端口指定为 5000
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); s.Bind(point);
//开一个单独的线程去侦听客户端连接
Task.Factory.StartNew(() => Listening(s), TaskCreationOptions.LongRunning);
Console.ReadLine(); //按回车关闭程序
} //侦听线程方法
static void Listening(Socket s)
{
s.Listen(5);
Console.WriteLine("服务器开始侦听...");
while (true)
{
Socket subSocket = s.Accept(); //等待新连接
Console.WriteLine("获取一个来自{0}的连接", subSocket.RemoteEndPoint.ToString());
//创建线程接收客户端的消息
Task.Factory.StartNew(() => ReceiveMessage(subSocket), TaskCreationOptions.LongRunning);
}
} //监听客户端连接的线程方法
static void ReceiveMessage(Socket subSocket)
{
byte[] buff = new byte[1024]; //创建一个接收缓冲区
try
{
while (true)
{
int count = subSocket.Receive(buff, buff.Length, SocketFlags.None);
//下面这个判断是非常必要的,否则有可能导致不停地接收到长度为 0 的数据,导致 CPU 占用率100%
if (count == 0)
{
subSocket.Close();
return;
}
//将接收到的数据转化为 ASCII 字符
string recvStr = Encoding.ASCII.GetString(buff, 0, count);
Console.WriteLine($"接收到数据:{recvStr}");
//将消息原样返回
subSocket.Send(buff, count, SocketFlags.None);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
subSocket.Close();//客户端关闭时会引发异常,此时关闭此连接
Console.WriteLine($"客户端{subSocket.RemoteEndPoint.ToString()}已退出连接。");
}
}
}
}

启动程序后,可以最小化去放心做实验了,重连多少次都不需要再回来看一眼。

缓存访问模式

BC26 支持两种数据访问模式:缓存访问模式和直接推送模式。我们首先介绍缓存访问模式的操作。

数据的发送

发送数据使用AT+QISENDAT+QISENDEX两个命令。

发送定长数据

//打开 socket 服务,并指定为缓存访问模式
>>>>>>>>>> AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0 OK +QIOPEN: 0,0 //URC:两个参数分别表示 socket 编号和错误码。 //查询网络状态
>>>>>>>>>> AT+QISTATE=1,0
//倒数第三个参数 2 表示已经连接网络
+QISTATE: 0,"TCP","193.112.19.116",5000,0,2,1,0 OK
//发送长度为10个字节的字符串“1234567890”
>>>>>>>>>> AT+QISEND=0,10,1234567890 OK SEND OK +QIURC: "recv",0 //URC:表示 0 号 socket 接收到数据
//发送长度为5个字节的十六进制格式的字符串“01234”
>>>>>>>>>> AT+QISENDEX=0,5,3031323334 OK SEND OK >>>>>>>>>> AT+QICLOSE=0 //关闭 socket 服务 OK CLOSE OK

此例使用两种方法向服务器发送数据,第一次是直接发送字符串,服务器返回数据,并报告 URC。第二次发送的是编码形式的数据,服务器返回数据但没有报告 URC,因为第一次接收的内容未接收,接收缓存未清空。

发送变长数据

发送变长数据需使用AT+QISEND=0命令,此时服务响应一个>,表示等待用户输入,用户在输入数据后,在结尾添加 0x1A 即可向服务器发送无需标明长度的数据。弄懂这个命令费了一些周折。因为文档写的是输入命令后,按下【Ctrl + Z】键,上帝啊!我想不出哪个串口工具可以使用【Ctrl + Z】来发送命令啊!所有编辑框里的【Ctrl + Z】都是用来 Undo 的。后来发现只要在数据的结尾加上 0x1A 发送即可,0x1A 即代表【Ctrl + Z】键。绝不能结尾加上回车(0x0D,0x0A),必须是以 0x1A 结束。

自己写工具的好处就在于自由,想加啥都行,当即加上此功能,版本改为 1.01。如下图左边【发送区设置】区域内添加了一个“自动添加【Ctrl+Z】”项,选择此项后,再点绿色按钮发送数据,就会自动添加 0x1A 并发送。

按上图所示设置接收区和发送区选项,打开 TCP Client 脚本,所有命令需要使用右边脚本面板中每条命令右边的三角按钮发送。仅在AT+QISEND=0命令之后的输入发送数据时使用发送区进行发送。在选择“自动添加【Ctrl+Z】”项时,由于无法在命令后面添加回车,发送区不能发送命令。以下是完整命令脚本

>>>>>>>>>>  AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0

OK

+QIOPEN: 0,0

>>>>>>>>>>  AT+QISEND=0

>

>>>>>>>>>>  www.iotxfd.cn  //注意,这里的结尾是 0x1A

OK

SEND OK

+QIURC: "recv",0

>>>>>>>>>>  AT+QICLOSE=0

OK

CLOSE OK

在使用这种方式进行发送时,还可以指定基最大发送长度,如AT+QISEND=0,10,表示只发送 10 个字节。下例演示了这种情况:

>>>>>>>>>>  AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0

OK

+QIOPEN: 0,0

>>>>>>>>>>  AT+QISEND=0,10

>

>>>>>>>>>>  www.iotxfd.cn  //注意,这里的结尾是 0x1A

www.iotxfd  //多出的字符串被截断
OK SEND OK +QIURC: "recv",0 >>>>>>>>>> AT+QICLOSE=0 OK CLOSE OK

可以看到,由于指定了最大长度,多出来的字符串未被发送。

数据的接收

先来一个最简单的接收示例:

>>>>>>>>>>  AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0 //创建 Socket 服务

OK

+QIOPEN: 0,0 //连接成功,使用的是 0 号 socket

>>>>>>>>>>  AT+QISEND=0,10,1234567890 //发送字符串“01234567890”

OK

SEND OK

+QIURC: "recv",0 //URC:0 号 socket 收到信息

>>>>>>>>>>  AT+QIRD=0,512 //接收 0 号 socket 的接收缓冲区,长度 512

+QIRD: 10 //收到 10 个字节
1234567890 //数据为:1234567890 OK >>>>>>>>>> AT+QIRD=0,512 //再次接收 +QIRD: 0 //指示接收缓冲已空 OK >>>>>>>>>> AT+QICLOSE=0 //关闭 socket 服务 OK CLOSE OK

这种接收方式应当是最常用的,每次按最大接收数 512 进行接收,最终只按实际数据长度进行接收,使用起来非常方便。你也可以指定接收的长度,如:

>>>>>>>>>>  AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0

OK

+QIOPEN: 0,0

>>>>>>>>>>  AT+QISEND=0,10,1234567890

OK

SEND OK

+QIURC: "recv",0 //URC:0 号 socket 收到信息

>>>>>>>>>>  AT+QIRD=0,6 //指定接收长度为 6 个字节

+QIRD: 6 //接收了 6 个字节
123456 OK >>>>>>>>>> AT+QIRD=0,6 //再次接收 +QIRD: 4 //接收了剩余的 4 个字节
7890 OK >>>>>>>>>> AT+QICLOSE=0 OK CLOSE OK

可以使用AT+QICFG="showlength",1指令更改收到信息 URC 的显示方式,让其指示收到了多少个字节。过程如下图所示:

可以使用AT+QICFG="viewmode",1更改接收信息的显示方式:

>>>>>>>>>>  AT+QICFG="viewmode",0 //将接收信息显示方式改为 0

OK

>>>>>>>>>>  AT+QIOPEN=1,0,"TCP","193.112.19.116",5000,0,0

OK

+QIOPEN: 0,0

>>>>>>>>>>  AT+QISEND=0,10,1234567890

OK

SEND OK

+QIURC: "recv",0,10

>>>>>>>>>>  AT+QIRD=0,4 //先接收 4 个字节

+QIRD: 4,6 //接收 4 个字节,剩余 6 个字节
1234 //换行显示 OK >>>>>>>>>> AT+QICFG="viewmode",1 //将接收信息显示方式改为 1 OK >>>>>>>>>> AT+QIRD=0,4 //再次接收 4 个字节 +QIRD: 4,2,5678 //接收 4 个字节,剩余 2 个字节,数据直接在逗号后面显示 OK >>>>>>>>>> AT+QIRD=0,4 //再次接收 4 个字节 +QIRD: 2,0,90 //只收到了 2 个字节 OK >>>>>>>>>> AT+QIRD=0,4 +QIRD: 0 OK >>>>>>>>>> AT+QICLOSE=0 OK CLOSE OK

从上例可观察到,在显示接收数据时,viewmode=0,会换行显示数据。viewmode=1 则直接在逗号后面显示数据。

直接推送模式

使用直接推送模式会在 URC 中直接显示接收到的数据,如下图所示:

很明显,如果收到的数据量较小,使用直接推送模式会方便很多。

Ping 一个远端地址

我这里有两块开发板,一块直接无法 Ping,另一块可以 Ping,但速度很慢。

>>>>>>>>>>  AT+QPING=1,193.112.19.116

OK

+QPING: 569

+QPING: 0,"193.112.19.116",32,990,52

+QPING: 0,"193.112.19.116",32,2060,52

+QPING: 0,"193.112.19.116",32,1040,52

+QPING: 0,4,3,1,990,2060,1363

>>>>>>>>>>  AT+QPING=1,"www.baidu.com"

OK

+QPING: 0,"39.156.66.18",32,1560,52

+QPING: 569

+QPING: 0,"39.156.66.18",32,560,52

+QPING: 569

+QPING: 0,4,2,2,560,1560,1060

上述代码中的 569 为错误码,表示超时。

时间同步

时间同步也一样,一块开发板无法用,另一块可以:

>>>>>>>>>>  AT+QNTP=1,"ntp5.aliyun.com"

OK

+QNTP: 0,"20/01/01,12:50:38+32"

新年第一天,泡制完 2020 年的第一篇文章。这个系列得停一段时间,想着还是得先把 RFID 写完了再回来继续。

AT指令之 TCP/IP 命令的更多相关文章

  1. TCP/IP协议基础(转)

    转自 http://www.chinaunix.net 作者:Bernardus160  发表于:2003-12-03 17:33:15 TCP/IP协议基础 -------------------- ...

  2. TCP/IP远程访问操作:rwho,rlogin,rcp和rsh

    TCP/IP网络通信 软件 包使用远程访问 的 命令 ,这些命令首先是由UC Berkely为Arpanet开发的.它允许您远程注册到另一个 系统 中,并从一个系统复制文件到另一个系统.您能取得关于一 ...

  3. TCP/IP 详解7 Ping指令

    首先介绍一下ping 指令的基本过程:(这部分摘自网络) 我们以下面一个网络为例:有A.B.C.D四台机子,一台路由RA,子网掩码均为255.255.255.0,默认路由为192.168.0.1 1. ...

  4. tomcat正常启动,但IP不能访问web。ping IP地址,一直超时。 用ipconfig命令修复TCP/IP的配置信息

    今天遇到一个好奇葩的问题  好吧是昨天遇到的一直没找到解决办法(`へ´) tomcat正常启动,但是通过IP不能访问web 用IP地址就是不行  (:′⌒`)  打不开 localhost就可以    ...

  5. TCP/IP协议学习之实例ping命令学习笔记

    TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...

  6. 『TCP/IP详解——卷一:协议』读书笔记——10

    2013-08-22 22:57:17 3.8 ifconfig命令 这个命令在Linux系统下可以通过下面的指令阅读说明文档: ifconfig 由于书中作者用的系统比较早的某Unix系统,所以我的 ...

  7. TCP/IP,Http,Socket,XMPP的区别

    大学学习网络基础的时候老师讲过,网络由下往上分为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用 ...

  8. TCP/IP详解之:TCP

    第17章 TCP:传输控制协议 TCP提供了一种可靠的面向连接的字节流运输层服务 TCP的服务 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务. TCP通过下 ...

  9. SQLserver2012 tcp/ip 1433port问题解决方法

    非常多MSSQL安装完毕后,调用1433(默认port)是失败的,这边具体介绍下解决方法. 一..我们须要在电脑上开启telnet服务,定位问题须要.在cmd下使用telnet,假设报命令不存在说明没 ...

随机推荐

  1. Bugku-CTF分析篇-这么多数据包(这么多数据包找找吧,先找到getshell的流)

    这么多数据包 这么多数据包找找吧,先找到getshell的流

  2. 多对多三种创建方式、forms组件、cookies与session

    多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...

  3. js语言简介

    JS语言概述 JS语言简史 JS语言的起源 网景(Netscape Communication Corperation),1994年,推出第一款商用浏览器,网景浏览器(Netscape Navigat ...

  4. 启动MySQL5.7时报错:initialize specified but the data directory has files in it. Aborting.

    启动MySQL5.7时报错:initialize specified but the data directory has files in it. Aborting 解决方法: vim /etc/m ...

  5. 「JSOI2015」套娃

    「JSOI2015」套娃 传送门 考虑贪心. 首先我们假设所有的套娃都互相不套. 然后我们考虑合并两个套娃 \(i\),\(j\) 假设我们把 \(i\) 套到 \(j\) 里面去,那么就可以减少 \ ...

  6. sqli-libs(11-22关)

    Less_11 点开11关出现登录页面: 1.可以随便输密码和账号,submit之后出现错误,可以看到查询username和password用and连接放在同一个SQL语句中 打开使用burp sui ...

  7. 7、源与值(Source/Values)

    学习目录:树莓派学习之路-GPIO Zero 官网地址:https://gpiozero.readthedocs.io/en/stable/source_values.html 环境:UbuntuMe ...

  8. 让 typora和word一样好用

    让 typora和word一样好用  :https://github.com/itcastWsy/typora_copy_images typora是一款支持实时预览的markdown编辑器,作者在使 ...

  9. Color the ball(差分数组)

    N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但 ...

  10. 【MySQL】常用增删改查

    目录 1. 文件夹(库) 2. 文件(表) 3. 文件内容(数据) "@ ___ 1. 文件夹(库) # 增 create database db charset utf8; # 查 sho ...