小高技术网-免费分享创业技术、为农村创业者服务!
当前位置: 小高技术网 > 技术常识4>正文

网络维护学什么语言好学(网络维护学什么语言好)

2023-03-08 05:24:02 技术常识4 内部分享

【温馨提示】本文共有9467个字,预计阅读完需要24分钟,请仔细阅读哦!


各开发语言DNS缓存配置建议,下面一起来看看本站小编京东云给大家精心整理的答案,希望对您有帮助

网络维护学什么语言好1

作者:翟贺龙

一、背景

在计算机领域,涉及性能优化动作时首先应被考虑的原则之一便是使用缓存,合理的数据缓存机制能够带来以下收益:

1.缩短数据获取路径,热点数据就近缓存以便后续快速读取,从而明显提升处理效率;

2.降低数据远程获取频次,缓解后端数据服务压力、减少前端和后端之间的网络带宽成本;

从 CPU 硬件的多级缓存设计,到浏览器快速展示页面,再到大行其道的 CDN、云存储网关等商业产品,处处应用了缓存理念。

在公网领域,如操作系统、浏览器和移动端 APP 等成熟产品所具备的缓存机制,极大的消解了网络提供商如电信移动联通、内容提供商如各大门户平台和 CDN 厂商直面的服务压力,运营商的 DNS 才能从容面对每秒亿万级的 DNS 解析,网络设备集群才能轻松承担每秒 Tbit 级的互联网带宽,CDN 平台才能快速处理每秒亿万次的请求。

面对公司目前庞大且仍在不断增长的的域名接入规模,笔者所在团队在不断优化集群架构、提升 DNS 软件性能的同时,也迫切需要推动各类客户端环境进行域名解析请求机制的优化,因此,特组织团队成员调研、编写了这篇指南文章,以期为公司、客户及合作方的前端开发运维人员给出合理建议,优化 DNS 整体请求流程,为业务增效。

本文主要围绕不同业务和开发语言背景下,客户端本地如何实现 DNS 解析记录缓存进行探讨,同时基于笔者所在团队对 DNS 本身及公司网络环境的掌握,给出一些其他措施,最终致力于客户端一侧的 DNS 解析请求规范化。

二、名词解释

1. 客户端

本文所述客户端,泛指所有主动发起网络请求的对象,包括但不限于服务器、PC、移动终端、操作系统、命令行工具、脚本、服务软件、用户 APP 等。

2. DNS

Domain Name System(Server/Service),域名系统(服务器/服务),可理解为一种类数据库服务;

客户端同服务端进行网络通信,是靠 IP 地址识别对方;而作为客户端的使用者,人类很难记住大量 IP 地址,所以发明了易于记忆的域名如 www.jd.com,将域名和 IP 地址的映射关系,存储到 DNS 可供客户端查询;

客户端只有通过向 DNS 发起域名解析请求从而获取到服务端的 IP 地址后,才能向 IP 地址发起网络通信请求,真正获取到域名所承载的服务或内容。

参考:域名系统 域名解析流程

3. LDNS

Local DNS,本地域名服务器;公网接入环境通常由所在网络供应商自动分配(供应商有控制权,甚至可作 DNS 劫持,即篡改解析域名得到的 IP),内网环境由 IT 部门设置自动分配;

通常 Unix、类Unix、MacOS系统可通过 /etc/resolv.conf 查看自己的 LDNS,在 nameserver 后声明,该文件亦支持用户自助编辑修改,从而指定 LDNS,如公网常见的公共 DNS 如谷歌 DNS、114DNS 等;纯内网环境通常不建议未咨询IT部门的情况下擅自修改,可能导致服务不可用;可参考 man resolv.conf 指令结果。

当域名解析出现异常时,同样应考虑 LDNS 服务异常或发生解析劫持情况的可能。

参考:windows系统修改TCP/IP设置(含DNS);

4. hosts

DNS 系统可以动态的提供域名和IP的映射关系,普遍存在于各类操作系统的hosts文件则是域名和IP映射关系的静态记录文件,且通常 hosts 记录优先于 DNS 解析,即本地无缓存或缓存未命中时,则优先通过 hosts 查询对应域名记录,若 hosts 无相关映射,则继续发起 DNS 请求。关于 Linux 环境下此逻辑的控制,请参考下文 C/C++ 语言 DNS 缓存介绍部分。

所以在实际工作中,常利用上述默认特性,将特定域名和特定 IP 映射关系写到 hosts 文件中(俗称“固定 hosts”),用于绕开 DNS 解析过程,对目标 IP 作针对性访问(其效果与 curl 的-x选项,或 wget 的 -e 指定 proxy 选项,异曲同工);

