Android网络代理原理及实现

news2024/11/23 6:56:59

网络代理简介

代理典型的分为三种类型:

正向代理

缓存服务器使用的代理机制最早是放在客户端一侧的,是代理的原型,称为正向代理。其目的之一
是缓存,另一目的是用来实现防火墙(阻止互联网与公司内网之间的包,同时要让必要的包通过)。
组网图如下所示:

forward_proxy

在使用正向代理时,一般需要在浏览器的设置窗口中的代理服务器一栏中填写正向代理的IP地址。
当设置了正向代理时。浏览器会忽略网址栏的内容,直接将所有请求发给正向代理(Http 的URI
部分从原来的文件路径改成http的完整路径,用于转发)。请求包中的URI如下所示:

forward_proxy_http

反向代理

通过将请求消息中的URI中的目录名与Web服务器进行关联,使得代理能够转发一般的不包含完整网
址的请求消息。这种方式称为反向代理(客户端不需要进行代理配置,地址栏中域名通过DNS服务器
解析成对应的为代理服务器地址,代理服务器根据请求消息中的URI的目录名转发给相应的服务器处
理)。这种方式一般应用于缓存服务器,分布式服务器场景。

reverse_proxy

透明代理

通过请求消息包头部中的IP地址,进行拦截转发,这种方式成为透明代理。透明代理需要对请求消
息进行拦截,如果请求消息到目的服务器有多条路径,就需要在每条路径中设置透明代理,通常为
了方便,需要把组网设计成只有一条路径,并在该条路径中进行拦截。比如在连接互联网的接入网
入口处可设置透明代理。

客户需求Http/Https Proxy业务

客户需求的Http/Https代理业务,属于客户端一侧的代理,即我们上述介绍的正向代理。
Android原生框架已支持http/https代理功能,博主基于原生框架接口实现对所有网络
进行代理配置。

框架实现

Android中的几个Proxy概念:

名称描述相关接口
GlobalProxy全局代理,对所有网络(以太网,WiFi,vpn等)生效。ConnectivityManager.getGlobalProxy()
ConnectivityManager.setGlobalProxy(ProxyInfo p)
NetWorkProxy存在全局代理,则全局代理即为该网络的代理,否则为该network特定的http代理。
说明:应用可以绑定指定的网络,当未配置全局代理时,各个应用的代理可以不同。
ConnectivityManager.getProxyForNetwork(Network network)
ConnectivityManager.getBoundNetworkForProcess()
ConnectivityManager.bindProcessToNetwork(Network network)
DefaultProxy默认代理为系统环境生效代理。当指定全局代理时,会将全局代理应用到默认代理。没有指定全局代理时,默认网络(首选网络)的代理会应用到默认代理。ConnectivityManager.getDefaultProxy()

本文的Http/Https代理业务,针对的是GlobalProxy的配置,对所有网络生效。
相关的配置项:

名称描述Settings provider 中使用的Keynvram 的Pvalue备注
proxy host代理服务器地址Settings.Global.GLOBAL_HTTP_PROXY_HOST以"host:port"形式持久存储
proxy port代理服务器端口Settings.Global.GLOBAL_HTTP_PROXY_PORT以"host:port"形式持久存储
exclusion list不使用代理的网址列表Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST持久存储
PAC(Proxy Auto Config)代理配置脚本文件,可以实现对符合一定规则的url配置相应的代理服务器,实现多代理服务器的大型代理网络,具体可以参考 PAC(代理自动配置)_百度百科, PAC自动代理文件格式,教你如何写PAC文件Settings.Global.GLOBAL_HTTP_PROXY_PAC博主目前不支持
Global Proxy配置实现架构

在这里插入图片描述

http/https 客户端请求Proxy应用详解

方式一 基于Android ojluni实现
  • ojluni(OpenJDK Lang,Util,Net,IO)库提供了URL,HttpURLConnection等类用于建立http连接。
  • 最原始的这个Java lib库,需要应用自己调用ProxySelector,对URL进行处理,并用处理后的URI进行
    请求。
  • 在Android4.4中,框架层引入了okhttp(代码目录:android/external/okhttp),并基于okhttp实现了HttpHandlerHttpsHandler(代码目录:android/external/okhttp/android/main/java/com/squareup/okhttp),
    这两个类实现了URLStreamHandler
  • 在ojluni中Android利用反射机制,当解析出协议为http或者https时,将http请求或https请求的处理实现交给okhttp的HttpHandlerHttpsHandler,并且没有携带指定的proxy。

