IO编程

作者: Finlay_Li | 来源:发表于2019-04-07 16:54 被阅读0次

    一、网络编程基础知识

    1、什么是网络编程
    

    在网络环境上使用IO流进行数据传输

    2、Java提供了什么
    

    网络编程相关定义和实现,联网的底层细节被隐藏在 Java 的JVM。

    程序员面对的是一个统一的网络编程环境。这也被称为:IO编程

    二、如何在Java平台上完成网络通信

    1、网络通信协议:

            TCP/IP模型                    对应协议
    
            应用层                            HTTP、ftp、telnet、DNS…
    
            传输层                            TCP、UDP、…
    
            网络层                            IP、ICMP、ARP…
    
            物理+数据链路层            Link
    

    2、数据在网络中是如何传输的:

         数据封装(从上至下)  /    数据拆封(从下至上)            
    
           传输层                            Segment        
    
           网络层                            Packet
    
           数据链路层                     Frame
    
           物理层                            Bits
    

    3、核心两点

    确定通信双方的地址

          1 )如何确定?两种方式:
    
                        > IP 地址: 192.168.10.165
    
                      //唯一的标识 Internet 上的计算机
    
                        > 域名: [www.atguigu.com](http://www.atguigu.com/)
    
                      //域名服务器(DNS)负责将域名转化成IP地址,即可与主机建立连接
    
          2)java编写要使用的类
    
                  [java.net](http://java.net/).InetAddress 类  : 表示 IP 地址
    
                           ①两个子类:Inet4Address、Inet6Address。
    
                           ②InetAddress 类的一个对象就代表着一个IP地址
    
          3) 常用方法:
    
               ①InetAddress类没有提供公共的构造器,提供两个静态方法来获取InetAddress实例
    
                            >getByName(String host) : 根据域名/IP地址获取对应的 InetAddress 实例
    
               ②getHostName() : 获取IP地址对应的域名
    
               ③getHostAddress() : 获取IP地址
    
               ④getLocalHost() : 获取 本机 的 IP
    
          4)端口号:
    
              不同的程序有固定的端口号。发送和接收都需对应上。
    

    满足:网络通信协议(TCP、UDP)

            TCP协议:
    
            使用TCP协议前,须先建立TCP连接,形成传输数据通道
    
            传输前,采用“三次握手”方式,是可靠的
    
            TCP协议进行通信的两个应用进程:客户端、服务端
    
            在连接中可进行大数据量的传输
    
            传输完毕,需释放已建立的连接,效率低
    
            UDP协议:
    
            将数据、源、目的封装成数据包,不需要建立连接
    
            每个数据报的大小限制在64K内
    
            因无需连接,故是不可靠的
    
            发送数据结束时无需释放资源,速度快l
    

    4、URL (统一资源定位符)

    1、定义:代表网上某站点的某一资源
    
    2、URL的基本结构由5部分组成:
    
        <传输协议>://<主机名>:<端口号>/<文件名>
    
        例如: [http://www.atguigu.com:9999/helloworld/index.jsp](http://www.atguigu.com:9999/helloworld/index.jsp)
    
        注:<主机名>都使用域名代替了
    
    3、常用方法
    
        public String getProtocol(  )       获取该URL的协议名
    
        public String getHost(  )           获取该URL的主机名
    
        public String getPort(  )           获取该URL的端口号
    
        public String getPath(  )           获取该URL的文件路径
    
        public String getFile(  )           获取该URL的文件名
    
        public String getRef(  )            获取该URL在文件中的相对位置
    
        public String getQuery(   )         获取该URL的查询名
    
    【注意】:站点上的下载链接其实就是URL,有加密与未加密的。
    

    三、使用 TCP 协议完成网络通信

    简化场景:客户端每隔两秒发送一个带有时间戳的"hello world"给服务端,服务端收到之后打印。

    服务端(先开):ServerSocket

    步骤

        1 传入端口号,创建一个ServerSocket的对象
    
        2 阻塞接收Socket = 获取与客户端连接并返回
    
        3 获取从客户端Socket对象发送过来的输入流
    
        4 操作过程
    
        5 关闭相应的流和 Socket、ServerSocket对象
    

    package com.dodou.liwh.ws.socket;

    import java.io.IOException;

    import java.io.InputStream;

    import java.net.ServerSocket;

    import java.net.Socket;

    /**

    • @author: Lwh

    • @ClassName: IOServer

    • @Description:

    • @version: 1.0.0

    • @date: 2019-03-25 3:49 PM

    */

    public class IOServer {

    public static void main(String[] args) throws Exception {
    
        //构建服务端对象
    
        ServerSocket serverSocket = new ServerSocket(8080);
    
        new Thread(() -> {
    
            while (true) {
    
                try {
    
                    //阻塞获取客户端连接,获取到一个连接就创建一个新的线程
    
                    Socket socket = serverSocket.accept();
    
                    new Thread(() -> {
    
                        try {
    
                            InputStream inputStream = socket.getInputStream();
    
                            byte[] bytes = new byte[1024];
    
                            int len;
    
                            // 按字节流方式读取数据到bytes再转换为String输出
    
                            while ((len = inputStream.read(bytes)) != -1) {
    
                                System.out.println(new String(bytes, 0, len));
    
                            }
    
                        } catch (IOException e) {
    
                            e.printStackTrace();
    
                        }
    
                    }).start();
    
                } catch (IOException e) {
    
                    e.printStackTrace();
    
                }
    
            }
    
        }).start();
    
    }
    

    }

    客户端:Socket

              (称为“套接字”,一个 IP地址与 端口号 的组合)
    

    步骤

        1 重载构造器,传入端口号,Ip 创建一个Socket的对象
    
        2 获取输出流,写出数据
    
        3 操作过程
    
        4 关闭相应的流和 Socket
    

    package com.dodou.liwh.ws.socket;

    import java.net.Socket;

    import java.util.Date;

    /**

    • @author: Lwh

    • @ClassName: IOClient

    • @Description:

    • @version: 1.0.0

    • @date: 2019-03-25 4:15 PM

    */

    public class IOClient {

    public static void main(String[] args) {
    
        new Thread(() -> {
    
            //获取一个Socket的对象
    
            try {
    
                Socket socket = new Socket("127.0.0.1", 8000);
    
                while (true) {
    
                    try {
    
                        //获取输出流,写出数据
    
                        socket.getOutputStream().write((new Date() + ": hello world").getBytes());
    
                        socket.getOutputStream().flush();
    
                        Thread.sleep(2000);
    
                    } catch (Exception e) {
    
                    }
    
                }
    
            } catch (Exception e) {
    
            }
    
        }).start();
    
    }
    

    }

    image.png

    四、缺点

    上面的demo,从服务端代码中我们可以看到,在传统的IO模型中,每个新的客户端连接成功之后

    服务端都需要一个线程来维护这条连接,每个线程包含一个while死循环

    那么1w个连接对应1w个线程,继而1w个while死循环,这就带来如下几个问题:

    1. 线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起

    2. 线程切换效率低下:单机cpu核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。

    3. 除了以上两个问题,IO编程中,我们看到数据读写是以字节流为单位,效率不高。

    为了解决这三个问题,JDK在1.4之后提出了NIO。

    相关文章

      网友评论

          本文标题:IO编程

          本文链接:https://www.haomeiwen.com/subject/itbsiqtx.html