java2_day06网络编程

Java网络编程

目录

  1. 网络编程概述

  2. 网络通信要素概述

  3. 通信要素1:IP和端口号

  4. 通信要素2:网络协议

  5. TCP网络编程

  6. UDP网络编程

  7. URL编程

1 网络编程概述

  • Java是Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。

  • Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境

1.1 网络基础

  • 计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。

  • 网络编程的目的: 直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。

  • 网络编程中有两个主要的问题:

    • 如何准确地定位网络上一台或多台主机:定位主机上的特定的应用

    • 找到主机后如何可靠高效地进行数据传输

2 网络通信要素概述

  • IP和端口号

  • 网络通信协议

2.1 如何实现网络中的主机相互通信

  • 通信双方地址

    • IP:网络中唯一定位的一台主机

    • 端口号:定位这台主机的哪个应用程序在通讯

  • 一定的规则(即:网络通信协议。有两套参考模型)

    • OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广

    • TCP/IP参考模型(或TCP/IP协议):事实上的国际标准

3 IP和端口

  • IP地址: 在java中使用InetAddress类代表IP

    • 唯一的标识Internet上的计算机(通信实体)

    • 本地回环地址(hostAddress): 127.0.0.1 主机名(hostName): localhost

    • IP地址分类方式1: IPV4和IPV6

      • IPV4: 4个字节组成,4个0-255。 大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1

      • IPV6: 128位 (16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(: )分开,如: 3ffe:3201:1401:1280c8f.fe4d:db39:1984

    • IP地址分类方式2: 公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0--192.168.255.255,专为组织机 构内部使用

    • 特点: 不易记忆

    • 域名: www.baidu.com

 package com.xin.java1;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/27 10:18
  * Description:
  *一、网络编程中有两个主要的问题:
  * - 如何准确地定位网络上一台或多台主机:定位主机上的特定的应用
  * - 找到主机后如何可靠高效地进行数据传输
  *二、网络编程中的两个要素
  * 1. 对应问题一: IP和端口号
  * 2. 对应问题二: 提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
  *三、通信要素一: IP和端口号
  * 1. IP: 唯一的标识Internet上的计算机(通信实体)
  * 2. 在java中使用InetAddress类代表IP
  * 3. IP分类: IPv4 和IPv6; 万维网和局域网
  * 4. 域名: www.baidu.com
  * 5. 本地回路地址:127.0.0.1 对应着: localhost(相当于域名)
  * 6. 如何实例化InetAddress:;两个方法:getByName(String host)、getLocalHost()
  *       两个常用方法:getHostName()/getHostAddress()
  * 7. 端口号:正在计算机上运行的进程
  *   要求:不同的进程有不同的端口号
  *   范围: 被规定为一个16位的整数0-65535
  *8. 端口号与IP地址的组合得出一个网络套接字: Socket.
  */
 public class InetAddressTest {
     public static void main(String[] args) {
         try {
             InetAddress inet1 = InetAddress.getByName("192.168.10.14");  //具体的IP地址
             System.out.println(inet1);  ///192.168.10.14
 
             InetAddress inet2 = InetAddress.getByName("www.atguigu.com"); //填写域名或者地址都行
             System.out.println(inet2);   //www.atguigu.com/120.201.240.42
 
             InetAddress inet3 = InetAddress.getByName("localhost");
             System.out.println(inet3);   //localhost/127.0.0.1,表示的是回环地址
 
             //获取本机的IP地址
             InetAddress localHost = InetAddress.getLocalHost();
             System.out.println(localHost);  //Wu001/192.168.91.1,表示的是本机在局域网中的地址
 
             //getHostName()获取域名
             System.out.println(inet2.getHostName());  //www.atguigu.com
 
             //getHostAddress()获取地址
             System.out.println(inet2.getHostAddress());  //120.201.240.42
 
        } catch (UnknownHostException e) {
             e.printStackTrace();
        }
    }
 }

image-20220427104601007

  • 端口号标识正在计算机上运行的进程(程序)

    • 不同的进程有不同的端口号

    • 被规定为一个16位的整数0~65535。

    • 端口分类:

      • 公认端口: 0~1023。被预先定义的服务通信占用(如: HTTP占用端口80,FTP 占用端口21,Telnet占用端口23)

      • 注册端口: 1024~49151。 分配给用户进程或应用程序。( 如: Tomcat占用端口8080,MySQL占用端口3306,Oracle 占用端口1521等)。

      • 动态/私有端口: 49152~65535。

  • 端口号与IP地址的组合得出一个网络套接字: Socket.

4 网络通信协议

  • 网络通信协议 计算机网络中实现通信必须有一-些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准

  • 问题: 网络协议太复杂 计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩,解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?

  • 通信协议分层的思想 在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一 层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

image-20220427101458317

image-20220427101704889

  • TCP/IP协议簇

  • 传输层协议中有两个非常重要的协议:

    • 传输控制协议TCP(Transmission Control Protocol)。比如打电话

    • 用户数据报协议UDP(User Datagram Protocol)。比如应用在视频播放,丢几帧图片不影响

image-20220427114714694

image-20220427114903782

TCP三次握手,实现多次信息确认,建立链接,保证通信可靠。

TCP四次挥手,释放连接

第一步客户端发送请求断开信息,第二步服务器端收到断开请求,第三步服务器已经断开,第四步再次发送信息确认是否断开。

image-20220427120002582

  • TCP/IP以其两个主要协议: 传输控制协议(TCP) 和 网络互联协议(IP) 而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。

  • IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。

  • TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。

5 TCP网络编程

  • 客户端先执行会报错,因为要执行三次握手,服务器端不打开,无法执行握手。

实例1:客户端发送内容给服务端,服务端将内容打印到控制台上

 package com.xin.java1;
 
 import org.junit.Test;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.UnknownHostException;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/27 14:56
  * Description:
  * 实现TCP的网络编程
  * 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
  */
 public class TCPTest1 {
     //客户端
     @Test
     public void client() {
         Socket socket = null;
         OutputStream os = null;
         try {
             //1. 创建Socket对象,指明服务器端的IP和端口号
             InetAddress inet = InetAddress.getByName("127.0.0.1");  //指明对方的IP,也是本机IP,因为现在只有一个主机
             socket = new Socket(inet, 8899);  //端口号不能超过65535
             //2. 获取一个输出流,用于输出数据
             os = socket.getOutputStream();  //发送给服务器端的数据。
             //3. 写出数据的操作
             os.write("你好,我是客户端大叔".getBytes());  //将一个字符串转化为一个字节数组byte []的方法。
        } catch (IOException e) {
             e.printStackTrace();
        } finally {
             //4. 资源的关闭
             if(os != null){
                 try {
                     os.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
             if(socket != null){
                 try {
                     socket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
        }
    }
 
 
     //服务端
     @Test
     public void server() {  //为了保证程序一定会执行,所以不用throws,try catch出问题也能执行一部分
         ServerSocket ss = null;
         Socket socket = null;
         InputStream is = null;
         ByteArrayOutputStream baos = null;
         try {
             //1. 创建服务器端的ServerSocket,指明自己的端口号
             ss = new ServerSocket(8899);   //设置自己的端口号,便于客户端访问
             //2. 调用accept()表示接收来自于客户端的Socket
             socket = ss.accept();   //接收来自客户端数据
             //3. 获取输入流
             is = socket.getInputStream();  //从客户端发来的数据。
 
 //       byte[] bytes = new byte[1024]; //是中文,容易乱码,如果字节太小
 //       int len;
 //       while((len = is.read(bytes)) != -1){
 //           String s = new String(bytes, 0, len);
 //           System.out.println(s); //一部分一部分输出,可能会乱码
 //       }
             //4. 读取输入流中的数据
             baos = new ByteArrayOutputStream();
             //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
             //先拼着,不会单独转换成字符串,等全部读取完才会转换,所以中文也不会乱码
             byte[] bytes = new byte[5];
             int len;
             while((len = is.read(bytes)) != -1){
                 baos.write(bytes, 0 ,len);  //通过字节流写出
            }
             System.out.println(baos.toString());    //记得输出
             System.out.println("收到了来自于"+ socket.getInetAddress().getHostName() + "的数据");
        } catch (IOException e) {
             e.printStackTrace();
        } finally {
             if(baos != null){
                 //关闭资源
                 try {
                     baos.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(is != null){
                 try {
                     is.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(socket != null){
                 try {
                     socket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(ss != null){
                 try {
                     ss.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
        }
    }
 
 }

实例2:客户端发送文件给服务端,服务端将文件保存在本地。

 package com.xin.java1;
 
 import org.junit.Test;
 
 import java.io.*;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/27 16:34
  * Description:
  * 实现TCP的网络编程
  * 例题2: 客户端发送文件给服务端,服务端将文件保存在本地
  */
 public class TCPTest2 {
     //客户端
     @Test
     public void client() throws IOException {
         //1. 创建Socket对象,指明服务器端的IP和端口号
         InetAddress inet = InetAddress.getByName("127.0.0.1");  //指明对方的IP,也是本机IP,因为现在只有一个主机
         Socket socket = new Socket(inet, 8899);  //端口号不能超过65535
         //2. 获取一个输出流,用于输出数据
         OutputStream os = socket.getOutputStream();  //发送给服务器端的数据。
         //3.获取文件
         FileInputStream fis = new FileInputStream(new File("king.jpg"));
         //4. 读和写的过程
         byte[] bytes = new byte[5];
         int len;
         while((len = fis.read(bytes)) != -1){
             os.write(bytes, 0, len);
        }
 
         fis.close();
         os.close();
         socket.close();
    }
 
 
     //服务端
     @Test
     public void server() {  //为了保证程序一定会执行,所以不用throws,try catch出问题也能执行一部分
         ServerSocket ss = null;
         Socket socket = null;
         InputStream is = null;
         ByteArrayOutputStream baos = null;
         FileOutputStream fos = null;
         try {
             //1. 创建服务器端的ServerSocket,指明自己的端口号
             ss = new ServerSocket(8899);   //设置自己的端口号,便于客户端访问
             //2. 调用accept()表示接收来自于客户端的Socket
             socket = ss.accept();   //接收来自客户端数据
             //3. 获取输入流
             is = socket.getInputStream();  //从客户端发来的数据。
             //4. 存储文件(图片,即字节流)
             fos = new FileOutputStream(new File("king3.jpg"));
 
 //       byte[] bytes = new byte[1024]; //是中文,容易乱码,如果字节太小
 //       int len;
 //       while((len = is.read(bytes)) != -1){
 //           String s = new String(bytes, 0, len);
 //           System.out.println(s); //一部分一部分输出,可能会乱码
 //       }
             //4. 读取输入流中的数据
 //           baos = new ByteArrayOutputStream();
             //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
             //先拼着,不会单独转换成字符串,等全部读取完才会转换,所以中文也不会乱码
             byte[] bytes = new byte[5];
             int len;
             while((len = is.read(bytes)) != -1){
                 fos.write(bytes, 0 ,len);  //通过字节流写出
            }
 //           System.out.println(baos.toString());   //记得输出
             System.out.println("收到了来自于"+ socket.getInetAddress().getHostName() + "的数据");
        } catch (IOException e) {
             e.printStackTrace();
        } finally {
             if(baos != null){
                 //关闭资源
                 try {
                     baos.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(is != null){
                 try {
                     is.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(socket != null){
                 try {
                     socket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(ss != null){
                 try {
                     ss.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(fos != null){
                 try {
                     fos.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
        }
    }
 }

实例3:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端,并关闭相应链接。

思路:客户端也建立一个端口,进行读取。 服务器端输出。

 package com.xin.java1;
 
 import org.junit.Test;
 
 import java.io.*;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/27 17:03
  * Description:
  * 实现TCP的网络编程
  * 例题3. 从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端,并关闭相应链接。**
  */
 public class TCPTest3 {
     //客户端
     @Test
     public void client() throws IOException {
         //1. 创建Socket对象,指明服务器端的IP和端口号
         InetAddress inet = InetAddress.getByName("127.0.0.1");  //指明对方的IP,也是本机IP,因为现在只有一个主机
         Socket socket = new Socket(inet, 8899);  //端口号不能超过65535
         //2. 获取一个输出流,用于输出数据
         OutputStream os = socket.getOutputStream();  //发送给服务器端的数据。
         //3.获取文件
         FileInputStream fis = new FileInputStream(new File("king.jpg"));
         //4. 读和写的过程
         byte[] bytes = new byte[5];
         int len;
         while((len = fis.read(bytes)) != -1){   //从文件读取,通过socket,从控制端写出
             os.write(bytes, 0, len);
        }
         //关闭数据的输出
         socket.shutdownOutput();   //否则接下来会读取失败!!!!,数据阻塞
 
         //接收来自于服务器段的数据,并且显示到控制台上
         InputStream is = socket.getInputStream();
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
         //先拼着,不会单独转换成字符串,等全部读取完才会转换,所以中文也不会乱码
         byte[] byte1 = new byte[5];   //字节
         int len1;
         while((len1 = is.read(byte1)) != -1){  //通过socket,从服务器端读取,写到控制台
             baos.write(byte1, 0 ,len1);  //通过字节流写出
        }
         System.out.println(baos.toString());    //记得输出
 
         fis.close();
         os.close();
         socket.close();
         baos.close();
    }
 
     //服务端
     @Test
     public void server() {  //为了保证程序一定会执行,所以不用throws,try catch出问题也能执行一部分
         ServerSocket ss = null;
         Socket socket = null;
         InputStream is = null;
         ByteArrayOutputStream baos = null;
         FileOutputStream fos = null;
         OutputStream os = null;
         try {
             //1. 创建服务器端的ServerSocket,指明自己的端口号
             ss = new ServerSocket(8899);   //设置自己的端口号,便于客户端访问
             //2. 调用accept()表示接收来自于客户端的Socket
             socket = ss.accept();   //接收来自客户端数据
             //3. 获取输入流
             is = socket.getInputStream();  //从客户端发来的数据。
             //4. 存储文件(图片,即字节流)
             fos = new FileOutputStream(new File("king3.jpg"));
 
 //       byte[] bytes = new byte[1024]; //是中文,容易乱码,如果字节太小
 //       int len;
 //       while((len = is.read(bytes)) != -1){
 //           String s = new String(bytes, 0, len);
 //           System.out.println(s); //一部分一部分输出,可能会乱码
 //       }
             //4. 读取输入流中的数据
 //           baos = new ByteArrayOutputStream();
             //字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
             //先拼着,不会单独转换成字符串,等全部读取完才会转换,所以中文也不会乱码
             byte[] bytes = new byte[5];
             int len;
             while((len = is.read(bytes)) != -1){  //通过socket读取从控制端,写到文件里。
                 fos.write(bytes, 0 ,len);  //通过字节流写出
            }
 //           System.out.println(baos.toString());   //记得输出
             System.out.println("收到了来自于"+ socket.getInetAddress().getHostName() + "的数据");
 
             System.out.println("图片传输完成");
 
             os = socket.getOutputStream();  //发送给客户端的数据。
             os.write("接收成功".getBytes());
 
        } catch (IOException e) {
             e.printStackTrace();
        } finally {
 
             if(baos != null){
                 //关闭资源
                 try {
                     baos.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(is != null){
                 try {
                     is.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(socket != null){
                 try {
                     socket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(ss != null){
                 try {
                     ss.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(fos != null){
                 try {
                     fos.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
 
             if(os != null){ 
               try { 
                   os.close(); 
              } catch (IOException e) { 
                   e.printStackTrace(); 
              } 
          } 
      } 
  } 
}

5.1 客户端与服务端说明

  • 客户端

    • 自定义

    • 浏览器

  • 服务端

    • 自定义

    • Tomcat服务器

6 UDP网络编程

6.1 UDP网络通信(了解)

  • 类DatagramSocket和DatagramPacket实现了基于UDP协议网络程序。

  • UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

  • DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。数据报限定为64k;效率高;

  • UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一-样。

  • 发送端先执行也不会报错,只是接收不到数据了。

 package com.xin.java1;
 
 import org.junit.Test;
 
 import java.io.IOException;
 import java.net.*;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/27 20:49
  * Description:
  * UDP协议的网络编程
  */
 public class UDPTest {
     //发送端
     @Test
     public void sender() throws IOException {
         DatagramSocket socket = new DatagramSocket();  //小船一样,**端口号与IP地址的组合得出一个网络套接字: Socket.**
 
         String str = "我是UDP方式发送的导弹";
         byte[] data = str.getBytes();
         InetAddress inet = InetAddress.getLocalHost();  //IP
 
         DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet,9090);  //指明对方IP和端口号
 
         socket.send(packet);
         // 关闭流
         socket.close();
    }
 
     //接收端
     @Test
     public void recerver() throws IOException {
         DatagramSocket socket = new DatagramSocket(9090);
 
         byte[] bytes = new byte[100];   //因为接收的数据不长,这里就不复杂操作了,直接一次读取了
         DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);   //接收就不需要IP和端口号了
 
         socket.receive(packet);
 
         System.out.println(new String(packet.getData(), 0 , packet.getLength()));
 
         // 关闭流
         socket.close();
    }
 
 }

7 URL编程

  • URL(Uniform Resource Locator):统一资源定位符, 它表示Internet上某一资源的地址。(URL就是一个种子,定位到服务器,如果服务器资源不在了,那就访问不到了)

  • 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。

  • 通过URL我们可以访问Internet上的各种网络资源,比如最常见的www, ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。

  • URL的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

    • 例如: htp://192. 168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123

    • #片段名: 即锚点,例如看小说,直接定位到章节

    • 参数列表格式: 参数名=参数值&参数名=参数值...,

  • 一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:

    • public String getProtocol( ) 获取该URL的协议名

    • public String getHost( ) 获取该URL的主机名

    • public String getPort( ) 获取该URL的端口号

    • public String getPath( ) 获取该URL的文件路径

    • public String getFile( ) 获取该URL的文件名

    • public String getQuery( ) 获取 该URL的查询名

知识补充

posted @   诺不克  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示