android/libcore/ojluni/src/main/java/java/net/URL.java

	       static URLStreamHandler getURLStreamHandler(String protocol) {

		    /*此处略去其他代码*/
		    // Fallback to built-in stream handler.
		    // Makes okhttp the default http/https handler
		    if (handler == null) {
		        try {
		            // BEGIN Android-changed
		            // Use of okhttp for http and https
		            // Removed unnecessary use of reflection for sun classes
		            if (protocol.equals("file")) {
		                handler = new sun.net.www.protocol.file.Handler();
		            } else if (protocol.equals("ftp")) {
		                handler = new sun.net.www.protocol.ftp.Handler();
		            } else if (protocol.equals("jar")) {
		                handler = new sun.net.www.protocol.jar.Handler();
		            } else if (protocol.equals("http")) {
		                handler = (URLStreamHandler)Class.
		                    forName("com.android.okhttp.HttpHandler").newInstance();
		            } else if (protocol.equals("https")) {
		                handler = (URLStreamHandler)Class.
		                    forName("com.android.okhttp.HttpsHandler").newInstance();
		            }
		            // END Android-changed
		        } catch (Exception e) {
		            throw new AssertionError(e);
		        }
		    }
		}

  • 在okhttp的HttpHandlerHttpsHandler中如果没有指定proxy,则使用的是默认代理选择器(ProxySelector.getDefault())。

  • ProxySelector.getDefault(),实例为ojluni中的“sun.net.spi.DefaultProxySelector”,其根据系统环境中的http/https代理相关属性对URL进行解析匹配判断处理。

  • 系统环境中的http/https代理相关属性如下:

    属性名称httphttps
    代理服务器地址http.proxyHosthttps.proxyHost
    代理服务器端口http.proxyPorthttps.proxyPort
    不使用代理的网址列表http.nonProxyHostshttps.nonProxyHosts
  • 从上述实现中,可以看到,即便设置了全局代理(并应用到了系统默认代理),无法保证所有请求都走的全局代理。系统默认代理在全局代理设置结束后仍可以变更。

Demo1 此处仅示范最简单的同步请求:

	    private void demoHttpURLConnection() {
		new Thread() {
		    @Override
		    public void run() {
		        /*当我们设置页面修改代理参数==>nvram 变更==>SystemManager收到广播 ==>
		          调用ConnectivityService.setGlobalProxy==>发出广播==》默认代理参数变更*/

		        //此处获取到的默认代理参数与设置的一致(http.nonProxyHosts分隔符变更为"|")
		        String host = System.getProperty("http.proxyHost");
		        String port = System.getProperty("http.proxyPort");
		        String nonProxyHosts = System.getProperty("http.nonProxyHosts");

	    //                //假如我们在此处修改默认代理参数,那么接下来的http请求也就变更
	    //                System.setProperty("http.proxyHost", "");
	    //                System.setProperty("http.proxyPort", "");
	    //                System.setProperty("http.nonProxyHosts", "");

		        Log.d(TAG, "host: " + host);
		        Log.d(TAG, "port: " + port);
		        Log.d(TAG, "nonProxyHosts: " + nonProxyHosts);

		        //以下请求基于默认代理参数进行
		        // 也就是"http.proxyHost","http.proxyPort","http.nonProxyHosts"只要确保正确,则代理请求正确
		        try {
		            URL url = new URL("http://192.168.xx.xx/cer/cert.pem");
		            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		            connection.setConnectTimeout(5000);
		            int code = connection.getResponseCode();
		            if (code == 200) {
		                InputStream inputStream = connection.getInputStream();
		                String ret = inputStreamString(inputStream);
		                Log.d(TAG, "success.. ret:" + ret);
		            } else {
		                Log.e(TAG, "fail..");
		            }
		        } catch (Exception e) {
		            e.printStackTrace();
		            Log.e(TAG, "e:" + e.getMessage());
		        }
		    }
		}.start();
	    }
方式二 基于okhttp实现
  • okhttp因为设计强大,易用,问题少,因此Android框架中也将其引入,第三方应用中使用也很广泛。
  • okhttp为开源http客户端,因此在Http代理的处理上设计为:

    (1)直接设置代理的host port,使当前请求直接走指定的代理

    (2)实现一个ProxySelector,对URL满足一定规则进行匹配处理,选择不同的代理

    (3)不设置代理或ProxySelector,okhttp内部直接使用默认代理服务器。

