Java-01 JAVA网络编程

一 、网络编程底层原理

后端服务用到网络请求非常常见,如何在技术不断升级的过程中,规范化管理网络请求、保持高性能调用是个持久话题
知其然,仍需知其所以然。先搞明白底层原理,了解最基础的网编过程。

1 网络编程三要素

A:IP地址 — 都懂,网络世界的唯一标识。
B:端口号 — 应用程序中某个进程所占用的逻辑端口。
C:传输层协议 — UDP协议与TCP协议
做web类经常会听到各种协议,UDP、TCP、IP、HTTP等各种协议很头疼,这里提供一张图,帮你看懂这些协议。
右图是7层模型,又称OSI(Open System Interconnection,开放式系统互联)7层模型。
http、https均在应用层。UDP、TCP处在传输层、IP协议处在网络层,配合左图适当发挥想象空间理解其含义吧。
在这里插入图片描述

2 传输层UDP协议与TCP协议区别

UDP (User Datagram Protocol) :用户数据包协议。
TCP (Transmission Control Protocol):传输控制协议。
传输层协议是通信的规则,UDP与TCP是2种不同的传输层协议,各自根据其自身特性均有代表性的应用场景。
UDP协议,将数据源和目的地封装成数据包,不需要建立连接;每个数据包的大小限制在64K;因为不建立连接,是不可靠协议;但传输速度快。
TCP协议,建立连接,形成数据传输的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,传输效率稍差。

UDP:                   TCP:
    把数据打包             建立连接通道
    数据有限制(64K)       数据无限制
    不建立连接             三次握手建立连接
    速度快                 速度慢
    不可靠(易丢包)        可靠

实际应用中,更倾向于将2中协议混合使用,将不注重可靠性的广播类数据通过UDP协议传输,而对于需要文件稳定上传、下载的场景通过TCP协议传输。

3 UDP协议代码实例

UDP协议使用底层java.net.DatagramPacket;java.net.DatagramSocket;进行数据报封装、套接字对象请求发送和接收。
消息发送:

/**
 *
 * 发送UDP数据
 * @author Administrator
 * DatagramSocket 表示用来发送和接收数据报包的套接字。
 *
 * 1 创建对象
 * 2 构造数据报包
 * 3 发送请求
 * 4 释放连接
 */
public class UdpSendDemo {
    public static void main(String[] args) throws IOException {

        //创建客户端socket对象
        DatagramSocket ds = new DatagramSocket();

        //构造数据报包 包含文件内容 长度 端口号 协议
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
        byte[] bys ="hello socket".getBytes();

        //定义发送目标的地址、端口号
        DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"),8448);

        //发送socket请求
        ds.send(dp);

        //释放连接
        ds.close();
    }
}

消息接收:

/**
 * 接受UDP数据
 * @author Administrator
 *
 * 1 创建接收Socket对象
 * 2 创建数据报(接收)
 * 3 调用sockrt接收方法,接受对象
 * 4 解析socket套接字包
 * 5 释放资源
 */
public class UdpReceiveDemo {
    public static void main(String[] args) throws IOException {

        DatagramSocket ds = new DatagramSocket(8448);

        //DatagramPacket(byte[] buf, int length)
        //构造 DatagramPacket,用来接收长度为 length 的数据包。
        byte[] bys =new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, bys.length);

        ds.receive(dp);

        //解析数据中的端口号及ip信息
        InetAddress inetAddress = dp.getAddress();

        //解析数据包
        //创建获取数据的缓冲区
        byte[] bys2 = dp.getData();

        String s = new String(bys2,0, bys2.length);

        System.out.println("来者地址:"+ inetAddress.getHostAddress() + "来者说:" + s);

        ds.close();
    }
}

4 TCP协议代码实例

在这里插入图片描述
原理分析:服务端监听端口,客服端发送Socket套接字连接,建立连接后即建立字节流通道,客服端写字节、服务端读字节、响应给客服端字节流再读,完成交互。
服务端监听:

