GVKun编程网logo

python websocket 客户端连接(python websocket-client)

4

在这里,我们将给大家分享关于pythonwebsocket客户端连接的知识,让您更了解pythonwebsocket-client的本质,同时也会涉及到如何更有效地ASP.NETMVC客户端连接ids

在这里,我们将给大家分享关于python websocket 客户端连接的知识,让您更了解python websocket-client的本质,同时也会涉及到如何更有效地ASP.NET MVC 客户端连接 ids4 SSo [授权] 302 重定向总是、DB2新手使用的一些小笔记:新建实例、数据库路径不存在、客户端连接 .、Docker 客户端连接 Docker Daemon 的方式、HTTP 客户端连接,选择 HttpClient 还是 OkHttp?的内容。

本文目录一览:

python websocket 客户端连接(python websocket-client)

python websocket 客户端连接(python websocket-client)

# -*- coding: utf-8 -*-
import json
import websocket
import _thread as thread


# try:
# import thread
# except ImportError:
# import _thread as thread


def on_message(self, message):   # 第一个参数必须传递
  print(message)


def on_error(self, error):
  print(error)


def on_close(self):
  print("### closed ###")


def on_open(self):
  def run():
    for i in range(3):  # 可以死循环发送
      ws.send(json.dumps({1: "123123"}))
    # ws.close()  # 发送完毕, 可以不关闭

  thread.start_new_thread(run, ())  # 启动线程执行run()函数发送数据


if __name__ == "__main__":

  while True:
    try:
      websocket.enableTrace(True)  # True 默认在控制台打印连接和信息发送接收情况
      ws = websocket.WebSocketApp("ws://192.168.130.164:8765/api/v1/data/",
        on_open=on_open,  # 连接后自动调用发送函数, 
        on_message=on_message,  # 接收消息调用
        on_error=on_error,
        on_close=on_close)
      ws.run_forever()  # 开启长连接

    # except KeyboardInterrupt: # 会被ws内部捕捉
      # print(123)
      # break
    except Exception as e: # ws 断开 或者psycopg2.OperationalError
      logger.warning("ws 断开 或者psycopg2.OperationalError, {}: {}".format(type(e), e))
      continue

原文出处:https://www.cnblogs.com/520zm/p/10689494.html

ASP.NET MVC 客户端连接 ids4 SSo [授权] 302 重定向总是

ASP.NET MVC 客户端连接 ids4 SSo [授权] 302 重定向总是

如何解决ASP.NET MVC 客户端连接 ids4 SSo [授权] 302 重定向总是

客户端代码

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    IdentityModelEventSource.ShowPII = true;

    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

    services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
               .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,options =>
               {
                   options.AccessDeniedpath = "/Authorization/AccessDenied";
               })
               .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,options =>
               {
                   options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                   options.Authority = "https://jpprojectsso.inthink.top:5000"; //
                   options.RequireHttpsMetadata = false;

                   options.ClientId = "TestClient";
                   options.ClientSecret = "Client Secrets";
                   options.Savetokens = true;
                   options.ResponseType = "code id_token";
                   options.GetClaimsFromUserInfoEndpoint = true;

                   options.Scope.Clear();
                   options.Scope.Add(OidcConstants.StandardScopes.OpenId);
                   options.Scope.Add(OidcConstants.StandardScopes.Profile);

               });
}
    

控制器看起来像这样:

[Authorize]
public IActionResult Privacy()
{
    var user = User.Identity.Name;
    return View();
}

ids4 连接客户端成功。但是客户端总是 302 重定向到 sso 并且 sso 成功重定向到客户端......循环。

我的 sso 使用 Jp 项目 ids4。我该如何解决这个问题?

谢谢,

解决方法

我发现了错误... 在 void 配置函数中。

app.UseAuthorization() 应该在 app.UseAuthentication() 之后执行

然后就可以了。

DB2新手使用的一些小笔记:新建实例、数据库路径不存在、客户端连接 .

DB2新手使用的一些小笔记:新建实例、数据库路径不存在、客户端连接 .

首先,是添加数据库实例:

  DB2的实例之间是相互独立的,实例可以被看作是数据库的容器。而默认DB2装好后会自己建一个名为DB2的实例。我们这里需要新建一个,命令这样敲:

在db2的命令行工具里面打开命令行,然后输入:

复制代码 代码如下:

db2icrt INSTNAME

它这个实例名还挺恶心的,必须是小于8个字符的名字。

  再用命令行创建好以后才能用那个控制中心的添加实例的功能来添加刚才创建的实例。其实这个添加只是把已有的实例添加到GUI的控制中心里,而不是创建实例。。。。所以,必须注意的是,在这个控制中心里,只要是添加的命令,似乎都得小心点它实际上并没有创建东西,只是把已有的东西拿进来管理。

  另外,再添加的时候,那个所谓的实例节点名也就仅仅是用于表示这个实例的一个节点的名字而已,似乎对于单台服务器来说意义不大。貌似是一个实例对应的每个实例节点组成一个分区实例的时候才有意义。

