赞
踩
目录
如下图所示,lora_pkt_fwd.c是一个运行在 Lora Gateway Host上的程序,将Concentrator(集中器)接收到的无线数据包通过 IP/UDP 转发到服务器链接,并发射由服务器发送的无线数据包。 它还可以发出用于协调所有节点的全网 GPS 同步信标信号网络。
-
- ((( Y )))
- |
- |
- +- -|- - - - - - - - - - - - -+ xxxxxxxxxxxx +--------+
- |+--+-----------+ +------+| xx x x xxx | |
- || | | || xx Internet xx | |
- || Concentrator |<----+ Host |<------xx or xx-------->| |
- || | SPI | || xx Intranet xx | Server |
- |+--------------+ +------+| xxxx x xxxx | |
- | ^ ^ | xxxxxxxx | |
- | | PPS +-----+ NMEA | | | |
- | +------| GPS |-------+ | +--------+
- | +-----+ |
- | |
- | Gateway |
- +- - - - - - - - - - - - - - -+
Concentrator:radio RX/TX board, based on Semtech multichannel modems
(SX130x), transceivers (SX135x) and/or low-power stand-alone modems (SX127x).
(无线电 RX/TX 板,基于 Semtech 多通道调制解调器(SX130x)、收发器 (SX135x) 和/或低功耗独立调制解调器 (SX127x))
Host:embedded computer on which the packet forwarder is run. Drives the
concentrator through a SPI link.
(运行数据包转发器的嵌入式计算机。 驱动集中器通过 SPI 链接)
GPS: GNSS (GPS, Galileo, GLONASS, etc) receiver with a "1 Pulse Per Second"
output and a serial link to the host to send NMEA frames containing time and
geographical coordinates data. Optional.
(具有“每秒 1 个脉冲”的 GNSS(GPS、Galileo GLONASS 等)接收器输出和到主机的串行链路以发送包含时间和地理坐标数据。 可选的)
Gateway: a device composed of at least one radio concentrator, a host, some
network connection to the internet or a private network (Ethernet, 3G, Wifi,
microwave link), and optionally a GPS receiver for synchronization.
(由至少一个无线电集中器、一个主机、一些到互联网或专用网络的网络连接(以太网、3G、Wifi、微波链接),以及可选的 GPS 接收器用于同步。)
Server: an abstract computer that will process the RF packets received and
forwarded by the gateway, and issue RF packets in response that the gateway
will have to emit.
(一个抽象的计算机,它将处理接收到的 RF 数据包和由网关转发,并发出 RF 数据包以响应网关
将不得不发射。)
以下来自CSDN博主「折腾java」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:什么是网络编程(一)_折腾java的博客-CSDN博客_网络编程
在计算领域中,网络是传输信息、接受、共享的虚拟的平台。通过它可以把各个点、面、体的信息联系到一起,从而实现这些资源的共享。网络是人类发展史上最重要的发明,提高了人类和科技的一个发展。
网络编程从大的方面就是说对信息的发送接收。
通过操作相应API调度计算机资源硬件,并且利用管道(网线)进行数据交互的过程。
更为具体的涉及:网络模型、套接字、数据包。
基础层:物理层(physical)、数据链路层(Datalink)、网络层(network).。
传输层(Transport):TCP-UDP协议层、Socket。
高级层::会话层(Session)、表示层(Presentation)、应用层(Application)
Socket:简单来说是ip地址与端口的结合协议(RFC 793).
一种地址与端口的结合描述协议。
TCP/IP协议的相关API的总称;是网络API的集合实现.
涵盖了Stream socket /Datagram Socket
socket 的组成与作用:
在网络传输中用于唯一标识两个端点的链接。
端点:包括(ip+port)
4个要素:客户端的地址、客户端的端口、服务器的地址、服务器端口。
Socket之TCP:
tcp是面向连接的通讯协议。
通过三次握手建立连接,通讯完成时要拆除连接。
由于TCP是面向连接的,所以只能用于端到端的通信。
Socket之UDP:
UDP是面向无连接进行通讯的。
UDP数据包括目的端口号和源端口号信息。
由于通讯时是不需要连接,所以可以是实现广播发送,并不局限于端到端。
struct sockaddr
{
unsigned short sa_family;
char sa_data[14];
};
1、sa_family 为调用socket()时的domain 参数, 即AF_xxxx 值。AF为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
2、sa_data 为14字节的协议地址,包含该socket的IP地址和端口号。
注:此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息,sockaddr 结构会因使用不同的socket domain 而有不同结构定义。
1)creates an endpoint for communication and returns a descriptor
int socket (int domain, int type, int protocol);
domain 参数指定一个通信域; 这个选择将用于通信的协议族。这些系列在 <sys/socket.h> 中定义。 目前可理解的格式包括:
- Name Purpose Man page
- AF_UNIX, AF_LOCAL Local communication unix(7)
- AF_INET IPv4 Internet protocols ip(7)
- AF_INET6 IPv6 Internet protocols ipv6(7)
- AF_IPX IPX - Novell protocols
- AF_NETLINK Kernel user interface device netlink(7)
- AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
- AF_AX25 Amateur radio AX.25 protocol
- AF_ATMPVC Access to raw ATM PVCs
- AF_APPLETALK AppleTalk ddp(7)
- AF_PACKET Low level packet interface packet(7)
- AF_ALG Interface to kernel crypto API
type参数为套接字指定类型,它指定了通信语义。 当前定义的类型有:
- SOCK_STREAM 提供基于顺序的、可靠的、双向的、连接的字节流。
- SOCK_DGRAM 支持数据报(无连接、不可靠固定最大长度的消息)。
- SOCK_SEQPACKET 基于数据报提供有序、可靠的、双向连接的数据传输路径固定最大长度。
- SOCK_RAW 提供原始网络协议访问。
- SOCK_RDM 提供不保证排序的可靠数据报层。
protocol 指定要与套接字一起使用的特定协议。 通常,在给定的protocol 族中,只有一个协议支持特定的套接字类型,在这种情况下,protocol 可以指定为 0。但是,可能存在许多协议,在这种情况下,必须指定一个特定的protocol 。
2) bind a name to a socket (为套接字分配名称)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind() 将 addr 指定的地址分配给文件描述符 sockfd 引用的套接字。addrlen 指定 addr 指向的地址结构的大小(以字节为单位)此操作称为“为套接字分配名称”。
3)initiate a connection on a socket (在套接字上启动连接)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
connect() 调用后系统将文件描述符 sockfd 引用的套接字连接到 addr 指定的地址。addrlen 参数指定 addr 的大小。addr中地址的格式由socket sockfd的地址空间决定。
4)listen for connections on a socket (侦听套接字上的连接)
int listen(int sockfd, int backlog);
listen() 将 sockfd 引用的套接字标记为被动套接字,用于接受即将传入的套接字,使用accept() 的连接请求。
sockfd 参数是引用套接字的文件描述符:SOCK_STREAM 或 SOCK_SEQPACKET 类型。
backlog 参数定义了 sockfd 的挂起连接队列可以增长到的最大长度。 如果连接请求在队列已满时到达,客户端可能会收到一个带有 ECONNREFUSED 指示的错误,或者,如果底层协议支持重传,则该请求可能会被忽略,以便稍后重新尝试连接成功。
5)accept a connection on a socket (接受套接字上的连接)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept() 与基于连接的套接字类型(SOCK_STREAM、SOCK_SEQPACKET)一起使用。它从侦听套接字 sockfd 的挂起连接队列中提取第一个连接请求,创建一个新的连接套接字,并返回一个引用该套接字的新文件描述符。新创建的套接字未处于侦听状态。原始套接字 sockfd 不受此调用的影响。
参数 sockfd 是一个使用 socket() 创建的套接字,使用 bind() 绑定到本地地址,并在 listen() 之后监听连接。
参数 addr 是指向 sockaddr 结构的指针。这个结构用通信层已知的对等套接字的地址填充。返回 addr 的地址的确切格式,由套接字的地址系列决定。当addr为NULL时,什么都不填;在这种情况下,addrlen 未使用,也应为 NULL。
addrlen 参数是一个 value-result 参数:调用者必须初始化它以包含 addr 指向的结构的大小(以字节为单位);返回时,它将包含对等地址的实际大小。
6)get and set options on sockets (获取和设置套接字上的选项)
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
参数sockfd:是一个使用 socket() 创建的套接字返回的文件描述符
参数level:协议层次
SOL_SOCKET 套接字层次
IPPROTO_IP ip层次
IPPROTO_TCP TCP层次
参数optname:选项的名称(套接字层次)
SO_BROADCAST 是否允许发送广播信息
SO_REUSEADDR 是否允许重复使用本地地址
SO_SNDBUF 获取发送缓冲区长度
SO_RCVBUF 获取接收缓冲区长度 SO_RCVTIMEO 获取接收超时时间
SO_SNDTIMEO 获取发送超时时间 参数optval:指针,指向获取到的选项的缓冲区
参数optlen:指针,指向optval缓冲区的长度
返回值:成功:0 失败:-1
在文件lora_pkt_fwd.c中,man()里面创建了6个线程来实现如下功能:
1、加载配置文件:全局配置还是局部配置还是调试配置
- if (access(debug_cfg_path, R_OK) == 0) { /* if there is a debug conf, parse only the debug conf如果有调试配置,只解析调试配置 */
- MSG("INFO: found debug configuration file %s, parsing it\n", debug_cfg_path);
- MSG("INFO: other configuration files will be ignored\n");
- x = parse_SX1301_configuration(debug_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- x = parse_gateway_configuration(debug_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- } else if (access(global_cfg_path, R_OK) == 0) { /* if there is a global conf, parse it and then try to parse local conf */
- MSG("INFO: found global configuration file %s, parsing it\n", global_cfg_path);
- x = parse_SX1301_configuration(global_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- x = parse_gateway_configuration(global_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- if (access(local_cfg_path, R_OK) == 0) {
- MSG("INFO: found local configuration file %s, parsing it\n", local_cfg_path);
- MSG("INFO: redefined parameters will overwrite global parameters\n");
- parse_SX1301_configuration(local_cfg_path);
- parse_gateway_configuration(local_cfg_path);
- }
- } else if (access(local_cfg_path, R_OK) == 0) { /* if there is only a local conf, parse it and that's all */
- MSG("INFO: found local configuration file %s, parsing it\n", local_cfg_path);
- x = parse_SX1301_configuration(local_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- x = parse_gateway_configuration(local_cfg_path);
- if (x != 0) {
- exit(EXIT_FAILURE);
- }
- } else {
- MSG("ERROR: [main] failed to find any configuration file named %s, %s OR %s\n", global_cfg_path, local_cfg_path, debug_cfg_path);
- exit(EXIT_FAILURE);
- }
2、启动GPS
- if (gps_tty_path[0] != '\0') { /* do not try to open GPS device if no path set */
- i = lgw_gps_enable(gps_tty_path, "ubx7", 0, &gps_tty_fd); /* HAL only supports u-blox 7 for now */
- if (i != LGW_GPS_SUCCESS) {
- printf("WARNING: [main] impossible to open %s for GPS sync (check permissions)\n", gps_tty_path);
- gps_enabled = false;
- gps_ref_valid = false;
- } else {
- printf("INFO: [main] TTY port %s open for GPS synchronization\n", gps_tty_path);
- gps_enabled = true;
- gps_ref_valid = false;
- }
- }
3、地址转换,将主机物理地址转换成网络字节顺序地址
- net_mac_h = htonl((uint32_t)(0xFFFFFFFF & (lgwm>>32)));
- net_mac_l = htonl((uint32_t)(0xFFFFFFFF & lgwm ));
4、创建网络套接字socket进行通信
- i = getaddrinfo(serv_addr, serv_port_up, &hints, &result);
- ...
- for (q=result; q!=NULL; q=q->ai_next) {
- sock_up = socket(q->ai_family, q->ai_socktype,q->ai_protocol);
- if (sock_up == -1) continue; /* try next field */
- else break; /* success, get out of loop */
- }
- if (q == NULL) {
- MSG("ERROR: [up] failed to open socket to any of server %s addresses (port %s)\n", serv_addr, serv_port_up);
- i = 1;
- for (q=result; q!=NULL; q=q->ai_next) {
- getnameinfo(q->ai_addr, q->ai_addrlen, host_name, sizeof host_name, port_name, sizeof port_name, NI_NUMERICHOST);
- MSG("INFO: [up] result %i host:%s service:%s\n", i, host_name, port_name);
- ++i;
- }
- exit(EXIT_FAILURE);
- }
- i = connect(sock_up, q->ai_addr, q->ai_addrlen);
- if (i != 0) {
- MSG("ERROR: [up] connect returned %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- freeaddrinfo(result);
5、启动集中器
i = lgw_start();
6、创建4个线程来管理上下行:thrid_up、thrid_down、thrid_jit、thrid_timersync
- i = pthread_create( &thrid_up, NULL, (void * (*)(void *))thread_up, NULL);
- i = pthread_create( &thrid_down, NULL, (void * (*)(void *))thread_down, NULL);
- i = pthread_create( &thrid_jit, NULL, (void * (*)(void *))thread_jit, NULL);
- i = pthread_create( &thrid_timersync, NULL, (void * (*)(void *))thread_timersync, NULL);
7、创建2个线程来管理GPS:thrid_gps、thrid_valid
- i = pthread_create( &thrid_gps, NULL, (void * (*)(void *))thread_gps, NULL);
- i = pthread_create( &thrid_valid, NULL, (void * (*)(void *))thread_valid, NULL);
8、信号量。
- sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */
- sigaction(SIGINT, &sigact, NULL); /* Ctrl-C */
- sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */
9、while循环。只要不是退出进程的信号,一直死循环的以默认的时间间隔收集和显示统计信息并发送给server
- while (!exit_sig && !quit_sig) {
- wait_ms(1000 * stat_interval);/* wait for next reporting interval */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。