/**
 * TCP协议:接收数据
 * A:创建接收端的socket对象
 * B:监听客户端 端口,返回一个对应的socket对象
 * C:获取输入流
 * D:释放资源
 */
public class ServerTcpSocket {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);

        //监听客户端 返回对应的docket对象
        //阻塞式方法
        Socket s =ss.accept();
        InputStream is = s.getInputStream();

        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String str =new String(bys,0,len);

        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+":"+str);

        //获取输出流
        OutputStream os =s.getOutputStream();
        os.write("数据已经收到了".getBytes());


        //服务器不关闭 客户端对应的socket关闭 ss.close
        s.close();
    }

}

客户端:

/**
 * Tcp协议发送数据:
 * A:创建发送端的Socket对象,成功则表示建立连接
 * B:获取输出流,写数据
 * C:释放资源
 *
 * 注意:TCP协议需要先保证接收端开放  否则:Connection refused: connect
 */
public class ClientTcpSocket {
    public static void main(String[] args) throws IOException {
        //创建发送端的Socket对象
        //Socket(String host,int port)
        Socket s =new Socket("localhost",8888);
        OutputStream os  = s.getOutputStream();
        os.write("hello TCP".getBytes());

        InputStream is =s.getInputStream();
        byte[] bys = new byte[1024];
        //阻塞
        int len =is.read(bys);
        String server = new String(bys,0,len);
        System.out.println("server:" + server);

        s.close();
    }
}

二、常用组件技术选型

在 Java 生态中,虽然有数不清的 HTTP client lib 组件库,但是大体可以分为这三类:
1、JDK 自带的 HttpURLConnection 标准库;
2、 Apache HttpComponents HttpClient, 以及基于该库的 wrapper, 如 Unirest. 非基于 Apache HttpComponents HttpClient,
3.1、大量重写应用层代码的 HTTP client 组件库,典型代表是 OkHttp.
3.2、基于OkHttp发展出来的Retrofit

1.JDK自带的网络组件 HttpURLConnection

1.1 HttpURLConnection 缺点:缺乏连接池管理、请求控制等、底层基于socket、阻塞式通道流传输
在这里插入图片描述
1.2 从oracle官网上对HttpURLConnection的介绍看,该方法底层是基于socket实现的。JDK从1.1就开始使用的HttpURLConnection。包含http请求及ssl(Secure Sockets Layer 安全套接字协议)协议的https请求。
在这里插入图片描述
1.3 传输流默认大小4096字节
在这里插入图片描述
1.4 底层文件传输沿用socket的通道字节流
在这里插入图片描述
方法:
在这里插入图片描述

public static void main(String[] args) throws IOException {
        String urlString = "https://httpbin.org/post";
        String bodyString = "password=e10adc3949ba59abbe56e057f20f883e&username=test3";

        URL url = new URL(urlString);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);

        OutputStream os = conn.getOutputStream();
        os.write(bodyString.getBytes("utf-8"));
        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());
        }
    }

总结来说:JDk1.1一直沿用的HttpURLConnection方法底层依旧是socket,阻塞式交互完全无法满足现在的需求,通道内字节流传输性能也略显逊色。

2 commons-httpclient.

2.1 commons-httpclient Apache老版本的http组件(2.x版本均移植至3.1),目前已停止更新,官网介绍如下。
在这里插入图片描述
2.2 commons-httpclient3.1版本的httpclient基于jdk1.1的HttpURLConnection方法也着实有不错改进,至少在连接管理上有不少提升,因为已经停更了,这里不做过多赘述,。在这里插入图片描述
2.3 国际惯例,先导包

    <!--网络请求-->
    <dependency>
      <groupId>commons-httpclient</groupId>
      <artifactId>commons-httpclient</artifactId>
      <version>3.1</version>
    </dependency>

2.4 代码示例:

public static String sendGet(String urlParam){
        String result=null;
        try {
            // 创建httpClient实例对象
            HttpClient httpClient = new HttpClient();
            // 设置httpClient连接主机服务器超时时间:15000毫秒
            httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(15000);
            // 创建GET请求方法实例对象
            GetMethod getMethod = new GetMethod(urlParam);
            // 设置post请求超时时间
            getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 60000);
            getMethod.addRequestHeader("Content-Type", "application/json");

            httpClient.executeMethod(getMethod);
            result = getMethod.getResponseBodyAsString();
            getMethod.releaseConnection();
        }catch (Exception e){
            log.error("发送网络请求失败 {}",urlParam,e);
        }
        return result;
    }

3 Apache HttpComponents

3.1 HttpComponents继承自Commons HttpClient 3.x,是apache目前在维护的,市面上最常用的HTTP协议网络传输Java组件。
3.2 稳定的HttpComponents版本 4.1、4.5(该版本是较稳定、国内最常用的版本,本文着重讲4.5版本)、5.0
3.3 HttpCore是一组轻量级HTTP传输组件。HttpCore支持两种I / O模型:基于经典的阻塞式Java I / O模型和基于Java NIO的非阻塞事件驱动的I / O模型。阻塞模型更适合数据密集型低延迟方案,而非阻塞模型更适合于高延迟方案。在原始数据吞吐量中,原始数据吞吐量的重要性不如处理数千个同时HTTP连接的能力。资源高效的方式。

   <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>

3.4 或许说了那么多你还不知道我在说什么,干脆提人吧,CloseableHttpClient 看到它你应该或许明白了。
在这里插入图片描述

3.5 目前市场主流的java网编工具,国内主流大厂都在用,下面解读百度云、腾讯云、华为云的SDK版本中网络请求中使用httpcomponents的源码,学习别人的实际用法。

3.5.1 百度

        <!--  百度云SDK-->
        <dependency>
            <groupId>com.baidubce</groupId>
            <artifactId>bce-java-sdk</artifactId>
            <version>0.10.86</version>
        </dependency>

上面是百度云SDK的maven地址,百度云SDK用法就不聊了,直接看看1、配置 2、发送 3、接收
1、连接配置

//首先设置连接配置,代码中设置ak/sk、局点,这3个百度云业务中用到的配置,直接忽略
 BceClientConfiguration config = new BceClientConfiguration()
                .withCredentials(new DefaultBceCredentials(accessKeyId, secretAccessKy))
                .withEndpoint(endPoint);
//重点看BceClientConfiguration这个类

这里设置了连接超时时间50s、最大连接数50个、应用层网络协议等等,并且挨个提供了set方法供使用者自定义连接配置。【开发标准】
在这里插入图片描述
在这里插入图片描述

//继续看如何发送请求的 这里是官网提供的生成客户端的方法
CdnClient cdnClient = new CdnClient(config);
//cdnClient 继承了abstractBceClient方法,并且业务场景中很多方法都用到了父类中的invokeHttpClient(T,T)方法,继续追寻原委

在这里插入图片描述
可以看到实际源码中,httpclient还是使用的CloseableHttpclient方法,实际SDK中还有异步的方法 CloseableHttpAsyncClient,具体的业务用法这里就不再赘述。
在这里插入图片描述

4 okhttp

okhttp也是目前比较主流的网络请求的主要工具,后面有机会再好好解读。这里同样拿腾讯云的SDK来学习okhttp的具体使用方法。

4.1 腾讯云

  <!-- 腾讯云SDK-->
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java</artifactId>
            <!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
            <!-- 请到 https://search.maven.org/search?q=tencentcloud-sdk-java 查询最新版本 -->
            <version>3.1.87</version>
        </dependency>

同样从配置和发送请求来分析
3.1.1 实例化client对象

        // 实例化要请求产品(以 cvm 为例)的 client 对象
        CvmClient client = new CvmClient(cred, "ap-guangzhou");

在这里插入图片描述
从上图能看出来,实际的连接管理是在profile中设置的(包括连接超时时间、协议、读写超时时间等)
在这里插入图片描述
而这里的HttpConnection实际用的就是OkHttpClient
在这里插入图片描述

5 retrofit

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧梦昂志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值