然后开始建立数据库:

  好的,建立好实例之后我们要在实例上建立数据库。由于是Windows的环境下,你第一次建一定会遇到类似这样的错误

复制代码 代码如下:

SQL1052N 数据库路径 "D:/foo/bar" 不存在。

说明:

该命令的 "<path>" 参数中指定的路径无效。不存在该名称的路径,或者在
DB2_CREATE_DB_ON_PATHS 注册表变量被禁用时,指定了路径(仅限于 Windows)


按照这个说法很简单只需要执行一下这个命令即可:

复制代码 代码如下:

db2set DB2_CREATE_DB_ON_PATH=YES

不过很遗憾,我还是得到了个报错,为什么呢?其实你使用这个命令来查看就知道了:

复制代码 代码如下:

C:/Program Files/IBM/SQLLIB/BIN>db2set -all
[e] DB2PATH=C:/Program Files/IBM/SQLLIB
[i] DB2PROCESSORS=0,1,2,3
[i] DB2INSTPROF=C:/Documents and Settings/All Users/Application Data/IBM/DB2/testdb2
[i] DB2COMM=TCPIP
[g] DB2_EXTSECURITY=YES
[g] DB2SYSTEM=SENDS-TV
[g] DB2PATH=C:/Program Files/IBM/SQLLIB
[g] DB2INSTDEF=DB2
[g] DB2ADMINSERVER=DB2DAS00

C:/Program Files/IBM/SQLLIB/BIN>db2set -?
-all     显示出现的所有本地环境变量,如以下各项中所定义:
         *  环境,用 [e] 表示
         *  用户级注册表,用 [u] 表示
         *  节点级注册表,用 [n] 表示
         *  实例级注册表,用 [i] 表示,和
         *  全局级注册表,用 [g] 表示

看到了吧,那个所谓的DB2_CREATE_DB_ON_PATH变量知识个实例级注册表,所以你直接执行上面那个命令改的是db2这个默认实例的东西。为了对我们新建的实例INSTNAME起作用,我们必须用这个命令:

复制代码 代码如下:

db2set -i INSTNAME DB2_CREATE_DB_ON_PATH=YES

注:此外,你可以通过DB2自带的那个配置助手来进行这些配置,GUI下的操作简单,就不写了。


好的,到此为止,数据库也已经成功的建立了,接下来就是日常事务了。

现在我们来看看DB2的客户端

  IBM喜欢把它译作客户机。用习惯了MySQL的同学肯定会觉得有些突兀吧。DB2的客户端也有很多个不同的版本,此外,除了IBM自己的客户端之外,也有第三方开发商弄的客户端,这篇入门文章,我们还是只探讨IBM自己的东西。



下面是IBM自己的说法:

IBM Data Server Client

IBM Data Server Client 是可用于 IBM 数据服务器的完整安装的客户机。在 DB2 9.5 中,它充分支持所有受支持的 API。例如,它为 Ruby 提供了驱动程序。在 DB2 9 中,需要通过后安装(post-installation)下载和配置步骤来添加 Ruby 支持。这个客户机还提供了完整的图形化工具。例如,如果安装一个 IBM Data Server Client,您可以获得 Configuration Assistant、IBM Add-ins for Visual Studio、语言支持,等等。

如果您计划使用这个客户机在一个后端 IDS 数据服务器中支持 OLE DB 应用程序,则需注意这个接口不支持这种使用。但是可以使用这个客户机提供的 ODBC 支持弥补这类场景中的缺陷。

简单来讲,如果某个选项可以用于一个 DB2 客户机,那么它就是可用的。DB2 Client 是与 DB2 连通性有关的所有内容的超集。如上图所示,如果需要任何工具支持,则必须安装这种客户机。

IBM Data Server Client 约为 330 MB。您可以使用前面提到的 db2iprune 实用程序自定义这个客户机把它缩减到大约 200 MB。

IBM Data Server Runtime Client

IBM Data Server Runtime Client 是轻量级客户机部署的最佳选择。它要比它的 DB2 9 伙伴小一些,并且现在和 IBM Data Server Client 一样提供了 IDS 支持。这个客户机没带有任何工具 — 如前所述,它是由 DB2 8 里前身改变而来(从 DB2 8.2 Run-Time 客户机中删除了 CCA。它不再是 DB2 9 Runtime Client 的一部分)。如果您希望使用 Configuration Assistant 来图形化配置 DB2 9.5 中的连接,则无法在此找到这个工具。然而,这个客户机却包含了 DB2 CLP。这个客户机包含了所有 DB2 接口,例如,Ruby 驱动程序、.NET 驱动程序等等。和 IBM Data Server Client 一样,这个客户机并不支持与IDS数据服务器建立OLE DB连接。IBM Data Server Runtime 客户机在安装后大约占 60-70 MB 的磁盘空间。