5. TTL

Time-To-Live,生存时间值,此概念在多领域适用且可能有不同意义。

本文涉及到 TTL 描述均针对数据缓存而言,可直白理解为已缓存数据的“有效期”,从数据被缓存开始计,在缓存中存在时长超过 TTL 规定时长的数据被视为过期数据,数据被再次调用时会立刻同权威数据源进行有效性确认或重新获取。

因缓存机制通常是被动触发和更新,故在客户端的缓存有效期内,后端原始权威数据若发生变更,客户端不会感知,表现为业务上一定程度的数据更新延迟、缓存数据与权威数据短时不一致。

对于客户端侧 DNS 记录的缓存 TTL,我们建议值为 60s;同时如果是低敏感度业务比如测试、或域名解析调整不频繁的业务,可适当延长,甚至达到小时或天级别;

三、DNS 解析优化建议

1. 各语言网络库对 DNS 缓存的支持调研

以下调研结果,推荐开发人员参考,以实现自研客户端 DNS 缓存。各开发语言对 DNS 缓存支持可能不一样,在此逐个分析一下。

C/C++ 语言

(1)glibc 的 getaddrinfo 函数

Linux环境下的 glibc 库提供两个域名解析的函数:gethostbyname 函数和 getaddrinfo 函数,gethostbyname 是曾经常用的函数,但是随着向 IPv6 和线程化编程模型的转移,getaddrinfo 显得更有用,因为它既解析 IPv6 地址,又符合线程安全,推荐使用 getaddrinfo 函数。

函数原型:

int getaddrinfo( const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);

getaddrinfo 函数是比较底层的基础库函数,很多开发语言的域名解析函数都依赖这个函数,因此我们在此介绍一下这个函数的处理逻辑。通过 strace 命令跟踪这个函数系统调用。

1)查找 nscd 缓存(nscd 介绍见后文)

我们在 linux 环境下通过 strace 命令可以看到如下的系统调用

//连接nscd socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3 connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory) close(3)

通过 unix socket 接口"/var/run/nscd/socket"连接nscd服务查询DNS缓存。

2)查询 /etc/hosts 文件

如果nscd服务未启动或缓存未命中,继续查询hosts文件,我们应该可以看到如下的系统调用

//读取 hosts 文件 open("/etc/host.conf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0 ... open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 3 fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC) fstat(3, {st_mode=S_IFREG|0644, st_size=178, ...}) = 0

3)查询 DNS 服务

从 /etc/resolv.conf 配置中查询到 DNS 服务器(nameserver)的IP地址,然后做 DNS 查询获取解析结果。我们可以看到如下系统调用

//获取 resolv.conf 中 DNS 服务 IP open("/etc/resolv.conf", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=25, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fef2abee000 read(3, "nameserver 114.114.114.114\n\n", 4096) = 25 ... //连到 DNS 服务,开始 DNS 查询 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("114.114.114.114")}, 16) = 0 poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])

而关于客户端是优先查找 /etc/hosts 文件,还是优先从 /etc/resolv.conf 中获取 DNS 服务器作查询解析,是由 /etc/nsswitch.conf 控制:

#/etc/nsswitch.conf 部分配置 ... #hosts: db files nisplus nis dns hosts: files dns ...

实际通过 strace 命令可以看到,系统调用 nscd socket 之后,读取 /etc/resolv.conf 之前,会读取该文件

newfstatat(AT_FDCWD, "/etc/nsswitch.conf", {st_mode=S_IFREG|0644, st_size=510, ...}, 0) = 0 ... openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3

4)验证

#include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> int gethostaddr(char * name); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "%s $host", argv[0]); return -1; } int i = 0; for(i = 0; i < 5; i++) { int ret = -1; ret = gethostaddr(argv[1]); if (ret < 0) { fprintf(stderr, "%s $host", argv[0]); return -1; } //sleep(5); } return 0; } int gethostaddr(char* name) { struct addrinfo hints; struct addrinfo *result; struct addrinfo *curr; int ret = -1; char ipstr[INET_ADDRSTRLEN]; struct sockaddr_in *ipv4; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; ret = getaddrinfo(name, NULL, &hints, &result); if (ret != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); return ret; } for (curr = result; curr != NULL; curr = curr->ai_next) { ipv4 = (struct sockaddr_in *)curr->ai_addr; inet_ntop(curr->ai_family, &ipv4->sin_addr, ipstr, INET_ADDRSTRLEN); printf("ipaddr:%s\n", ipstr); } freeaddrinfo(result); return 0; }

综上分析,getaddrinfo 函数结合 nscd ,是可以实现 DNS 缓存的。

(2)libcurl 库的域名解析函数

