java进阶10——面向网络编程

网络编程概述

网络协议

通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
网络通信协议有很多种,目前应用最广泛的是TCP/IP协议(Transmission Control Protocal/Internet Protoal传输控制协议/英特网互联协议),它是一个包括TCP协议和IP协议,UDP(User Datagram Protocol)协议和其它一些协议的协议组。
在进行数据传输时,要求发送的数据与收到的数据完全一样,这时,就需要在原有的数据上添加很多信息,以保证数据在传输过程中数据格式完全一致。

  • TCP/IP协议的层次结构:
    java进阶10——面向网络编程_第1张图片
    上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能
    链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
    网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
    传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
    应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。

IP地址和端口号

计算机在网络中实现通信的一个标识号,通过这个标识号来指定接受数据的计算机或发送数据的计算机
在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,如:00001010000000000000000000000001。由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,如 “192.168.1.100”。
随着计算机网络规模的不断扩大,对IP地址的需求也越来越多,IPV4这种用4个字节表示的IP地址面临枯竭,因此IPv6 便应运而生了,IPv6使用16个字节表示IP地址,它所拥有的地址容量约是IPv4的8×10^28倍,达到2^128个(算上全零的),这样就解决了网络地址资源数量不够的问题。
通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。在计算机中,不同的应用程序是通过端口号区分的。端口号是用两个字节(16位的二进制数)表示的,它的取值范围是0~65535,其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号,从而避免端口号被另外一个应用或服务所占用。

  • IP地址和端口号的作用
    java进阶10——面向网络编程_第2张图片
    从上图中可以清楚地看到,位于网络中一台计算机可以通过IP地址去访问另一台计算机,并通过端口号访问目标计算机中的某个应用程序。

网络通信的三要素

1.Ip地址
2.端口号
3.通讯协议TCP/Ip或UPD协议

InetAddress

JDK中提供了一个InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法

  • 常用方法
    java进阶10——面向网络编程_第3张图片

UDP协议

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

  • 使用UDP协议的优点
    消耗资源小
    通信效率高
    所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
  • 使用UDP协议的缺点
    由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
  • UDP的交换过程如下图所示。
    java进阶10——面向网络编程_第4张图片

DatagramPacket

UDP通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接收货物时都需要使用集装箱来装载货物,UDP通信也是一样,发送和接收的数据也需要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。

  • 构造方法
    这里需要注意,在接收方和发送方的构造方法是不一样的,发送方需要确定接受方的ip和端口号,否则无法发送失败,而接收方只需要接受字节数组和长度即可
    java进阶10——面向网络编程_第5张图片
  • 常用方法
    java进阶10——面向网络编程_第6张图片
  • 案例
// 这是一个UDP的Demo的客户端
public class ClientDemo {
    public static void main(String[] args) throws Exception {
        // 创建socket
        DatagramSocket datagramSocket = new DatagramSocket();
        InetAddress ip = InetAddress.getByName("localhost");
        int port = 9998;
        String s = "hello UDP demo";
        byte[] buf = s.getBytes();
        int length = 1024;

        // 创建DatagramPacket
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, ip, port);
        datagramSocket.send(datagramPacket);

        // 关流
        datagramSocket.close();
    }
}
// 这是一个UDP的Demo的服务器端
public class ServerDemo {
    public static void main(String[] args) throws Exception{
        // 创建服务器端的Socket
        DatagramSocket datagramSocket = new DatagramSocket(9998);

        // 接收发送端的数据
        byte[] buf = new byte[1024];
        int length = 1024;
        DatagramPacket datagramPacket = new DatagramPacket(buf, length);
        datagramSocket.receive(datagramPacket);
        System.out.println(new String(buf, 0, datagramPacket.getLength()));

        // 关流
        datagramSocket.close();
    }
}

TCP协议

  • 与UDP的相同点
    TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建socket对象。
  • 与UDP的区别
    UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。
    而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
  • 实现TCP的类
    一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。
    通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。

ServerSocket

  • 构造方法
    这里写图片描述
  • 常用方法
    java进阶10——面向网络编程_第7张图片
    ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。

Socket

  • 构造方法
    这里写图片描述
    这里写图片描述
  • 常用方法
int getPort(); // 该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号
InetAddress getLocalAddress(); // 该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回
void close(); // 该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源
InputStream getInputStream(); // 该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据
OutputStream getOutputStream(); // 该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据

在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。
- 案例:

// 这是一个TCP协议的Demo的客户端
public class ClientDemo {
    public static void main(String[] args) throws Exception {
        // 创建Socket,指定地址,指定端口号
        String ip = "192.168.1.124";
        int port = 9999;
        Socket socket = new Socket(ip, port);

        // 将数据打包——读取文件中的数据
        String pathname = "G:/Hello.txt";
        File file = new File(pathname);
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        OutputStream outputStream = socket.getOutputStream();
        int len = 0;
        byte[] b = new byte[1024];
        while((len = bufferedInputStream.read(b)) != -1) {
            outputStream.write(b, 0, len);
        }

        // 关流
        outputStream.close();
        bufferedInputStream.close();
    }
}
// 这是一个TCP协议的Demo中的服务器端
public class ServerDemo {
    public static void main(String[] args) throws Exception {
        // 创建服务器端的Socket
        int port = 9999;
        ServerSocket serverSocket = new ServerSocket(port);

        // 阻塞
        Socket socket = serverSocket.accept();

        // 创建输入流对象
        InputStream inputStream = socket.getInputStream();
        int len = 0;
        byte[] b = new byte[1024];
        while((len = inputStream.read(b)) != -1) {
            System.out.println(new String(b, 0, len));
        }

        // 关流
        inputStream.close();
    }
}

你可能感兴趣的:(java,java,java进阶,java进阶)