如果您的内存需求非常紧迫,则不适合使用这种占用空间较大的客户机,但是它提供了针对任何应用程序连通性场景的充分支持。如果您支持使用各种编程语言构建的应用程序,并且不需要任何工具,那么这种客户机是最佳选择。如果支持像 Ruby on Rails 这样的开源应用程序并且不需要工具,该客户机则是惟一的选择,因为驱动程序不会为 Ruby、PHP 这样的开源 API 包含预编译的二进制文件。

IBM Data Server Driver for JDBC and SQLJ

这个驱动程序与 DB2 9 中的驱动程序非常相似,但是进行了一些技术增强和修复(在 pureQuery 环境中也会用到这个驱动程序)。和所有 IBM 数据服务器连通性选项一样,这个驱动程序也支持 IDS 数据服务器。它通过 db2jcc.jar 的单一包的方式交付(如果需要将它连接到 DB2 for i5/OS 或 DB2 for z/OS 数据服务器,则需要一个有效的 DB2 Connect 许可),并且按照 JDBC 3.0 规范进行交付。DB2 9.5 还通过一个称为 db2jcc4.jar 的包支持 JDBC 4.0 规范。

如果您需要对基于 Java 的应用程序使用一个轻量级的、免版权费的可重新发布的驱动程序,并且不需要任何工具,那么这是最佳选择,因为它支持诸如连接集中(connection concentration)、客户机自动重路由等高级特性。由于只占用大约 2MB 的空间,我将驱动程序使用的空间称为一个指纹(fingerprint)。这个驱动程序的使用有多么普遍呢?每分钟有数十亿美元的资金依靠它运作(或者其早先的版本)。

IBM Data Server Driver for ODBC, CLI, and .NET(只针对 Windows)

这个驱动程序按照 DB2 9 的方式交付,除了新添加的 .NET 支持外,还包括针对 ODBC 和 CLI 接口的支持。这是一个非常适合 .NET 应用程序的部署选项,因为您不再需要仅仅为了向 .NET 应用程序提供连通性而使用大量的内存。此外,添加了针对 Ruby、Perl 和 PHP 这类接口的二进制版本,因此无需亲自编译(尽管驱动程序的名称中没有提到),这大大降低了这些应用程序的部署时间(以及部署工作)。

IBM Data Server Driver for ODBC, CLI, and .NET 还提供了一些非常不错的 Windows 增强。例如,附带了一个安装包装器,可以显著增强在 Windows 上的部署特性。

这个驱动程序还提供了一组合并模块,比如 DB2 Runtime Client。我推荐使用这些合并模块进行安装,因为不论是谁开发您的应用程序的安装范例,它都非常适合。如果您不需要 CLP 或其他任何工具,我推荐使用这个驱动程序,因为它不会产生任何实例管理负担。

现在,您应该非常清楚何时适合使用这个驱动程序。然而,需要注意一点,这个驱动程序并不包含对 OLE DB 的支持。我想我需要特别指出这点,应该通常情况下 ODBC 和 OLE DB 支持是互相关联的。如果需要支持一个 OLE DB 应用程序,则至少要安装一个 DB2 Run-Time Client。

注意 :尽管名称有些不符,从 IDS 的角度来看,这个驱动程序只交付面向 .NET、PHP、Perl 和 Ruby 编程接口的支持(它建议客户机继续使用 Informix SDK for C/C++ 应用程序)。这个驱动程序附带了一个免版权费的发布许可。

DB2 9.5 的新的 .NET 部署选项远远超越了为应用程序提供运行时环境这一功能。如果您希望部署最轻量级的 .NET 开发环境,您可以下载独立的 IBM Add-ins for Visual Studio(大约 30 MB)和这个驱动程序(大约 10 MB),您将获得一个专门为 .NET 集成了 IBM 数据服务器开发环境的 Visual Studio。记住,如果使用这个方法,IBM Add-ins for Visual Studio 和 IBM Data Server Driver for ODBC, CLI, and .NET必须位于相同的代码级别。例如,如果您计划支持 Visual Studio 2008 IDE,则必须在 Fix Pack 1 级别安装这些组件。如果 Fix Pack 2 对任一个这些组件进行了功能性修改,那么必须确保所有这些组件都处于 Fix Pack 2 级别。


IBM Data Server Driver for ODBC and CLI


这个驱动程序实际上提供了与 IBM Data Server Driver for ODBC, CLI, and .NET 相同的功能、特性和优点,惟一的不同是它绝对不支持 .NET 或提供以 Windows 为中心的部署增强。如果需要支持前面小节中描述的相同场景,那么可以使用这个驱动程序,但是注意不能将它用于 .NET 应用程序。这个驱动程序可从 DB2 9 获得,它还附带了免版权费用的发布许可。


IBM Data Server Add-ins for Visual Studio


