【从零开始的嵌入式生活】网络编程7——编程扩展

简介: 【从零开始的嵌入式生活】网络编程7——编程扩展

今天是网络编程的最后一篇文章了,这篇文章会补充一下常用的知识点,我尽量快点写0.0。希望有人愿意跟我一起学习呀。


🧑🏻作者简介:一个学嵌入式的年轻人

✨联系方式:2201891280(QQ)

📔源码地址:https://gitee.com/xingleigao/study_qianrushi

⏳全文大约阅读时间: 60min


文章目录

网络信息检索

域名解析

网络属性设置

网络超时处理

广播和组播

广播

广播地址

广播发送

广播接收

广播发送伪码

组播

组播地址

组播发送

组播接收

加入组播组的方式

UNIX域套接字

写在最后

网络信息检索

域名解析

gethostbyname() 根据主机名取得主机信息 只适用于IPV4


#include <netdb.h>
      extern int h_errno;
      struct hostent *gethostbyname(const char *name);
      #include <sys/socket.h>       /* for AF_INET */
      struct hostent *gethostbyaddr(const void *addr,
                                    socklen_t len, int type);
      void sethostent(int stayopen);
      void endhostent(void);  //释放空间
      void herror(const char *s);
      const char *hstrerror(int err);


可以看到返回值是一个结构体,并且如果是空指针的是出错,我们可以一起看一下这个结构体。


The hostent structure is defined in <netdb.h> as follows:
          struct hostent {
              char  *h_name;            /* official name of host */
              char **h_aliases;         /* alias list */
              int    h_addrtype;        /* host address type */
              int    h_length;          /* length of address */
              char **h_addr_list;       /* list of addresses */
          }
          #define h_addr h_addr_list[0] /* for backward compatibility */


可以看到:h_addr_list是一个列表,多个网络地址(网络字节序的32位整数)列表

一个简单的demo


 

if ((hs = gethostbyname (argv[1])) == NULL) {//获取地址
                  herror ("gethostbyname error");
                  exit (1);
          }
          if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
                  perror ("socket");
                  exit (1);
          }
          bzero (&sin, sizeof (sin));
          sin.sin_family = AF_INET;
          sin.sin_port = htons (port);
          sin.sin_addr.s_addr = *(uint32_t *) hs->h_addr;//拿到地址
          endhostent ();//释放空间
          hs = NULL;//释放空间

网络属性设置

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
getsockopt和setsockopt 
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)


level指定控制套接字的层次.可以取三种值:


1、SOL_SOCKET:通用套接字选项. (应用层)

2、IPPROTO_IP:IP选项. (传输层)

3、IPPROTO_TCP:TCP选项. (网络层)

optval选项:

5805746123cbebd5e6723b0e7d2d465.png312154f2ffb55320eb73435bcee74fa.png


这部分其实就是内容很多,但是用起来还是很快的:之前的

允许IP快速重用我们就是:


int b_reuse = 1;
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));


超时时间设置:


struct timeval  tv;
     tv.tv_sec = 5;   //  设置5秒时间
     tv.tv_usec = 0;
     setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,  &tv,  
                       sizeof(tv));   //  设置接收超时
      recv() / recvfrom()    //   从socket读取数据

网络超时处理

方法一:设置socket的属性

设置socket的属性 SO_RCVTIMEO就是上面说到的方式

方法二:用select检测socket是否’ready’


struct fd_set rdfs;
   struct timeval  tv = {5 , 0};   // 设置5秒时间
   FD_ZERO(&rdfs);
   FD_SET(sockfd, &rdfs);
   if (select(sockfd+1, &rdfs, NULL, NULL, &tv) > 0)   // socket就绪
   {
         recv() /  recvfrom()    //  从socket读取数据
   }

方法三:设置定时器(timer)


void  handler(int signo)     {   return;  }
     struct sigaction  act;
     sigaction(SIGALRM, NULL, &act);
     act.sa_handler = handler;
     act.sa_flags &= ~SA_RESTART;
     sigaction(SIGALRM, &act, NULL);
     alarm(5);
     if (recv(,,,) < 0) ……


当然网络编程还有心跳检测等多种方式。


广播和组播

广播和组播都是一种一对多的方式,所以一定使用的UDP


广播

如果同时发给局域网中的所有主机,称为广播

只有用户数据报(使用UDP协议)套接字才能广播


广播地址

以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址192.168.1.255代表该网段的广播地址

发到该地址的数据包被所有的主机接收

255.255.255.255在所有网段中都代表广播地址全网广播,一般都会被禁用

广播发送

1.创建用户数据报套接字

2.缺省创建的套接字不允许广播数据包,需要设置属性

setsockopt可以设置套接字属性

3.接收方地址指定为广播地址

4.指定端口信息

5.发送数据包

广播接收

1.创建用户数据报套接字

2.绑定本机IP地址和端口

绑定的端口必须和发送方指定的端口相同

3.等待接收数据

可以发现这部分基本上与普通的接收方式相同。


广播发送伪码

sockfd = socket(,,);
……
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
……
sendto(;;;;;);


组播

单播方式只能发给一个接收方

广播方式发给所有的主机。过多的广播会大量占用网络带宽,造成广播风暴,影响正常的通信。

组播(又称为多播)是一种折中的方式。只有加入某个多播组的主机才能收到数据。

组播地址

D类地址(组播地址)