android/external/okhttp/okhttp/src/main/java/com/squareup/okhttp/OkHttpClient.java

		 OkHttpClient copyWithDefaults() {
		    OkHttpClient result = new OkHttpClient(this);
		    if (result.proxySelector == null) {
		      result.proxySelector = ProxySelector.getDefault();
		    }
		    /*省略其他代码*/
		    return result;
		  }

		  @android/external/okhttp/okhttp-urlconnection/src/main/java/com/squareup/okhttp/OkUrlFactory.java
		  HttpURLConnection open(URL url, Proxy proxy) {
		      /*省略其他代码*/
		      OkHttpClient copy = client.copyWithDefaults();
		      copy.setProxy(proxy);
		      /*省略其他代码*/
		   }
  • 上述okhttp的实现说明,使用okhttp进行请求也无法保证所有请求都走了全局代理(全局代理已应用到了默认代理),okhttp的单个请求可以特别指定它的代理服务器。

Demo2 此处仅示范最简单的同步请求:

    private void demoOkhttp() {
        new Thread() {
            @Override
            public void run() {
                try {
                    //当指定了Proxy,则proxySelector会失效。不指定Proxy和proxySelector,走默认代理(同方式一,只要确保系统默认代理参数正确即可)
                    OkHttpClient client = new OkHttpClient.Builder().proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.128.81", 808))).proxySelector(ProxySelector.getDefault()).build();//创建OkHttpClient对象

                    Request request = new Request.Builder()
                            .url("http://192.168.xx.xx/cer/cert.pem")//请求接口。如果需要传参拼接到接口后面。
                            .build();//创建Request 对象
                    Response response = null;
                    response = client.newCall(request).execute();//得到Response 对象
                    if (response.isSuccessful()) {
                        Log.d(TAG, "response.code()==" + response.code());
                        Log.d(TAG, "response.message()==" + response.message());
                        Log.d(TAG, "res==" + response.body().string());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
方式三 基于apache-http实现
  • apache-http 也是属于使用比较广泛的开源http客户端。Android系统中也有引入(代码目录:android/external/apache-http),并在其基础上对代理相关代码做了一定的修改。
  • 第三方应用使用时在moudle的gradle中增加以下,即可引入Android系统中的apache-http
        android {
            useLibrary 'org.apache.http.legacy'
        }
  • Android修改代理主要实现:

    (1)设置指定代理时,直接使用指定代理

    (2)未设置指定代理时,使用默认代理

android/external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java

        @Override
        protected HttpRoutePlanner createHttpRoutePlanner() {
            // BEGIN android-changed
            //     Use the proxy specified by system properties
            return new ProxySelectorRoutePlanner(getConnectionManager().getSchemeRegistry(), null);
            // END android-changed
        }

        @android/external/apache-http/src/org/apache/http/impl/conn/ProxySelectorRoutePlanner.java
        public HttpRoute determineRoute(HttpHost target,
                                HttpRequest request,
                                HttpContext context)
            throws HttpException {
            /*省略其他代码*/

            // BEGIN android-changed
            //     If the client or request explicitly specifies a proxy (or no
            //     proxy), prefer that over the ProxySelector's VM-wide default.
            HttpHost proxy = (HttpHost) request.getParams().getParameter(ConnRoutePNames.DEFAULT_PROXY);
            if (proxy == null) {
                proxy = determineProxy(target, request, context);
            } else if (ConnRouteParams.NO_HOST.equals(proxy)) {
                // value is explicitly unset
                proxy = null;
            }
            // END android-changed

            /*省略其他代码*/
            return route;
            }

             protected HttpHost determineProxy(HttpHost    target,
                                      HttpRequest request,
                                      HttpContext context)
                throws HttpException {

                // the proxy selector can be 'unset', so we better deal with null here
                ProxySelector psel = this.proxySelector;
                if (psel == null)
                psel = ProxySelector.getDefault();
                if (psel == null)
                return null;

                URI targetURI = null;
                try {
                targetURI = new URI(target.toURI());
                } catch (URISyntaxException usx) {
                throw new HttpException
                    ("Cannot convert host to URI: " + target, usx);
                }
                List<Proxy> proxies = psel.select(targetURI);

                Proxy p = chooseProxy(proxies, target, request, context);

                HttpHost result = null;
                if (p.type() == Proxy.Type.HTTP) {
                // convert the socket address to an HttpHost
                if (!(p.address() instanceof InetSocketAddress)) {
                    throw new HttpException
                    ("Unable to handle non-Inet proxy address: "+p.address());
                }
                final InetSocketAddress isa = (InetSocketAddress) p.address();
                // assume default scheme (http)
                result = new HttpHost(getHost(isa), isa.getPort());
                }

                return result;
            }
  • 上述代理实现说明,使用apache-http进行请求也无法保证所有请求都走了全局代理(全局代理已应用到了默认代理),apache-http的单个请求可以特别指定它的代理服务器。

Demo3 此处仅示范最简单的同步请求:

      private void demoApacheHttp() {
	    new Thread() {
		@Override
		public void run() {
		    try {
			HttpClient client = new DefaultHttpClient();
			HttpGet request = new HttpGet("http://192.168.xx.xx/cer/cert.pem");
			//当指定了Proxy,则直接使用该代理。不指定Proxy则走默认代理(同方式一,只要确保系统默认代理参数正确即可)
			HttpHost proxy = new HttpHost("192.168.xx.xx", 808);
			request.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

			HttpResponse response = client.execute(request);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			    String ret = EntityUtils.toString(response.getEntity());
			    Log.d(TAG, "success.." + ret);
			}

		    } catch (ClientProtocolException e) {
			e.printStackTrace();
		    } catch (IOException e) {
			e.printStackTrace();
		    }
		}
	    }.start();
	}

方式四 基于Android Network实现
  • 前述三种方式,如果没有指定特殊的代理,则最终使用的都是系统环境的默认代理。而Default Proxy可以直接通过System.setProperty来修改,这将导致Android无法进行维护。
  • 因此Android框架层中维护了Global Proxy,当Global Proxy变更则同时更新Default Proxy。按照目前设计思路,Android应该希望每个应用均可以指定特定的网络进行请求,
    且各个网络代理可以不同。因此Android的Network.java也提供了单独的接口进行网络连接。
  • Android Network.java的代理实现设计也非常简单:

    (1)直接使用openConnection(URL url, java.net.Proxy proxy)对某个请求指定特殊的代理。内部实现直接利用okhttp进行请求。

android/frameworks/base/core/java/android/net/Network.java

public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException {
                if (proxy == null) throw new IllegalArgumentException("proxy is null");
                maybeInitHttpClient();
                String protocol = url.getProtocol();
                OkUrlFactory okUrlFactory;
                // TODO: HttpHandler creates OkUrlFactory instances that share the default ResponseCache.
                // Could this cause unexpected behavior?
                if (protocol.equals("http")) {
                    okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxy);
                } else if (protocol.equals("https")) {
                    okUrlFactory = HttpsHandler.createHttpsOkUrlFactory(proxy);
                } else {
                    // OkHttp only supports HTTP and HTTPS and returns a null URLStreamHandler if
                    // passed another protocol.
                    throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
                }
                OkHttpClient client = okUrlFactory.client();
                client.setSocketFactory(getSocketFactory()).setConnectionPool(mConnectionPool);
                // Let network traffic go via mDns
                client.setDns(mDns);

                return okUrlFactory.open(url);
            }
(2)使用openConnection(URL url),使用当前网络的代理(从实现来看,单个网络应该只支持设置代理域名和端口,不支持不进行代理网址的过滤,如果设置了全局代理,利用 Network.java的这个接口进行请求,同样不支持不进行代理网址的过滤)

android/frameworks/base/core/java/android/net/Network.java

public URLConnection openConnection(URL url) throws IOException {
                final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull();
                if (cm == null) {
                    throw new IOException("No ConnectivityManager yet constructed, please construct one");
                }
                /* note:此处我们可以看出,该实现没有完全确定,后续可能不支持全局代理替换单个Network代理。*/
                // TODO: Should this be optimized to avoid fetching the global proxy for every request?
                final ProxyInfo proxyInfo = cm.getProxyForNetwork(this);
                java.net.Proxy proxy = null;
                if (proxyInfo != null) {
                    proxy = proxyInfo.makeProxy();
                } else {
                    proxy = java.net.Proxy.NO_PROXY;
                }
                return openConnection(url, proxy);
            }
  • 上述实现中,也能看到单个网络的请求也可指定特殊代理。如果不指定代理,则使用的是全局代理。此处存在差异是该全局代理却不支持不进行代理的网址的过滤。(可能是Android的bug,只要代理传null,其实就和其他的方式一样使用默认代理了)

Demo4 此处仅示范最简单的同步请求:

    private void demoAndroidNetwork() {
            new Thread() {
                @Override
                public void run() {
                    try {
                        URL url = new URL("http://192.168.xx.xx/cer/cert.pem");

                        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                        Network defNet = cm.getActiveNetwork();
                        Log.e(TAG, "defNet.." + defNet);
                        HttpURLConnection connection = (HttpURLConnection) defNet.openConnection(url);
                        connection.setConnectTimeout(5000);
                        int code = connection.getResponseCode();
                        if (code == 200) {
                            InputStream inputStream = connection.getInputStream();
                            String ret = inputStreamString(inputStream);
                            Log.e(TAG, "success.." + ret);

                        } else {
                            Log.e(TAG, "fail..");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        Log.e(TAG, "e:" + e.getMessage());
                    }
                }
            }.start();
        }

相关代码路径

模块路径说明
Android frameworkandroid/frameworks/base/telecomm/java/android/telecom/ConnectionService.java
android/frameworks/base/core/java/android/net/Network.java
Global Proxy维护,以及提供单个Network的网络连接接口
ojluniandroid/libcore/ojluniOpenJDK Lang,Util,Net,IO库,默认代理选择器的实现在此
okhttpandroid/external/okhttp框架层实际使用了okhttp进行http请求
apache-httpandroid/external/apache-http第三方应用可以引用Android系统中的apache-http,Android在apache-http中修改了代理的实现

遗留问题说明

  • 上述方式四,也就是使用指定Network进行网络请求,在设置了全局代理的情况时,全局代理的不进行代理的域名列表将不生效。
    该问题可能为Android的bug,Android后续也可能不会对在此接口应用全局代理。目前未做修改,如有必要,我认为修改为和其他方式一样,直接使用默认代理。
  • 上述前三种方式,均存在默认代理被修改的风险(通过System.setProperty),此为Android系统整体的问题,后续可能SELINUX加强后,对这个属性进行保护,也许能进行规避。目前未做修改。

其他调试经验

  • 获取global proxy信息
        settings get global global_http_proxy_host
        settings get global global_http_proxy_port
        settings get global global_http_proxy_exclusion_list

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/490492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI 工具合辑盘点(六)持续更新

AI 图像生成和编辑工具 不久前&#xff0c;艺术创作是特定群体的领域。 不再是这样了&#xff01; 今天&#xff0c;在人工智能艺术生成器的帮助下&#xff0c;任何人都可以通过编写文本提示并让人工智能创建所需的图像来成为艺术家。 &#x1f3a8;&#x1f58c; 文本到图像…

多线程 双重检查锁详解

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Word处理控件Aspose.Words功能演示:在 Java 中将 Word DOC/DOCX 转换为 PDF

Aspose.Words是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。 Aspose API支持流行文件格式处理&#xff0c;并…

工业路由器误按RST复位键如何处理?RST键的作用

接触过工业路由器的朋友们都知道&#xff0c;几乎市面上的所有路由器产品都具备着一个常见但不常用的RST按键&#xff0c;它的作用是让工业路由器恢复出厂设置&#xff0c;也称为“复位键”“重置键”&#xff0c;用户可在通电情况下长按RST键10秒便会出现工业路由器指示灯全灭…

高级【IO】

目录 一.五种IO模型 &#xff08;1&#xff09;阻塞IO&#xff1a; &#xff08;2&#xff09;非阻塞IO &#xff08;3&#xff09;信号驱动IO: &#xff08;4&#xff09;IO多路转接 &#xff08;5&#xff09;异步IO 二.高级IO概念 1.同步通信、异步通信 2.阻塞、非阻…

你知道ChatGPT里面的G、P、T分别代表什么吗?

生成式AI&#xff0c; 在学习归纳数据分布的基础上&#xff0c;创造数据中不存在的新内容。可以生成文本、图片、代码、语音合成、视频和3D模型。 比尔盖茨&#xff1a;ChatGPT是1980年以来最具革命性的科技进步。 身处这个AI变革的时代&#xff0c;唯有躬身入局&#xff0c;…

vcs -libmap

1 libmap的作用 主要两个作用: 解决module名重复问题: 比如有两个IP, IP0和IP1, 它们都例化了一个叫ADD的module, 而且它们的filelist中都包含add.v. 这时会引起编译错误, 这时可以: (1) 指定IP0中的add.v编译到库lib0中, IP1中的add.v编译到库lib1中, (2) 指定IP0中的ADD使用…

超细Redis(二)

五大数据类型 官方文档&#xff1a; 翻译&#xff1a; Redis 是一个开源&#xff08;BSD 许可&#xff09;内存数据结构存储系统&#xff0c;用作数据库、缓存、消息代理和流引擎。Redis 提供数据结构&#xff0c;例如字符串、哈希、列表、集、带有范围查询的排序集、位图、超…

MySQL: 运算符使用练习

前言&#xff1a; 练习运算符的使用&#xff0c;加强记忆。 案例目的&#xff1a; 在已建数据库中创建数据表&#xff0c;并对表中数据进行处理&#xff0c;练习运算符&#xff08;包括数据运算符、逻辑运算符、位运算符&#xff09;的使用。 操作过程&#xff1a; 创建名…

java基础入门-03-【字符串】

Java基础入门-03-【字符串】 10、字符串10.1.API10.1.1API概述10.1.2如何使用API帮助文档 10.2.String类10.2.1 String类概述10.2.2 String类的特点10.2.3 String类的构造方法10.2.4 创建字符串对象两种方式的区别10.2.5 字符串的比较10.2.5.1 号的作用10.2.5.2 equals方法的作…

清华发布首个最全大模型安全评测系统,ChatGPT登榜首!

夕小瑶科技说 原创作者 | 天于刀刀 Python当前大型语言模型的火爆程度我们不用再进行赘述了&#xff0c;伴随着百度文心一言打响国内商业大模型第一枪&#xff0c;华为盘古&#xff0c;阿里通义千问&#xff0c;智谱ChatGLM,科大讯飞星火等国内公司纷纷开始布局。 另一方面由于…

01-Flink Metrics简介

Flink Metrics简介 Flink Metrics是Flink集群运行中的各项指标&#xff0c;包含机器系统指标&#xff0c;比如&#xff1a;CPU、内存、线程、JVM、网络、IO、GC以及任务运行组件&#xff08;JM、TM、slot、作业、算子&#xff09;等相关指标。 Flink Metrics包含两大作用&…

阿里云服务器购买教程(新手入门指南)

阿里云服务器ECS选购指南&#xff0c;阿里云百科分享2023阿里云服务器新手选择流程&#xff0c;选购云服务器有两个入口&#xff0c;一个是选择活动机&#xff0c;只需要选择云服务器地域、系统、带宽即可&#xff1b;另一个是在云服务器页面&#xff0c;自定义选择云服务器配置…

探究C语言数组的奥秘:大小可省略的定义、内存存储、数组名、传参、指针遍历、数组指针和指针数组、柔性数组等

也许你认为&#xff0c;C语言中的数组非常好理解&#xff0c;就是把一组相同类型的元素存储在同一块空间里。但是你可能并没有真正理解数组的本质&#xff0c;不信的话请回答一下下面的几个小问题&#xff0c;如果你能非常清晰的回答这些问题&#xff0c;那么你对C语言中的数组…

【Git】制造冲突以及解决冲突的详细方法

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

CentOS安装Redis数据库流程by阿里云服务器

使用阿里云服务器ECS安装Redis数据库流程&#xff0c;操作系统为CentOS 7.6镜像&#xff0c;在CentOS上安装Redis 4.0.14&#xff0c;云服务器选择的是持久内存型re6p实例&#xff0c;新手站长分享阿里云CentOS服务器安装Redis流程方法&#xff1a; 目录 在CentOS系统中部署R…

2023-05-04 线性DP_力扣练习

线性DP的力扣题目练习 这一章将会介绍线性动态规划的相关概念和经典问题&#xff0c;并给出一些练习题供大家演练。 用动态规划解决问题的过程有以下几个关键点&#xff1a;状态定义&#xff0c;状态的转移&#xff0c;初始化和边界条件。 状态定义 就是定义子问题&#xff…

【IM苹果推iMessage】苹果真机推送自动分配任务,自动分配任务,让您瞄准中高端客户

推荐内容IMESSGAE相关 作者✈️IMEAE推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容3.日历推 *** …

代码命名规范的套路是真优雅呀,命名如歌,代码如诗

日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力。那它们有什么规律呢&#xff1f; Java项目的代码结构&#xff0c;能够体现它的设计理念。Java采用长命名的方式来规范类的命名&#xff0c;能够自己表达…

ansible常用命令

目录 1、列出默认清单文件中的所有受管主机 2. 列出自定义清单文件中的所有受管主机&#xff08;自定义清单文件&#xff1a;inventory&#xff09; 3、运行playbook 4、创建需要输入文件密码的加密的文件 5、创建用密码文件的加密的文件 6、查看加密的文件内容 7、向已有…