IBM Data server Add-ins for Visual Studio 在过去只是为了获得一般可用性而作为基于 Windows 的 DB2 Client 或服务器映像附带(换言之,我在这里不会介绍技术内容)。在 DB2 9 中,这个插件以前被称为 IBM Database Add-ins for Visual Studio 2005。在 DB2 9.5 中,它被重命名以反映可用于 Visual Studio 2005 或 Visual Studio 2008 的插件,因此从插件名称中去掉了版本信息。
在 DB2 9.5 中,虽然 DB2 Client 和服务器映像仍然附带了这个插件,但是现在它可以作为独立下载的映像使用,大概有 30 MB 的大小。

  不管IBM自己怎么说,当务之急还是下载客户端要紧,DB2的客户端可以从这里去寻找:http://www-01.ibm.com/software/data/db2/ad/

为了让客户机可以连接服务器,还需要设置一下实例的通信设置。这里选中实例以后在控制中心里把对应的实例的通信设置里面设定成tcp/ip,并且设定好你要的端口即可。此外还需要设置DBM配置里面的通信部分的SVCENAME这个变量可以在控制中心设置,如果要用命令的话似乎是这样的:

复制代码 代码如下:

UPDATE DBM CFG USING SVCENAME 50001 DEFERRED;

上面都配置好了以后就可以用客户端连接了:

 我这里是用的runtime client,所以这里需要使用命令行(选择命令行工具输入db2进入交互界面):

复制代码 代码如下:

db2 => catalog tcpip node MYDB2 remote 192.168.0.11 server 50000
//catalog tcpip node命令表示以tcpip连接方式建立节点
//MYDB2是节点名,可以随便指定 remote制定远程服务器的
//hostname或者ip,server制定服务名称或者端口号
 DB20000I  The CATALOG TCPIP NODE command  completed successfully.
 DB21056W  Directory changes may not be effective until the directory cache is refreshed.
db2 => catalog db MYTEST as MYTESTALIAS at node MYDB2
//在你的节点下编目一个数据库,注意这里必须要制定一个不同的别名,否则会出现找不到服务器的链接错误。
 DB20000I  The CATALOG DATABASE command completed successfully.
 DB21056W  Directory changes may not be effective until the directory cache is refreshed.
db2 => connect to MYTESTALIAS user USERNAME using PASSWORD

   Database Connection Information

 Database server        = DB2/NT 9.7.0
 SQL authorization ID   = USERNAME
 Local database alias   = MYTESTALIAS

至于为什么要这么做,实际上,是因为这个客户端也自己维护了一个编录,你需要先新建一个本地的node来保存一台数据库服务器的信息,之后再添加一个对应的数据库目录才可以连接。

关于这一部分内容,可以参考这段引用:

在DB2中从客户端访问服务器端的数据库时,不能直接用connect命令,而必须先建立通信node,再在node的基础上建立数据库连接。在命令行的具体操作如下:

->db2 catalog tcpip node ABC remote serverName server 50000
->db2 catalog db databaseName at node ABC
->db2 connect to databaseName user Uid using Pwd

说明:

catalog tcpip node ABC 中的ABC是由你任意起的一个结点名,结点名不能跟已有的结点名重复
catalog db databaseName at node ABC 中的ABC指的是你在前面起的那个结点名
serverName 服务器名称(远程数据库)
databaseName 数据库名称
Uid 用户名
Pwd 密码
另外,如果客户端已经跟同一个服务器建立了node,那么如果你想连接该服务器上的另一个数据库时,不需要再另建node,直接用同一个node即可。另外,建立node时服务器名称后的端口不一定是50000,要看DB工程师当时的设置。
相关指令:
list db directory 列出可访问的db
list node directory 列出可访问的结点
其他一些重要的DB2命令


  1. 查看本地节点目录
  命令窗口中输入:db2 list node directory

  2. 编目一个TCP/IP节点
  命令窗口:db2 catalog tcpip node <node_name> remote <hostname|ip_address> server <svcname|port_number> ostype <OS2|AIX|WIN95|NT|HPUX|SUN|MVS|OS400|VM|VSE|SCO|SGI|LINUX|DYNIX>

  3. 取消节点编目
  db2 uncatalog node <node_name>

  4. 查看系统数据库目录
  db2 list database directory

  5. 查看本地数据库目录
  db2 list database directory on <盘符>
  在本地数据库目录中有而系统数据库目录中没有的数据库不能访问,可以在控制中心中选中<数据库>右键单击选择添加,然后输入需要添加的数据库名称或者点击刷新按钮选择数据库,加入数据库后即可以访问。

  6. 编目数据库
  db2 catalog database <db_name> as <db_alias> at node <node_name>

  7. 取消数据库编目
  db2 uncatalog database <db_name>

  8. 测试远程数据库的连接
  db2 connect to <db_alias> user <user_id> using <password>

 

接下来,一个显然的问题就是用户认证及其权限

  和MySQL Orancle不同,DB2对于用户的认证是直接整合操作系统的用户认证的,因此,db2的用户就是操作系统的用户。在成功的通过了用户验证以后,就开始验证用户权限了。

  至于用户权限的设置,可以直接使用控制中心对某个表、数据库甚至实例进行配置。表权限就是select等等,这些大家都清楚,而数据库权限要说明一下:

 

