Java基础--网络编程(TCP、UDP)

网络编程

  1. 文件的上传下载实际就是读入写出的过程
  2. 如果是文本文件建议用字符流,如果是图片或者其他的文件,建议用字节流+处理流
IP、端口号和Socket
  1. 目的:直接或间接的通过网络协议与其他计算机实现数据交换,通讯

  2. 两个问题:

    • 如何准确的定位到网络上的一台或多台主机,或者定位到主机上特定的应用
      • IP
      • 端口号
    • 找到主机后如何可靠高效的进行数据传输
      • OSI参考模型:
      • 通讯协议
  3. 网络通信协议

    • OSI参考模型:
      • 应用层:直接面向用户的一层,用户的通信内容要由应用进程解决
      • 表示层:应用过程之间传送的信息提供表示方法的服务。
      • 会话层:负责维护两个节点之间的传输联接,确保点到点传输不中断,以及管理数据交换等功能
      • 传输层:数据传输
      • 网络层:数据在节点之间传输创建逻辑链路,通过路由选择算法为分组选择最佳路径,从而实现拥塞控制、网络互联等功能
      • 数据链路层:通信实体问建立数据链路联接,传输的基本单位为“帧”
      • 物理层:最底层,物理层传输的基本单位是比特流
    • 实际上的TCP/IP参考模型
      • 应用层:HTTP、FTP、DNS
      • 传输层:TCP、UCP
      • 网络层:IP、ICMP、ARP
      • 物理+数据链路层:Link
  4. IP地址:InetAddress类

    • Java中Inetaddress来代表一个类,一个对象就是一个IP
  5. InetAddress常用方法

    • 静态方法:
      • getByName(String str);获取IP对象
      • getLocalhost();获取本地ip
    • 非静态常用方法:
      • getHostName();获取ip对象的域名
      • getHostAddress(); 获取地址
    public static void main(String[] args) {
            try {
                InetAddress ip = InetAddress.getByName("www.baidu.com");
                System.out.println(ip);//www.baidu.com/61.135.169.121

                InetAddress ip2 = InetAddress.getByName("192.168.1.1");
                System.out.println(ip2);///192.168.1.1

                InetAddress ip3 = InetAddress.getLocalHost();
                System.out.println(ip3);//LAPTOP-IA3LU4GJ/169.254.193.252

                //获取域名
                String yuming = ip.getHostName();
                System.out.println(yuming);//www.baidu.com

                //获取ip地址
                String ipAddress = ip.getHostAddress();
                System.out.println(ipAddress);//61.135.169.125    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
  1. 端口号:
    • 标识正在计算机上运行的进程
    • 不同的进程有不同的端口号
    • tomcat默认占用8080,HTTP一般占用80,FTP一般是21,mysql3306
  2. 端口号和IP共同构成一个网络套接字:
    • Socket
通讯协议,TCP和UDP
  1. TCP:使用TCP协议前,会建立TCP连接,形成传输数据通道
    - 传输使用三次握手方式,点对点通信,可靠的
    - TCP协议进行通信的两个应用程序:客户端、服务端
    - 在连接中可进行大数据量的传输
    - 传输完毕,需要释放连接,效率低

  2. UDP:将数据、源、目的封装成数据包,不需要建立连接
    - 每个数据包大小在64k内
    - 只管发,不管其他的,接收方也不确认,不可靠传输
    - 可以广播发送
    - 无需释放资源,效率高,速度快

  3. 三次握手(TCP建立可靠连接的依据/实现)

    • 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号
    • 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
    • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手
  4. 四次挥手(连接终止协议)

    • TCP客户端发送一个FIN终止报文,用来关闭客户到服务器的数据传送。
    • 服务器收到这个FIN终止报文,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
    • 服务器关闭客户端的连接,发送一个FIN给客户端。
    • 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
实现TCP的网络编程
  1. 客户端发送信息给服务器端发送信息,服务器端将数据显示在控制台

  2. 服务器端:

    • 创建一个服务器端套接字,用于绑定端口号
    • 设置该端口为可接收状态
    • 给服务器端的套接字端输入流对象,用于读取数据
    • 循环读取数据,通过ByteArrayOutputStream类写入数据,而是写到了该类中
    • 关闭资源
  3. 客户端:

    • 创建ip地址对象找到ip
    • 创建套接字对象,写入ip地址和端口号
    • 给套接字一个输出流,用于写出数据
    • 写出数据到实体流中
    • 关闭资源
    public void Server(){
        //1. 创建服务器端端口对象
        ServerSocket ss = new ServerSocket(8899);
        //2. 设置该端口为可接收状态
        Socket socket = ss.accept();
        //3. 获取输入流 ---Returns an input stream for this socket.
        InputStream is = socket.getInputStream();
        //4. 从务器端写出数据, 他没有指定写入到哪,而是写到了该类中的一个数组中
        ByteArrayOutputStream bis = new ByteArrayOutputStream();
        byte[] bytes = new byte[10];
        int len;
        while((len = is.read(bytes)) != -1){
            bis.write(bytes,0,len);
        }
        //打印到控制台
        System.out.println(bis.toString());

        //5. 关闭资源
        bis.close();          
        is.close();    
        socket.close();
        ss.close();

      }

  1. TCP编程:客户端发送文件给服务器端,服务器端把该文件存入到本地
    /**
    * 服务器端从socket的输出流中,接收数据,读取,然后输出流存储到本地
    */
    public void Server(){
        //1. 创建端口
        ServerSocket sso = new ServerSocket(8899);
        //2. 设置端口为可接收状态
        Socket socket = sso.accept();
        //3. 创建接收流,用于接收socket信息
        InputStream is = socket.getInputStream();//接受流
        //4. 创建输出流,用于将读取的文件存入本地
        FileOutputStream fos = new FileOutputStream(new File("D:\\IdeaProjects\\JavaDemo\\sou\\图片05.jpg"));
        //接收流开始读取数据
        byte[] bytes = new byte[1024];
        int len;
        while((len = is.read(bytes)) != null){
            //输出流,写入文件内容
            fos.write(bytes,0,len);
        }
        //5. 关闭资源
        fos.close();
        is.close();
        socket.close();

    }

    /**
     * 客户端从本地读取一个文件,传输到socket中,发送给服务器端
     */
    @Test
    public void Client(){
        //1. 发送前写清ip地址和端口号
        InetAddress ip = InetAddress.getByName("127.0.0.1");
        Socket socket = new Socket(ip,8890);
        //2. 创建输出流,用于输出读取的文件
        OutputStream os = socket.getOutputStream();//输出流
        //3. 创建输入流,读取本地文件写入到输出流中
        FileInputStream fis = new FileInputStream(new File("D:\\IdeaProjects\\JavaDemo\\sou\\图片04.jpg"));
        //读入 写出
        byte[] bytes = new byte[1024];
        int len;
        while((len = fis.read(bytes)) !=null){
            //写出文件内容到socket中
            os.write(bytes,0,len);
        }
        //4. 关闭资源
        fis.close();
        os.close();
        socket.close();
    }
  1. 在2基础上添加 服务器回复“图片已上传,谢谢”这句话,客户端接收
    /**
    * 服务器端从socket的输出流中,接收数据,读取,然后输出流存储到本地
    */
    public void Server(){
        //1. 创建端口
        ServerSocket sso = new ServerSocket(8899);
        //2. 设置端口为可接收状态
        Socket socket = sso.accept();
        //3. 创建接收流,用于接收socket信息
        InputStream is = socket.getInputStream();//接受流
        //4. 创建输出流,用于将读取的文件存入本地
        FileOutputStream fos = new FileOutputStream(new File("D:\\IdeaProjects\\JavaDemo\\sou\\图片05.jpg"));
        //接收流开始读取数据
        byte[] bytes = new byte[1024];
        int len;
        while((len = is.read(bytes)) != null){
            //输出流,写入文件内容
            fos.write(bytes,0,len);
        }

        //5.服务器端接收完毕,发送一段话给客户端
        OutputStream os = socket.getOutputStream();//写出
        os.write("图片已上传,谢谢".getBytes());

        //6. 关闭资源
        os.close();
        fos.close();
        is.close();
        socket.close();

    }
    /**
     * 客户端从本地读取一个文件,传输到socket中,发送给服务器端
     */
    @Test
    public void Client(){
        //1. 发送前写清ip地址和端口号
        InetAddress ip = InetAddress.getByName("127.0.0.1");
        Socket socket = new Socket(ip,8890);
        //2. 创建输出流,用于输出读取的文件
        OutputStream os = socket.getOutputStream();//输出流
        //3. 创建输入流,读取本地文件写入到输出流中
        FileInputStream fis = new FileInputStream(new File("D:\\IdeaProjects\\JavaDemo\\sou\\图片04.jpg"));
        //读入 写出
        byte[] bytes = new byte[1024];
        int len;
        while((len = fis.read(bytes)) !=null){
            //写出文件内容到socket中
            os.write(bytes,0,len);
        }

        //4. 客户端接收服务器发送的数据,并读取
        InputStream is = socket.getInputStream();//读入
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//写出到控制台
        byte[] bytes1 = new bytes[1024];
        int len1;
        while((len1 = is.read(bytes1) != -1){
          baos.write(bytes1,0,len);
        }
        System.out.println(baos.toString());

        //5. 关闭资源
        baos.close();
        is.close();
        fis.close();
        os.close();
        socket.close();
    }
UDP编程
    /**
     * UDP网络编程 发送端和接收端
     */
    @Test
    public void sender(){
        DatagramSocket socket = null;
        try {
            //1. 创建一个socket来发送
            socket = new DatagramSocket();

            //2. 把一些信息打包给DatagramPacket
            String str = "这是一个UDP数据";
            byte[] data = str.getBytes();
            InetAddress ip = InetAddress.getByName("127.0.0.1");
            // 把一切信息都打包起来发送
            DatagramPacket packet = new DatagramPacket(data,0,data.length,ip,8850);

            //3. 将包由socket发送
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(socket != null){
                //4. 关闭资源
                socket.close();
            }
        }
    }

    @Test
    public void receiver(){
        DatagramSocket socket = null;
        try {
            //1. 创建socket
            socket = new DatagramSocket();

            //2. 接收包,用数组存储数据
            byte[] data = new byte[1024];
            DatagramPacket packet = new DatagramPacket(data,0,data.length);

            //3. 接收包数据,从0到数组长度
            socket.receive(packet);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(socket != null){
                //4. 关闭资源
                socket.close();
            }
        }
    }
下载案例
  1. URL下载案例,tomcat下webapps中存放静态资源,
  2. 创建url对象,找到资源路径
  3. 创建url连接
    • 先打开连接,返回连接对象
    • 再通过连接对象进行连接
    • 读入(从流中读取文件信息)
    • 写出(边读边写到本地硬盘中)
  4. 关闭连接
    public void downloadTest(){
        //1. 指定URL资源
        URL url = new URL("http://localhost:8080/example/ju.png");

        //2. 返回一个url打开连接对象
        HttpURLConnection urlConnection = (HttpURLConnection)  url.openConnection();

        //3. 连接
        urlConnection.connect();

        InputStream is = urlConnection.getInputStream();
        FileOutputStream fos = new FileOutputStream("蓝屏01.png");
        byte[] bytes = new byte[1024];
        int len;
        while((len = is.read(bytes)) != -1){
            fos.write(bytes,0,len);
        }

        fos.close();
        is.close();
        urlConnection.disconnect();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值