libcurl 库是 c/c++ 语言下,客户端比较常用的网络传输库,curl 命令就是基于这个库实现。这个库也是调用 getaddrinfo 库函数实现 DNS 域名解析,也是支持 nscd DNS 缓存的。

int Curl_getaddrinfo_ex(const char *nodename, const char *servname, const struct addrinfo *hints, Curl_addrinfo **result) { ... error = getaddrinfo(nodename, servname, hints, &aihead); if(error) return error; ... }

Java

Java 语言是很多公司业务系统开发的主要语言,通过编写简单的 HTTP 客户端程序测试验证 Java 的网络库是否支持 DNS 缓存。测试验证了 Java 标准库中 HttpURLConnection 和 Apache httpcomponents-client 这两个组件。

(1)Java 标准库 HttpURLConnection

import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; public class HttpUrlConnectionDemo { public static void main(String[] args) throws Exception { String urlString = "http://example.my.com/"; int num = 0; while (num < 5) { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.flush(); os.close(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } System.out.println("rsp:" + sb.toString()); } else { System.out.println("rsp code:" + conn.getResponseCode()); } num++; } } }

测试结果显示 Java 标准库 HttpURLConnection 是支持 DNS 缓存,5 次请求中只有一次 DNS 请求。

(2)Apache httpcomponents-client

import java.util.ArrayList; import java.util.List; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.NameValuePair; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.message.BasicNameValuePair; public class QuickStart { public static void main(final String[] args) throws Exception { int num = 0; while (num < 5) { try (final CloseableHttpClient httpclient = HttpClients.createDefault()) { final HttpGet httpGet = new HttpGet("http://example.my.com/"); try (final CloseableHttpResponse response1 = httpclient.execute(httpGet)) { System.out.println(response1.getCode() + " " + response1.getReasonPhrase()); final HttpEntity entity1 = response1.getEntity(); EntityUtils.consume(entity1); } } num++; } } }

测试结果显示 Apache httpcomponents-client 支持 DNS 缓存,5 次请求中只有一次 DNS 请求。

从测试中发现 Java 的虚拟机实现一套 DNS 缓存,即实现在 java.net.InetAddress 的一个简单的 DNS 缓存机制,默认为缓存 30 秒,可以通过 networkaddress.cache.ttl 修改默认值,缓存范围为 JVM 虚拟机进程,也就是说同一个 JVM 进程中,30秒内一个域名只会请求DNS服务器一次。同时 Java 也是支持 nscd 的 DNS 缓存,估计底层调用 getaddrinfo 函数,并且 nscd 的缓存级别比 Java 虚拟机的 DNS 缓存高。

# 默认缓存 ttl 在 jre/lib/security/java.security 修改,其中 0 是不缓存,-1 是永久缓存 networkaddress.cache.ttl=10 # 这个参数 sun.net.inetaddr.ttl 是以前默认值,目前已经被 networkaddress.cache.ttl 取代

Go

随着云原生技术的发展,Go 语言逐渐成为云原生的第一语言,很有必要验证一下 Go 的标准库是否支持 DNS 缓存。通过我们测试验证发现 Go 的标准库 net.http 是不支持 DNS 缓存,也是不支持 nscd 缓存,应该是没有调用 glibc 的库函数,也没有实现类似 getaddrinfo 函数的功能。这个跟 Go语言的自举有关系,Go 从 1.5 开始就基本全部由 Go(.go) 和汇编 (.s) 文件写成的,以前版本的 C(.c) 文件被全部重写。不过有一些第三方 Go 版本 DNS 缓存库,可以自己在应用层实现,还可以使用 fasthttp 库的 httpclient。

(1)标准库net.http