数据库权限
每个数据库权限都允许拥有该权限的授权标识对整个数据库执行某种特定类型的操作。数据库权限与特权不同,后者允许对特定数据库对象(例如表或索引)执行特定操作。

这些是数据库权限。

ACCESSCTRL
允许拥有者授予和撤销所有对象特权和数据库权限(对审计例程的特权除外)以及 ACCESSCTRL、DATAACCESS、DBADM 和 SECADM 权限。
BINDADD
允许拥有者在数据库中创建新包。
CONNECT
允许拥有者连接到数据库。
CREATETAB
允许拥有者在数据库中创建新表。
CREATE_EXTERNAL_ROUTINE
允许拥有者创建过程以供数据库的应用程序和其他用户使用。
CREATE_NOT_FENCED_ROUTINE
允许拥有者创建未受防护的用户定义的函数(UDF)或过程。将把 CREATE_EXTERNAL_ROUTINE 自动授予任何已被授予 CREATE_NOT_FENCED_ROUTINE 权限的用户。
注意: 数据库管理器不会阻止未受防护的 UDF 或过程访问它的存储器或控制块。因此,具有此权限的用户必须非常仔细地测试他们的 UDF,以使之特别严密,然后再将其注册为未受防护的 UDF。
DATAACCESS
允许拥有者访问存储在数据库表中的数据。
DBADM
允许拥有者充当数据库管理员。特别是,它授予拥有者除 ACCESSCTRL、DATAACCESS 和 SECADM 之外的所有其他数据库权限。
EXPLAIN
允许拥有者说明查询方案,而不要求他们拥有访问这些查询方案所引用的表中数据的特权。
IMPLICIT_SCHEMA
允许任何用户隐式地创建模式(使用 CREATE 语句创建对象,并指定尚不存在的模式名)。SYSIBM 成为隐式创建的模式的所有者,并且授予 PUBLIC 在此模式中创建对象的特权。
LOAD
允许拥有者将数据装入到表中。
QUIESCE_CONNECT
允许拥有者在数据库处于停顿状态时访问该数据库。
SECADM
允许拥有者充当数据库的安全管理员。
SQLADM
允许拥有者监视和调整 SQL 语句。
WLMADM
允许拥有者充当工作负载管理员。特别是,WLMADM 权限的拥有者可以创建和删除工作负载管理器对象、授予和撤销工作负载管理器特权以及执行工作负载管理器例程。
只有具有 SECADM 权限的授权标识才能授予 ACCESSCTRL、DATAACCESS、DBADM 和 SECADM 权限。所有其他权限都可以由具有 ACCESSCTRL 或 SECADM 权限的授权标识授予。

要从 PUBLIC 除去任何数据库权限,具有 ACCESSCTRL 或 SECADM 权限的授权标识必须显式地撤销该权限。
 

关于权限这一部分是一个大话题,有机会以后再写,这一部分的内容完全可以参考这里的文档来配置:

http://pic.dhe.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.admin.sec.doc/doc/c0005524.html

您可能感兴趣的文章:
  • DB2 常用命令小结
  • DB2比较常用与实用sql语句总结
  • db2 导入导出单个表的操作详解
  • DB2 日期和时间的函数应用说明
  • DB2 数据库创建、表的ixf文件导出导入示例
  • DB2 常用命令速查(备忘)
  • DB2 自动递增字段实现方法
  • DB2 SELECT语句高级用法
  • DB2如何查看当前用户模式及切换用户
  • CentOS下DB2数据库安装过程详解
  • 比较SQL Server与Oracle、DB2
  • DB2数据库的备份和恢复
  • Python连接DB2数据库

Docker 客户端连接 Docker Daemon 的方式

Docker 客户端连接 Docker Daemon 的方式

Docker 为 C/S 架构,服务端为 docker daemon,客户端为 docker.service,支持本地 unix socket 域套接字通信远程 socket 通信

默认为本地 unix socket 通信,要支持远程客户端访问需要做如下设置(不安全,仅用于测试),

1、UNIX 域套接字

默认就是这种方式,会生成一个 /var/run/docker.sock 文件,UNIX 域套接字用于本地进程之间的通讯,这种方式相比于网络套接字效率更高,但局限性就是只能被本地的客户端访问。

 2、TCP 端口监听

服务端开启端口监听 dockerd  -H | --host  IP:PORT , 客户端通过指定 IP 和端口访问服务端 docker -H IP:PORT