不分网络地址和主机地址,第1字节的前4位固定为1110

224.0.0.1 – 239.255.255.255

组播发送

相当于之前的client

1.创建用户数据报套接字

2.接收方地址指定为组播地址

2.指定端口信息

4.发送数据包

组播接收

相当于之前的server

1.创建用户数据报套接字

2.加入多播组

3.绑定本机IP地址和端口

4.绑定的端口必须和发送方指定的端口相同

5.等待接收数据

加入组播组的方式

struct ip_mreq
{
    struct  in_addr  imr_multiaddr;
    struct  in_addr  imr_interface;
};
struct  ip_mreq  mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(“235.10.10.3”);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,  
                 sizeof(mreq));


UNIX域套接字

socket同样可以用于本地通信

创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)。


socket(AF_LOCAL, SOCK_STREAM, 0)
socket(AF_LOCAL, SOCK_DGRAM, 0)


分为流式套接字和用户数据报套接字


1.进程间消息通信:管道、消息队列、共享内存、unix域套接字

易用性:消息队列>unix域套接字>管道>共享内存

效率:共享内存>unix域套接字>管道>消息队列

2.异步通信: 信号

3.信号量和互斥:信号量


struct sockaddr_un        //  <sys/un.h>
{
sa_family_t  sun_family;
char  sun_path[108];         // 套接字文件的路径
};


注意点:1.文件必须不存在 2.一般是绝对路径 3.文件在内存中

TCP域套接字服务端:


socket(AF_UNIX, SOCK_STREAM, 0)
bind(,本地地址, )
listen(,)
accept(,,)
recv() / send()


客户端:

socket(PF_UNIX, SOCK_STREAM, 0)
bind(,本地地址, )   //   可选
connect(,,)
recv() / send()


UDP域套接字服务端:


socket(PF_UNIX, SOCK_DGRAM, 0)
bind(,本地地址, )
recvfrom() 
sendto()


客户端:


socket(PF_UNIX, SOCK_DGRAM, 0)
bind(,本地地址, )     //  可选
sendto() 
recvfrom()    //  若没有绑定地址,无法接收数据

写在最后


相关文章
|
5月前
|
网络协议 区块链 KVM
Arista vEOS 4.30.10M - 虚拟化的数据中心和云网络可扩展操作系统
Arista vEOS 4.30.10M - 虚拟化的数据中心和云网络可扩展操作系统
130 2
Arista vEOS 4.30.10M - 虚拟化的数据中心和云网络可扩展操作系统
|
5月前
|
监控 区块链 数据中心
Arista EOS 4.34.0F - 适用于下一代数据中心和云网络的可扩展操作系统
Arista EOS 4.34.0F - 适用于下一代数据中心和云网络的可扩展操作系统
144 0
Arista EOS 4.34.0F - 适用于下一代数据中心和云网络的可扩展操作系统
|
7月前
|
机器学习/深度学习 API Python
Python 高级编程与实战:深入理解网络编程与异步IO
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧、数据科学、机器学习、Web 开发和 API 设计。本文将深入探讨 Python 在网络编程和异步IO中的应用,并通过实战项目帮助你掌握这些技术。
|
10月前
|
机器学习/深度学习 算法 PyTorch
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
本文探讨了图神经网络(GNN)与大型语言模型(LLM)结合在知识图谱问答中的应用。研究首先基于G-Retriever构建了探索性模型,然后深入分析了GNN-RAG架构,通过敏感性研究和架构改进,显著提升了模型的推理能力和答案质量。实验结果表明,改进后的模型在多个评估指标上取得了显著提升,特别是在精确率和召回率方面。最后,文章提出了反思机制和教师网络的概念,进一步增强了模型的推理能力。
492 4
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
|
11月前
|
监控 安全
公司上网监控:Mercury 在网络监控高级逻辑编程中的应用
在数字化办公环境中,公司对员工上网行为的监控至关重要。Mercury 作为一种强大的编程工具,展示了在公司上网监控领域的独特优势。本文介绍了使用 Mercury 实现网络连接监听、数据解析和日志记录的功能,帮助公司确保信息安全和工作效率。
214 51
|
9月前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
469 15
|
10月前
|
JSON 算法 Java
Nettyの网络聊天室&扩展序列化算法
通过本文的介绍,我们详细讲解了如何使用Netty构建一个简单的网络聊天室,并扩展序列化算法以提高数据传输效率。Netty的高性能和灵活性使其成为实现各种网络应用的理想选择。希望本文能帮助您更好地理解和使用Netty进行网络编程。
126 12
|
11月前
|
缓存 负载均衡 网络协议
|
12月前
|
Java 应用服务中间件
面对海量网络请求,Tomcat线程池如何进行扩展?
【10月更文挑战第4天】本文详细探讨了Tomcat线程池相较于标准Java实用工具包(JUC)线程池的关键改进。首先,Tomcat线程池在启动时即预先创建全部核心线程,以应对启动初期的高并发请求。其次,通过重写阻塞队列的入队逻辑,Tomcat能够在任务数超过当前线程数但未达最大线程数时,及时创建非核心线程,而非等到队列满才行动。此外,Tomcat还引入了在拒绝策略触发后重新尝试入队的机制,以提高吞吐量。这些优化使得Tomcat线程池更适应IO密集型任务,有效提升了性能。
面对海量网络请求,Tomcat线程池如何进行扩展?
|
11月前
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
169 1