【从零开始的嵌入式生活】网络编程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()    //  若没有绑定地址,无法接收数据

写在最后


相关文章
|
10天前
|
监控 安全
公司上网监控:Mercury 在网络监控高级逻辑编程中的应用
在数字化办公环境中,公司对员工上网行为的监控至关重要。Mercury 作为一种强大的编程工具,展示了在公司上网监控领域的独特优势。本文介绍了使用 Mercury 实现网络连接监听、数据解析和日志记录的功能,帮助公司确保信息安全和工作效率。
82 51
|
17天前
|
缓存 负载均衡 网络协议
|
1月前
|
Java 应用服务中间件
面对海量网络请求,Tomcat线程池如何进行扩展?
【10月更文挑战第4天】本文详细探讨了Tomcat线程池相较于标准Java实用工具包(JUC)线程池的关键改进。首先,Tomcat线程池在启动时即预先创建全部核心线程,以应对启动初期的高并发请求。其次,通过重写阻塞队列的入队逻辑,Tomcat能够在任务数超过当前线程数但未达最大线程数时,及时创建非核心线程,而非等到队列满才行动。此外,Tomcat还引入了在拒绝策略触发后重新尝试入队的机制,以提高吞吐量。这些优化使得Tomcat线程池更适应IO密集型任务,有效提升了性能。
面对海量网络请求,Tomcat线程池如何进行扩展?
|
1月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
|
3月前
|
安全 Java 应用服务中间件
网络安全的护城河:漏洞防御与加密技术深入浅出Java并发编程
【8月更文挑战第31天】在数字世界的棋盘上,每一次点击都可能是一步棋。网络安全的战场无声却激烈,漏洞如同裂缝中的风,悄无声息地侵袭着数据的堡垒。本文将揭示网络漏洞的隐蔽角落,探讨如何通过加密技术筑起防线,同时提升个人和组织的安全意识,共同守护我们的数字家园。
|
3月前
|
缓存 网络协议 Linux
扩展Linux网络栈
扩展Linux网络栈
75 3
|
4月前
|
监控 Python
单位网络监控软件中的PostScript图形编程
PostScript是一种强大的页面描述语言,广泛应用于图形编程和打印控制。在单位网络监控软件中,利用PostScript可以实现复杂的图形绘制和文本处理。本文将通过几个具体的代码示例,介绍如何在PostScript中进行图形编程,并讨论如何将监控到的数据自动提交到网站。
70 10
|
4月前
|
域名解析 安全 物联网
阿里云EMAS HTTPDNS 扩展全球服务节点:提升解析安全性与网络覆盖
阿里云EMAS HTTPDNS新增国内西南、华南及国际欧洲、美东服务节点,提升了全球覆盖能力与性能。作为高效域名解析服务,EMAS HTTPDNS针对互联网、汽车、物流、IOT等行业提供支持,解决了传统解析易遭劫持等问题。新增节点优化了就近调度功能,显著缩短响应时间并增强了服务稳定性和连续性,尤其为中国企业的海外业务提供了强有力的支持。此次扩展展现了阿里云对服务质量的持续追求和全球市场布局的战略思考。
|
4月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
55 4
|
4月前
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
64 2