通过这种方式,任何人只要知道暴露的 ip 和端口就能随意访问 docker 服务 (因为 docker 的权限很高,一旦被突破就能够取得服务端宿主机的最高权限),因此这种方式一定要使用 TLS 加密通信

 3、启动 docker 守护进程时可以同时监听多个 socket

 

 Docker 客户端要和 Docker daemon 通过 REST API 通信,那就让我们看看它们可以采用的方法有哪些:

  1. Unix socket (-H unix:///var/run/docker.sock)
  2. Systemd socket activation (-H fd://)
  3. Tcp (-H tcp://127.0.0.1:2376)

1 和 2 可理解成一种方式,就是同一台主机上的进程间通信。

dockerd  -H unix:///var/run/docker.sock  -H tcp://127.0.0.1:2376  -H tcp://127.0.0.1:2377

-H fd:// 方式不能与 - H tcp:// 方式同时使用,若同时使用仅前者生效

若要 socket 和 tcp 方式同时使用,则使用 unix:/// 和 tcp://

 

HTTP 客户端连接,选择 HttpClient 还是 OkHttp?

HTTP 客户端连接,选择 HttpClient 还是 OkHttp?

https://juejin.im/post/6844904040644476941

写在前面

为什么会写这篇文章,起因于和朋友的聊天

img

这又触及到我的知识盲区了,首先来一波面向百度学习,直接根据关键字 httpclient 和 okhttp 的区别、性能比较进行搜索,没有找到想要的答案,于是就去 overstackflow 上看看是不是有人问过这个问题,果然不会让你失望的

img

所以从使用、性能、超时配置方面进行比较

使用

HttpClient 和 OkHttp 一般用于调用其它服务,一般服务暴露出来的接口都为 http,http 常用请求类型就为 GET、PUT、POST 和 DELETE,因此主要介绍这些请求类型的调用

HttpClient 使用介绍

使用 HttpClient 发送请求主要分为一下几步骤:

  • 创建 CloseableHttpClient 对象或 CloseableHttpAsyncClient 对象,前者同步,后者为异步
  • 创建 Http 请求对象
  • 调用 execute 方法执行请求,如果是异步请求在执行之前需调用 start 方法

创建连接:

CloseableHttpClient&nbsp;httpClient&nbsp;=&nbsp;HttpClientBuilder.create().build();

该连接为同步连接

GET 请求:

@Test
public&nbsp;void&nbsp;testGet()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;HttpGet&nbsp;httpGet&nbsp;=&nbsp;new&nbsp;HttpGet(url);
&nbsp;&nbsp;&nbsp;&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpGet);
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

使用 HttpGet 表示该连接为 GET 请求,HttpClient 调用 execute 方法发送 GET 请求

PUT 请求:

@Test
public&nbsp;void&nbsp;testPut()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/user";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;HttpPut&nbsp;httpPut&nbsp;=&nbsp;new&nbsp;HttpPut(url);
&nbsp;&nbsp;&nbsp;&nbsp;UserVO&nbsp;userVO&nbsp;=&nbsp;UserVO.builder().name("h2t").id(16L).build();
&nbsp;&nbsp;&nbsp;&nbsp;httpPut.setHeader("Content-Type",&nbsp;"application/json;charset=utf8");
&nbsp;&nbsp;&nbsp;&nbsp;httpPut.setEntity(new&nbsp;StringEntity(JSONObject.toJSONString(userVO),&nbsp;"UTF-8"));
&nbsp;&nbsp;&nbsp;&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpPut);
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

POST 请求:

  • 添加对象
@Test
public&nbsp;void&nbsp;testPost()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/user";
&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;HttpPost&nbsp;httpPost&nbsp;=&nbsp;new&nbsp;HttpPost(url);
&nbsp;UserVO&nbsp;userVO&nbsp;=&nbsp;UserVO.builder().name("h2t2").build();
&nbsp;httpPost.setHeader("Content-Type",&nbsp;"application/json;charset=utf8");
&nbsp;httpPost.setEntity(new&nbsp;StringEntity(JSONObject.toJSONString(userVO),&nbsp;"UTF-8"));
&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpPost);
&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

该请求是一个创建对象的请求,需要传入一个 json 字符串

  • 上传文件
@Test
public&nbsp;void&nbsp;testUpload1()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;HttpPost&nbsp;httpPost&nbsp;=&nbsp;new&nbsp;HttpPost(url);
&nbsp;File&nbsp;file&nbsp;=&nbsp;new&nbsp;File("C:/Users/hetiantian/Desktop/学习/docker\_practice.pdf");
&nbsp;FileBody&nbsp;fileBody&nbsp;=&nbsp;new&nbsp;FileBody(file);
&nbsp;MultipartEntityBuilder&nbsp;builder&nbsp;=&nbsp;MultipartEntityBuilder.create();
&nbsp;builder.setMode(HttpMultipartMode.BROWSER\_COMPATIBLE);
&nbsp;builder.addPart("file",&nbsp;fileBody);&nbsp;&nbsp;//addPart上传文件
&nbsp;HttpEntity&nbsp;entity&nbsp;=&nbsp;builder.build();
&nbsp;httpPost.setEntity(entity);
&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpPost);
&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

通过 addPart 上传文件

DELETE 请求:

@Test
public&nbsp;void&nbsp;testDelete()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/user/12";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;HttpDelete&nbsp;httpDelete&nbsp;=&nbsp;new&nbsp;HttpDelete(url);
&nbsp;&nbsp;&nbsp;&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpDelete);
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