package main import ( "flag" "fmt" "io/ioutil" "net/http" "time" ) var httpUrl string func main() { flag.StringVar(&httpUrl, "url", "", "url") flag.Parse() getUrl := fmt.Sprintf("http://%s/", httpUrl) fmt.Printf("url: %s\n", getUrl) for i := 0; i < 5; i++ { _, buf, err := httpGet(getUrl) if err != nil { fmt.Printf("err: %v\n", err) return } fmt.Printf("resp: %s\n", string(buf)) time.Sleep(10 * time.Second) # 等待10s发起另一个请求 } } func httpGet(url string) (int, []byte, error) { client := createHTTPCli() resp, err := client.Get(url) if err != nil { return -1, nil, fmt.Errorf("%s err [%v]", url, err) } defer resp.Body.Close() buf, err := ioutil.ReadAll(resp.Body) if err != nil { return resp.StatusCode, buf, err } return resp.StatusCode, buf, nil } func createHTTPCli() *http.Client { readWriteTimeout := time.Duration(30) * time.Second tr := &http.Transport{ DisableKeepAlives: true, //设置短连接 IdleConnTimeout: readWriteTimeout, } client := &http.Client{ Timeout: readWriteTimeout, Transport: tr, } return client }

从测试结果来看,net.http 每次都去 DNS 查询,不支持 DNS 缓存。

(2)fasthttp 库

fasthttp 库是 Go 版本高性能 HTTP 库,通过极致的性能优化,性能是标准库 net.http 的 10 倍,其中一项优化就是支持 DNS 缓存,我们可以从其源码看到

//主要在fasthttp/tcpdialer.go中 type TCPDialer struct { ... // This may be used to override DNS resolving policy, like this: // var dialer = &fasthttp.TCPDialer{ // Resolver: &net.Resolver{ // PreferGo: true, // StrictErrors: false, // Dial: func (ctx context.Context, network, address string) (net.Conn, error) { // d := net.Dialer{} // return d.DialContext(ctx, "udp", "8.8.8.8:53") // }, // }, // } Resolver Resolver // DNSCacheDuration may be used to override the default DNS cache duration (DefaultDNSCacheDuration) DNSCacheDuration time.Duration ... }

可以参考如下方法使用 fasthttp client 端

func main() { // You may read the timeouts from some config readTimeout, _ := time.ParseDuration("500ms") writeTimeout, _ := time.ParseDuration("500ms") maxIdleConnDuration, _ := time.ParseDuration("1h") client = &fasthttp.Client{ ReadTimeout: readTimeout, WriteTimeout: writeTimeout, MaxIdleConnDuration: maxIdleConnDuration, NoDefaultUserAgentHeader: true, // Don't send: User-Agent: fasthttp DisableHeaderNamesNormalizing: true, // If you set the case on your headers correctly you can enable this DisablePathNormalizing: true, // increase DNS cache time to an hour instead of default minute Dial: (&fasthttp.TCPDialer{ Concurrency: 4096, DNSCacheDuration: time.Hour, }).Dial, } sendGetRequest() sendPostRequest() }

(3)第三方DNS缓存库

这个是 github 中的一个 Go 版本 DNS 缓存库

可以参考如下代码,在HTTP库中支持DNS缓存

r := &dnscache.Resolver{} t := &http.Transport{ DialContext: func(ctx context.Context, network string, addr string) (conn net.Conn, err error) { host, port, err := net.SplitHostPort(addr) if err != nil { return nil, err } ips, err := r.LookupHost(ctx, host) if err != nil { return nil, err } for _, ip := range ips { var dialer net.Dialer conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip, port)) if err == nil { break } } return }, }

Python

(1)requests 库

#!/bin/python import requests url = 'http://example.my.com/' num = 0 while num < 5: headers={"Connection":"close"} # 开启短连接 r = requests.get(url,headers = headers) print(r.text) num +=1

(2)httplib2 库

#!/usr/bin/env python import httplib2 http = httplib2.Http() url = 'http://example.my.com/' num = 0 while num < 5: loginHeaders={ 'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.0 Chrome/30.0.1599.101 Safari/537.36', 'Connection': 'close' # 开启短连接 } response, content = http.request(url, 'GET', headers=loginHeaders) print(response) print(content) num +=1

(3)urllib2 库

#!/bin/python import urllib2 import cookielib httpHandler = urllib2.HTTPHandler(debuglevel=1) httpsHandler = urllib2.HTTPSHandler(debuglevel=1) opener = urllib2.build_opener(httpHandler, httpsHandler) urllib2.install_opener(opener) loginHeaders={ 'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.0 Chrome/30.0.1599.101 Safari/537.36', 'Connection': 'close' # 开启短连接 } num = 0 while num < 5: request=urllib2.Request('http://example.my.com/',headers=loginHeaders) response = urllib2.urlopen(request) page='' page= response.read() print response.info() print page num +=1

Python 测试三种库都是支持 nscd 的 DNS 缓存的(推测底层也是调用 getaddrinfo 函数),以上测试时使用 HTTP 短连接,都在 python2 环境测试。

总结

针对 HTTP 客户端来说,可以优先开启 HTTP 的 keep-alive 模式,可以复用 TCP 连接,这样可以减少 TCP 握手耗时和重复请求域名解析,然后再开启 nscd 缓存,除了 Go 外,C/C++、Java、Python 都可支持 DNS 缓存,减少 DNS查询耗时。

这里只分析了常用 C/C++、Java、Go、Python 语言,欢迎熟悉其他语言的小伙伴补充。

2. Unix/类 Unix 系统常用 dns 缓存服务:

在由于某些特殊原因,自研或非自研客户端本身无法提供 DNS 缓存支持的情况下,建议管理人员在其所在系统环境中部署DNS缓存程序;

现介绍 Unix/类 Unix 系统适用的几款常见轻量级 DNS 缓存程序。而多数桌面操作系统如 Windows、MacOS 和几乎所有 Web 浏览器均自带 DNS 缓存功能,本文不再赘述。

P.S. DNS 缓存服务请务必确保随系统开机启动;

nscd

name service cache daemon 即装即用,通常为 linux 系统默认安装,相关介绍可参考其 manpage:man nscd;man nscd.conf

(1)安装方法:通过系统自带软件包管理程序安装,如 yum install nscd

(2)缓存管理(清除):

1.service nscd restart 重启服务清除所有缓存;

2.nscd -i hosts 清除 hosts 表中的域名缓存(hosts 为域名缓存使用的 table 名称,nscd 有多个缓存 table,可参考程序相关 manpage)

dnsmasq

较为轻量,可选择其作为 nscd 替代,通常需单独安装

(1)安装方法:通过系统自带软件包管理程序安装,如 yum install dnsmasq

(2)核心文件介绍(基于 Dnsmasq version 2.86,较低版本略有差异,请参考对应版本文档如 manpage 等)

(3)/etc/default/dnsmasq 提供六个变量定义以支持六种控制类功能

(4)/etc/dnsmasq.d/ 此目录含 README 文件,可参考;目录内可以存放自定义配置文件

(5)/etc/dnsmasq.conf 主配置文件,如仅配置 dnsmasq 作为缓存程序,可参考以下配置

listen-address=127.0.0.1 #程序监听地址,务必指定本机内网或回环地址,避免暴露到公网环境 port=53 #监听端口 resolv-file=/etc/dnsmasq.d/resolv.conf #配置dnsmasq向自定义文件内的 nameserver 转发 dns 解析请求 cache-size=150 #缓存记录条数,默认 150 条,可按需调整、适当增大 no-negcache #不缓存解析失败的记录,主要是 NXDOMAIN,即域名不存在 log-queries=extra #开启日志记录,指定“=extra”则记录更详细信息,可仅在问题排查时开启,平时关闭 log-facility=/var/log/dnsmasq.log #指定日志文件 #同时需要将本机 /etc/resolv.conf 第一个 nameserver 指定为上述监听地址,这样本机系统的 dns 查询请求才会通过 dnsmasq 代为转发并缓存响应结果。 #另 /etc/resolv.conf 务必额外配置 2 个 nameserver,以便 dnsmasq 服务异常时支持系统自动重试,注意 resolv.conf 仅读取前 3 个 nameserver

(6)缓存管理(清除):

1.kill -s HUP `pidof dnsmasq` 推荐方式,无需重启服务

2.kill -s TERM `pidof dnsmasq` 或 service dnsmasq stop

3.service dnsmasq force-reload 或 service dnsmasq restart

(7)官方文档:https://thekelleys.org.uk/dnsmasq/doc.html

3. 纯内网业务取消查询域名的AAAA记录的请求

以 linux 操作系统为例,常用的网络请求命令行工具常常通过调用 getaddrinfo() 完成域名解析过程,如 ping、telnet、curl、wget 等,但其可能出于通用性的考虑,均被设计为对同一个域名每次解析会发起两个请求,分别查询域名 A 记录(即 IPV4 地址)和 AAAA 记录(即 IPV6 地址)。

因目前大部分公司的内网环境及云上内网环境还未使用 ipv6 网络,故通常 DNS 系统不为内网域名添加 AAAA 记录,徒劳请求域名的 AAAA 记录会造成前端应用和后端 DNS 服务不必要的资源开销。因此,仅需请求内网域名的业务,如决定自研客户端,建议开发人员视实际情况,可将其设计为仅请求内网域名 A 记录,尤其当因故无法实施本地缓存机制时。

4. 规范域名处理逻辑

客户端需严格规范域名/主机名的处理逻辑,避免产生大量对不存在域名的解析请求(确保域名从权威渠道获取,避免故意或意外使用随机构造的域名、主机名),因此类请求的返回结果(NXDOMAIN)通常不被缓存或缓存时长较短,且会触发客户端重试,对后端 DNS 系统造成一定影响。

网络维护学什么语言好2

打开网络,与世界握手。我们在享受互联网方便快捷服务的同时也饱尝其苦,深受其害。从信息泄露到网络诈骗,从色情图片到非法网站,从人肉搜索到网络制作-网民都渴望有个祥和宁静的网络世界,造风清气正、和谐向上的网络空间,做合格的好网民。用良知和道义维护网络的正义,用正面的声音占领网络阵地,用洁净的语言肃清舆论导向,在网络上自觉践行社会主义核心价值观,对网络虚假信息,大声说“不”,维护网络秩序,,把群众的声音反映出来,争做新时代“四有好网民”,用“四有”的新要求来规范和约束自己的网络行为。

网络是一把双刃剑,恰如其分地运用网络,我们可以一日千里地进步,亦师亦友地亲近网络,我们可以日新月异地提高。但网络世界是现实世界的延伸,网络具有虚拟性、隐蔽性,可虚拟并不等于虛假,隐蔽往往意味着一些危险的存在。就像一-群戴着面具的人在跳舞,就像一群锦衣的人在夜行,其实离我们并不远,就在我们身边,就和我们息息相关。它无处不在,它无孔不入,它无所不包。

在现实生活中,我们要有安全意识,在网络世界里更需要提高安全防范意识。如果我们不能正视这些,就很难享受到网络带给我们的快乐和便捷。营造安全、和谐、绿色的网络环境,需要每一位网民参与,需要每一位网民奉献和传递正能量。俗话说,害人之心不可有,防人之心不可无。谁能知道面具背后隐藏的是不是杀机,谁能知道锦衣下面掩盖的是不是狰狞,每一个网民必须要有安全意识,改变不健康的网络习惯,必须时时刻刻绷紧安全这根弦,牢筑安全防线,让安全意识永驻心间,

让网络安全内化于心,外践于行,让网络不法分子无机可乘,真正强化网络安全这只盾。我们不仅要做中国好公民,更要做“有高度的安全意识、有文明的网络素养、有守法的行为习惯、有必备的防护技能”

的中国好网民。要坚定政治信念和立场,弘扬真善美,敢于向假恶丑亮剑,要敢于同网络上的歪风邪气作斗争,敢于发出自己真实的声音,敢于维护网民和社会利益,尽自己所能,为创造干净、纯洁、绿色、和谐的网络环境添砖加瓦。

网络维护学什么语言好3

构建传统的本地应用程序通常需要维护两个或更多的代码库。让我们看看两个框架,它们可以让你的代码保持统一。

网络开发者有几种传统的方法来提供离线体验。

1. Progressive Web Apps(渐进式网络应用程序)。通过添加manifest file(清单文件)和service worker(服务工作者),响应式网络应用程序可以在无互联网连接的情况下加载应用。通常情况下,围绕数据缓存、同步、冲突解决和离线请求处理要解决的问题,比把应用做成PWA要多得多同时,为了让它显示在某人的主屏幕上,用户必须访问网站并点击屏幕底部的安装按钮,这奇怪的操作违背了大多数用户的使用习惯,即在任何涵盖网站内容的东西上刷掉或点击X。虽然我对PWA的未来寄予厚望,但现在我不认为它是触达用户的有效方式。

2. Cordova。Apache Cordova通过将网站放在WebView(基本上是本地应用的iframe)中,并将WebView打包成iOS或Android应用,从而将网站变成移动应用。虽然这是将网站带到应用商店最便捷的方式,在理论上可以完成几乎所有原生应用的功能。这个过程和最终结果都充满了各种不确定性。即使是一个在移动浏览器中完美运行的网站,也可能需要大量的工作才能在Cordova应用程序中正常运行。此外,对本地智能手机API的支持也是不完整的,有时是不可靠的;即使是像媒体控制这样简单的功能,实现效果也是差强人意。因此,尽管Cordova作为提供 "应用中的网站 "的最具成本效益的方式发挥了重要作用,但我认为它并不是新项目的最佳选择。(在这里我不能不提到Ionic,它确实有助于实现原生的外观和感觉,但通常需要部分或全部重写,仍然不能解决一些问题)。

在排除了以上选项之后,我所知道的其余选项是。

· 传统的本地应用程序

· Xamarin

· React Native

· Flutter

构建传统的本地应用程序需要我维护两个或更多的代码库,而且我还要从头开始学习Swift,所以听起来就很麻烦。Xamarin可能是一个不错的选择,因为我在日常工作中使用.NET,但我的印象是,它没有其他公司那样强大的社区和市场份额。我也有一些相关的经验可以考虑。我已经用React做了几个副业,并且一直在用Flutter做游戏。最后,React Native和Flutter似乎是最适合我的技能组合的选择。

在几个周末的时间里,我建立了两个概念验证的应用程序,分别使用最新版本的React Native和Flutter。这是两个完全不同的框架,每个框架都有其令人沮丧和愉快的方式,我认为从一个Web开发者的角度来比较它们是有价值的。

它们如何工作?组件和渲染

React Native(由Meta/Facebook创建)提供了一套React组件,代表布局和UI抽象,如View(用于包含和安排元素,像一个`p`,上面有`display: flex`)或TextInput(像一个HTML`input`或`textarea`)。然后,它使用一个C++引擎,为每个平台单独编译,将这些翻译成本地组件,在屏幕上渲染。代码使用JavaScript引擎(目前是JavaScriptCore,Safari使用的引擎,但Hermes的自定义引擎可能很快就会接替前者)运行,并通过Bridge上的序列化消息与本地代码进行通信。

Flutter(由谷歌创建)是一个集视图框架、渲染引擎、代码执行引擎和组件库于一身的软件。它使用Dart,一种由谷歌创建和维护的高级编程语言,并明显受到React的启发:每个部件(组件)都有一个构建(渲染)方法,通常返回一个或多个其他部件的树。Flutter不在目标设备上渲染本地组件,而是选择接管整个屏幕并渲染自己的用户界面(与视频游戏不同)。Dart代码是为桌面和移动设备使用的各种指令集提前编译的。在网络上,它被转换为JavaScript。

学习过程:语言和工具

有人说,学习Flutter的新编程语言所需的时间会比设置和学习React Native工具的时间多出一个数量级。然而,我完全没有发现这一点。Dart是一种非常简单且对开发者友好的语言,与TypeScript、C#和Kotlin有很大的相似之处。它的文档是一流的。更重要的是,我很喜欢学习它--它的强可读性,有很多很酷的特性,比如级联符号和默认的空安全,而且编译器会告诉哪里出错。所以,学习这门语言需要一天左右的时间,但如果你已经知道强类型的命令式编程语言,你将会很轻松地完成它。

使用React Native,只要你知道JavaScript或TypeScript,你就不会花时间学习新的编程语言。然而,你将不得不学习一些标准的工具和库来提高速度--感觉React Native的工具和生态系统要比Flutter复杂得多,但在质量上并没有真正的优势(关于这一点,在下一节有更多的介绍)。对我来说,这两个框架的升级时间是差不多的,比较一下我第一次学习Flutter(通过Flame,一个游戏开发库)和学习React Native的时间。我估计,无论哪种方式,提高生产力的最低时间是10到15个小时。

特点:没有什么聚会能比得上第一次聚会了

React Native遵循标准的网络开发方法,其特点是你的本地`node_modules`文件夹。它包括你拥有一个应用程序所需的基本工具,但如果你想要一个UI语言(如Material Design或Cupertino)、图标、状态管理、本地化、HTTP请求、高级开发者工具等,你将依靠社区支持的代码或编写自己的。React Native社区很大,而且非常活跃。但这确实意味着一个典型的React Native应用将是一个由代表不同设计理念的软件包、非标准化的API和一知半解的文档组成的拼凑。

相比之下,谷歌在过去几年里对Flutter进行了大量投资,并支持开箱即用的令人印象深刻的功能集。Material Design和Cupertino组件、数百个图标、基本的状态管理设置、几个运行时的开发者工具和25个核心的第一方包,包括本地化、HTTP请求等等--所有这些都有树形摇动功能,所以你不会用你不使用的东西使你的应用变得臃肿。我所使用的组件都有一个一致的设计,并且像手套一样适合这个框架。

你可以在没有任何第三方软件包的情况下发布一个功能强大、设计精良的Flutter应用,这在React Native中是不可行的。我在React Native中的`package.json`文件和Flutter中的`pubspec.yaml`文件之间的大小差异是惊人的。Flutter做了很多的工具和组件,让开发者开箱即用。包括:Dart的软件包库。 pub.dev可能永远不会接近NPM的规模。考虑到NPM不能访问浏览器或Node API,很难估计有多少NPM包与React Native兼容,但我猜测还是有足够多的包可以在数量上获胜。

如果你对自己编写不常见的算法或视觉效果的能力有信心,你可能会对这两个框架感到满意。否则,你会想在开始之前在每个软件包库中打探一下,看看它们是否有你需要的东西。

UI:平台、一致性和定制

在使用Flutter和React Native使用户界面保持平台一致性时会遇到一些麻烦。Flutter有自己的图形引擎,所以你会认为无论你去哪里,一切都会是一样的。但我确实注意到在网页、MacOS和iOS输出之间的间距和对齐方式有一些差异,但我无法修复。虽然它们是非常小的、单一像素的差异--我怀疑最终用户甚至会注意到--但它们确实让我有点紧张。

由于React Native在每个平台上都渲染原生组件,它的问题并不比Flutter少。说到样式,React Native使用CSS。它比这稍微复杂一些,但如果你对CSS(以及重要的是,flexbox)很熟悉,你就可以在React Native中随心所欲地制作。Flutter的造型机制虽然不同,但也不是完全陌生的--大多数类似于CSS的属性都是由同名的部件字段表示的,而Column和Row部件是flex layout的直接替代物。不过,你可能还是要查一下你想做的每一件事,或者查看小部件的代码,而不是插入一些CSS属性,然后继续你的快乐之路。Flutter的组合范式也需要一些时间来适应;很多你通常可能用CSS属性应用的东西在Flutter中都有自己的widget。

这两个框架都是非常可定制的。如果你有完美的像素设计,你会很快进入构建组件的状态。

性能:反应灵敏的用户体验和动画

Flutter的最大卖点从一开始就是速度。该框架的营销演示充满了一望无际的全屏动画,不会错过任何一帧。而且,从我用它制作一个简单的游戏的经验来看,我可以证明它有能力处理你扔给它的东西。它很流畅。事实上,我之所以转向Flutter,是因为我已经厌倦了在HTML5画布上看着精灵在屏幕上闪动和交错。

这并不是说Flutter会比原生应用更快。即使性能在视觉上与原生程序相似,你仍然有一个完整的非原生渲染引擎在硬件上运行。至少,你会使用更多的内存。

React Native在性能方面并没有太大的优势。它在后台解释JavaScript,然后在JavaScript引擎和本地代码之间扮演中间人。我们已经知道JavaScript是相对较慢的。不建议用这两个软件来构建一个身临其境的第一人称射击游戏(尽管Flutter无疑会做得更好)。当我们在谈论文本表单和商业逻辑时,没有必要为十几或二十几毫秒的响应时间争论不休。作为一个程序员,你所做的决定对用户体验的影响要远远大于引擎盖下运行的框架。

有一点需要注意的是动画。Flutter团队一直在努力使他们的框架成为美丽的、触摸响应的动画的代名词。如果你想建立一个用波纹和花纹包围用户的应用程序,就可以选择Flutter。

管线:构建和发布你的应用程序

也许让React Native开发者不跳槽的最大原因是Expo。Expo是一家私营公司,为React Native应用提供开发者工具和服务,包括一个可管理的跨平台运行时间、本地API模块,以及一个针对两个应用商店的自动部署工具。Expo还提供了一个名为Expo Go的应用程序,让你可以在智能手机上测试你的应用程序,无需侧载或使用有线连接;只需将相机对准生成的QR码,就可以了。这是一个令人印象深刻的产品。

Flutter没有相应的服务。担忧fastlane填补了发布自动化部门的一些空白,当然Flutter还内置了一个跨平台的运行时。但如果你想在实体智能手机上测试你的Flutter应用,你就必须把它插到你的笔记本电脑上,然后移动一些.apk或.ipa文件。Android和iPhone都有很好的模拟器。

开发者的经验:身处战壕

这一部分会比较主观。我相信很多开发者都喜欢React Native的体验,也有很多人对Flutter感到失望。但对我来说,Flutter比React Native更容易使用和工作。有几个客观因素对Flutter有利--热重载、更紧密的VS Code集成和更广泛的内置调试工具--但不能说这些都是决定性因素。

我用React Native构建的时间是Flutter的两倍。

其中大部分时间都花在了基本的事情上,例如:项目设置、图标、消失的应用栏、神秘的CLI警告、让受控输入工作。

总结:最好的框架是你选择的框架

抛开所有的商业影响不谈,我不能强烈推荐Flutter。但最近React Native阵营有很多令人振奋的消息,它在容易招聘以及有大规模开源社区支持方面为自己提供了强有力支持。今年的Stack Overflow开发者调查显示Flutter和React Native并驾齐驱,RN在 "专业开发者 "类别中略微领先,Flutter在 "所有调查对象 "类别中略微领先。(两者都远远领先于Ionic、Cordova和Xamarin)。

客观地说,这里没有明显的赢家。你会根据你的应用程序的需求和限制来选择一个框架,就像你做任何技术决定一样。React Native显然不会消失,一年后,由于社区贡献的稳定步伐,开发者的体验可能会大大改善。但在我看来,Flutter将继续存在,并将在短期内大幅增长,因为开发者发现它是多么强大和易于使用。


内容更新时间(UpDate): 2023年03月08日 星期三

版权保护: 【本文标题和链接】网络维护学什么语言好学(网络维护学什么语言好) http://www.youmengdaxiazuofa.net/longxia8/84462.html






















你的评论更有价值!!!
  • 全部评论(0
    还没有评论,快来抢沙发吧!
博客主人百科博主
女,免费分享各种生活、电商知识、百科常识。
  • 文章总数
  • 100W+访问次数
  • 建站天数
  • {/dede:arclist}