Android网络代理原理及实现

网络代理简介

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

正向代理

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

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.mfbz.cn/a/18298.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十二章_Redis单线程 VS 多线程

Redis为什么选择单线程&#xff1f; 是什么 这种问法其实并不严谨&#xff0c;为啥这么说呢? Redis的版本很多3.x、4.x、6.x&#xff0c;版本不同架构也是不同的&#xff0c;不限定版本问是否单线程也不太严谨。 1 版本3.x &#xff0c;最早版本&#xff0c;也就是大家口口相…

Day965.从持续集成到持续部署 -遗留系统现代化实战

从持续集成到持续部署 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于从持续集成到持续部署的内容。 只有做好任务分解和小步提交&#xff0c;才能放心大胆地 PUSH 代码&#xff0c;触发持续构建&#xff1b; 只有通过质量门禁&#xff0c;才能得到一个有信心的制…

( 位运算 ) 268. 丢失的数字 ——【Leetcode每日一题】

❓268. 丢失的数字 难度&#xff1a;简单 给定一个包含 [0, n] 中 n 个数的数组 nums &#xff0c;找出 [0, n] 这个范围内没有出现在数组中的那个数。 示例 1&#xff1a; 输入&#xff1a;nums [3,0,1] 输出&#xff1a;2 解释&#xff1a;n 3&#xff0c;因为有 3 个数…

干货分享|一款让企业知识管理变得简单高效的工具软件

互联网发展到下半场&#xff0c;很多企业都开始进行数字化转型&#xff0c;在这个过程中&#xff0c;很多企业都忽视了极为重要的一点——企业的知识管理。如今信息化的时代&#xff0c;可以说企业的知识管理是引领企业数字化转型、进行创新的关键。 企业知识管理的实质就是对…

视频文本检索之CLIP4Clip

论文&#xff1a;CLIP4Clip: An Empirical Study of CLIP for End to End Video Clip Retrieval GitHub&#xff1a;https://github.com/ArrowLuo/CLIP4Clip 学习是一种行动反射&#xff0c; 不是为了晓得些“知识”&#xff0c; 要切己体察&#xff0c;代入自己&#xff0c…

mid360激光雷达跑Point-LIO算法

在商场里面上下楼穿梭,使用mid360激光雷达,完成建图 以下是建图的运行过程及参数配置 mid360激光雷达驱动 安装(ubuntu20.4 ) /ws_livox/src/livox_ros_driver2$source /opt/ros/noetic/setup.sh /ws_livox/src/livox_ros_driver2$./build.sh ROS1配置修改MID360_confi…

可拓展哈希

可拓展哈希 借CMU 15445的ppt截图来说明问题。 我们传统静态hash的过程是hash函数后直接将值存入对应的bucket&#xff0c;但是在可扩展hash中&#xff0c;得查询Directory&#xff08;左&#xff09;&#xff0c;存入directory指向的bucket&#xff08;右&#xff09;。 下面…

ASEMI代理ADI亚德诺LTC6992IS6-1#TRMPBF车规级芯片

编辑-Z LTC6992IS6-1#TRMPBF参数描述&#xff1a; 型号&#xff1a;LTC6992IS6-1#TRMPBF 输出频率&#xff1a;3.81Hz 工作电源电压范围&#xff1a;2.25 - 5.5V 通电复位电压&#xff1a;1.95V 电源电流&#xff1a;105-365A SET引脚处的电压&#xff1a;1V 频率设置电…

物联网|IAR集成开发环境简介|cc254核心板硬件资源|物联网之蓝牙4.0 BLE基础-学习笔记(3)

文章目录 4、IAR集成开发环境简介5、 cc254核心板硬件资源 4、IAR集成开发环境简介 完整稳定的专业嵌入式开发环境&#xff0c;对不同的处理器有统一的用户界面&#xff0c;支持35种以上的MCU&#xff0c;包括8&#xff0c;16&#xff0c;32位&#xff0c; 完全兼容C语言的 高…

FPN和PAN的内容及区别

FPN和PAN都是用于解决在目标检测中特征金字塔网络(FPN)在多尺度检测任务上的不足的方法。下面分别详细介绍一下它们的原理和区别。 FPN FPN全称Feature Pyramid Network&#xff0c;是由FAIR在2017年提出的一种处理多尺度问题的方法。FPN的主要思路是通过构建金字塔式的特征图…

【CSS系列】第四章 · CSS字体属性

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

人机智能中几个困难问题浅析

1、人机之间与人人之间信任的区别人机之间的信任与人人之间的信任存在以下异同&#xff1a;①信任对象。人机之间的信任的对象是计算机系统、算法、机器人等&#xff0c;而人人之间的信任的对象是其他人。②信任方式。人机之间的信任是基于技术、安全协议等建立的&#xff0c;例…

【Linux网络】传输层中UDP和TCP协议

文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手&#xff08;连接管理机制&#xff09;3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号 端口号port标识一…

2023年前端面试题汇总-代码输出篇

1. 异步 & 事件循环 1. 代码输出结果 const promise new Promise((resolve, reject) > {console.log(1);console.log(2); }); promise.then(() > {console.log(3); }); console.log(4); 输出结果如下&#xff1a; 1 2 4 promise.then 是微任务&#xff0c;它…

1、防刷限流实现1

1、本章诉求 限流的需求出现在许多常见的场景中&#xff1a; 秒杀活动&#xff0c;有人使用软件恶意刷单抢货&#xff0c;需要限流防止机器参与活动某api被各式各样系统广泛调用&#xff0c;严重消耗网络、内存等资源&#xff0c;需要合理限流 2、流程设计 3、方案实现 3.1…

使用 spring 的 IoC 的实现账户的CRUD(2)双层实现

spring实现service和dao的数据的查找 dao层设置接口实现dao层的接口service设置接口通过注入dao层&#xff0c;来实现接口 //dao层的接口&#xff0c;定义了根据id查询的方法 public interface Accountdao {Account findByid(int id); }实现接口&#xff1a;实现了查询的方法 …

项目创建第一天 搭建前端环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、环境是什么&#xff1f;二、使用步骤1.前台搭建方式1.创建项目2.目录结构3. 安装elementui4. 创建路由5.使用axios6.bug记录6.1出现跨域问题6.2 解决方式6.…

2023年会展服务研究报告

第一章 行业概况 会展行业是指一系列与会议、展览、展示相关的服务和经济活动的总称&#xff0c;是加强企业间交流、促进合作和推动经济发展的重要手段。该行业涉及广泛&#xff0c;包括会议和展览的组织、场地租赁和设计、活动策划和执行、展品运输和咨询服务等各个环节。随着…

tiechui_lesson03_缓冲读写与自定义控制

学习了与应用层通过缓冲区方式的交互&#xff0c;包括读写&#xff0c;自定义控制等。小坑比较多&#xff0c;大部分是是头文件和设置上的错误&#xff0c;跟着视频敲想快进就跳过了一些细节。包括&#xff1a; <windef.h> 头文件的引用 //使用DWORD等类型switch语句…

基于标签的协同过滤算法实现与个人兴趣相关的文章推荐

一、前言 在当前信息爆炸的时代&#xff0c;每天都会涌现出大量的文章&#xff0c;人们有时候会感到信息的获取难度比筛选更大。而作为信息的提供者&#xff0c;我们应当为用户提供依据个人兴趣的文章推荐。 本项目中的文章标签相似度推荐功能使用了一种基于标签的协同过滤算…
最新文章