请求的取消:

@Test
public&nbsp;void&nbsp;testCancel()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;HttpGet&nbsp;httpGet&nbsp;=&nbsp;new&nbsp;HttpGet(url);
&nbsp;&nbsp;&nbsp;&nbsp;httpGet.setConfig(requestConfig);&nbsp;&nbsp;//设置超时时间
&nbsp;&nbsp;&nbsp;&nbsp;//测试连接的取消
&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;begin&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;CloseableHttpResponse&nbsp;response&nbsp;=&nbsp;httpClient.execute(httpGet);
&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(true)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(System.currentTimeMillis()&nbsp;-&nbsp;begin&nbsp;&gt;&nbsp;1000)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;httpGet.abort();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("task&nbsp;canceled");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(EntityUtils.toString(response.getEntity()));
}

调用 abort 方法取消请求 执行结果:

task&nbsp;canceled
cost&nbsp;8098&nbsp;msc
Disconnected&nbsp;from&nbsp;the&nbsp;target&nbsp;VM,&nbsp;address:&nbsp;''127.0.0.1:60549'',&nbsp;transport:&nbsp;''socket''
java.net.SocketException:&nbsp;socket&nbsp;closed...【省略】

OkHttp 使用

使用 OkHttp 发送请求主要分为一下几步骤:

  • 创建 OkHttpClient 对象
  • 创建 Request 对象
  • 将 Request 对象封装为 Call
  • 通过 Call 来执行同步或异步请求,调用 execute 方法同步执行,调用 enqueue 方法异步执行

创建连接:

private&nbsp;OkHttpClient&nbsp;client&nbsp;=&nbsp;new&nbsp;OkHttpClient();

GET 请求:

@Test
public&nbsp;void&nbsp;testGet()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.get()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();
&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;&nbsp;&nbsp;&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(response.body().string());
}

PUT 请求:

@Test
public&nbsp;void&nbsp;testPut()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/user";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;//请求参数
&nbsp;&nbsp;&nbsp;&nbsp;UserVO&nbsp;userVO&nbsp;=&nbsp;UserVO.builder().name("h2t").id(11L).build();
&nbsp;&nbsp;&nbsp;&nbsp;RequestBody&nbsp;requestBody&nbsp;=&nbsp;RequestBody.create(MediaType.parse("application/json;&nbsp;charset=utf-8"),
&nbsp;&nbsp;&nbsp;&nbsp;JSONObject.toJSONString(userVO));
&nbsp;&nbsp;&nbsp;&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.put(requestBody)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();
&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;&nbsp;&nbsp;&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(response.body().string());
}

POST 请求:

  • 添加对象
@Test
public&nbsp;void&nbsp;testPost()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/user";
&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;//请求参数
&nbsp;JSONObject&nbsp;json&nbsp;=&nbsp;new&nbsp;JSONObject();
&nbsp;json.put("name",&nbsp;"hetiantian");
&nbsp;RequestBody&nbsp;requestBody&nbsp;=&nbsp;RequestBody.create(MediaType.parse("application/json;&nbsp;charset=utf-8"),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String.valueOf(json));
&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;.post(requestBody)&nbsp;//post请求
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();
&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;System.out.println(response.body().string());
}
  • 上传文件
@Test
public&nbsp;void&nbsp;testUpload()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;RequestBody&nbsp;requestBody&nbsp;=&nbsp;new&nbsp;MultipartBody.Builder()
&nbsp;&nbsp;&nbsp;.setType(MultipartBody.FORM)
&nbsp;&nbsp;&nbsp;.addFormDataPart("file",&nbsp;"docker\_practice.pdf",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RequestBody.create(MediaType.parse("multipart/form-data"),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;File("C:/Users/hetiantian/Desktop/学习/docker\_practice.pdf")))
&nbsp;&nbsp;&nbsp;.build();
&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;.post(requestBody)&nbsp;&nbsp;//默认为GET请求,可以不写
&nbsp;&nbsp;&nbsp;.build();
&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;System.out.println(response.body().string());
}

通过 addFormDataPart 方法模拟表单方式上传文件

DELETE 请求:

@Test
public&nbsp;void&nbsp;testDelete()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;//请求参数
&nbsp;&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.delete()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();
&nbsp;&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;&nbsp;System.out.println(response.body().string());
}

请求的取消:

@Test
public&nbsp;void&nbsp;testCancelSysnc()&nbsp;throws&nbsp;IOException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
&nbsp;&nbsp;&nbsp;&nbsp;Request&nbsp;request&nbsp;=&nbsp;new&nbsp;Request.Builder()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.url(url)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.get()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();
&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Call&nbsp;call&nbsp;=&nbsp;client.newCall(request);
&nbsp;&nbsp;&nbsp;&nbsp;Response&nbsp;response&nbsp;=&nbsp;call.execute();
&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;start&nbsp;=&nbsp;System.currentTimeMillis();
&nbsp;&nbsp;&nbsp;&nbsp;//测试连接的取消
&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(true)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//1分钟获取不到结果就取消请求
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(System.currentTimeMillis()&nbsp;-&nbsp;start&nbsp;&gt;&nbsp;1000)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;call.cancel();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("task&nbsp;canceled");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(response.body().string());
}

调用 cancel 方法进行取消 测试结果:

task&nbsp;canceled
cost&nbsp;9110&nbsp;msc
java.net.SocketException:&nbsp;socket&nbsp;closed...【省略】

小结

  • OkHttp 使用 build 模式创建对象来的更简洁一些,并且使用. post/.delete/.put/.get 方法表示请求类型,不需要像 HttpClient 创建 HttpGet、HttpPost 等这些方法来创建请求类型
  • 依赖包上,如果 HttpClient 需要发送异步请求、实现文件上传,需要额外的引入异步请求依赖
&nbsp;<!--文件上传-->
&nbsp;<dependency>
&nbsp;&nbsp;<groupid>org.apache.httpcomponents</groupid>
&nbsp;&nbsp;<artifactid>httpmime</artifactid>
&nbsp;&nbsp;<version>4.5.3</version>
&nbsp;</dependency>
&nbsp;<!--异步请求-->
&nbsp;<dependency>
&nbsp;&nbsp;<groupid>org.apache.httpcomponents</groupid>
&nbsp;&nbsp;<artifactid>httpasyncclient</artifactid>
&nbsp;&nbsp;<version>4.5.3</version>
&nbsp;</dependency>
  • 请求的取消,HttpClient 使用 abort 方法,OkHttp 使用 cancel 方法,都挺简单的,如果使用的是异步 client,则在抛出异常时调用取消请求的方法即可

超时设置

**HttpClient 超时设置:** 在 HttpClient4.3 + 版本以上,超时设置通过 RequestConfig 进行设置

private&nbsp;CloseableHttpClient&nbsp;httpClient&nbsp;=&nbsp;HttpClientBuilder.create().build();
private&nbsp;RequestConfig&nbsp;requestConfig&nbsp;=&nbsp;&nbsp;RequestConfig.custom()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.setSocketTimeout(60&nbsp;\/*&nbsp;1000)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.setConnectTimeout(60&nbsp;\/*&nbsp;1000).build();
String&nbsp;api&nbsp;=&nbsp;"/api/files/1";
String&nbsp;url&nbsp;=&nbsp;String.format("%s%s",&nbsp;BASE\_URL,&nbsp;api);
HttpGet&nbsp;httpGet&nbsp;=&nbsp;new&nbsp;HttpGet(url);
httpGet.setConfig(requestConfig);&nbsp;&nbsp;//设置超时时间

超时时间是设置在请求类型 HttpGet 上,而不是 HttpClient 上

**OkHttp 超时设置:** 直接在 OkHttp 上进行设置

private&nbsp;OkHttpClient&nbsp;client&nbsp;=&nbsp;new&nbsp;OkHttpClient.Builder()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.connectTimeout(60,&nbsp;TimeUnit.SECONDS)//设置连接超时时间
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.readTimeout(60,&nbsp;TimeUnit.SECONDS)//设置读取超时时间
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();

** 小结:** 如果 client 是单例模式,HttpClient 在设置超时方面来的更灵活,针对不同请求类型设置不同的超时时间,OkHttp 一旦设置了超时时间,所有请求类型的超时时间也就确定

HttpClient 和 OkHttp 性能比较

测试环境:

  • CPU 六核
  • 内存 8G
  • windows10

每种测试用例都测试五次,排除偶然性

client 连接为单例:

img

client 连接不为单例:

img

单例模式下,HttpClient 的响应速度要更快一些,单位为毫秒,性能差异相差不大 非单例模式下,OkHttp 的性能更好,HttpClient 创建连接比较耗时,因为多数情况下这些资源都会写成单例模式,因此图一的测试结果更具有参考价值

总结

OkHttp 和 HttpClient 在性能和使用上不分伯仲,根据实际业务选择即可 最后附:示例代码:https://github.com/TiantianUpup/http-call,欢迎 forkstar/* 好久没有对外输出文章了

img

主要是写的前两篇没有人看,受打击了,急需网友的肯定【点赞呀

END

推荐阅读

太赞了,这个 Java 网站,什么项目都有!https://markerhub.com

这个 B 站的 UP 主,讲的 java 真不错!

太赞了!最新版 Java 编程思想可以在线看了!

关于python websocket 客户端连接python websocket-client的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于ASP.NET MVC 客户端连接 ids4 SSo [授权] 302 重定向总是、DB2新手使用的一些小笔记:新建实例、数据库路径不存在、客户端连接 .、Docker 客户端连接 Docker Daemon 的方式、HTTP 客户端连接,选择 HttpClient 还是 OkHttp?的相关知识,请在本站寻找。

本文标签: