5、网络编程

实现网络通信需要解决的两个问题

  1. 如何准确地定位网络上一台或多台主机;并且定位主机上的特定的应用?
  2. 找到主机后如何可靠高效地进行数据传输?

网络通信的两个要素

  1. IP和端口号,解决上面问题1
  2. 网络通信协议,例如TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层),解决上面问题2

通信要素一:IP和端口号

IP

InetAddress类
//1.获取本机地址ip对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());//获取主机名字
System.out.println(ip1.getHostAddress());//获取ip地址
//2.获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());//获取域名
System.out.println(ip2.getHostAddress());//获取域名的ip地址
//3.获取公网对象
InetAddress ip3 = InetAddress.getByName("112.80.248.76");
System.out.println(ip3.getHostName());//获取公网名字
System.out.println(ip3.getHostAddress());//获取公网ip地址
//判断网络是否能连接通信 ping 5s之前测试是否能通过
System.out.println(ip3.isReachable(5000));//通过会返回true

端口号

通信要素二:网络通信协议

分层模型

说明: untitle.png

TCP和UDP

TCP

TCP三次握手和四次挥手

img

三次握手

SYN标志位数置1,表示建立TCP连接;ACK标志表示验证字段。

四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

其中:FIN标志位数置1,表示断开TCP连接。

ServerSocket

Socket

客户端要获取一个 Socket 对象通过实例化 ,而服务器端获得一个 Socket 对象是通过accept()方法的返回值

TCP Demo

服务端
public static void main(String[] args) throws Exception{
    //1、创建服务端管道
    ServerSocket serverSocket = new ServerSocket(8080);
    //2、阻塞等待客户端连接
    Socket accept = serverSocket.accept();
    System.out.println("有客户端连接:" + accept.getRemoteSocketAddress());
    //3、从管道获取输入流,接收客户端消息
    InputStream inputStream = accept.getInputStream();
    //4、升级输入流为缓冲流
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    //5、逐行读取数据
    String s;
    while ((s = bufferedReader.readLine()) != null){
        System.out.println("客户端说:" + s);
    }
    bufferedReader.close();
}
客户端
public static void main(String[] args) throws Exception{
    //1、创建客户端管道
    Socket socket = new Socket("127.0.0.1",8080);
    //2、从管道获取输出流,发送消息给服务端
    OutputStream outputStream = socket.getOutputStream();
    //3、升级输出流为打印流
    PrintStream printStream = new PrintStream(outputStream);
    //4、发送消息
    printStream.println("你好呀,服务端!!!");
    printStream.flush();
    printStream.close();
}

UDP

DatagramSocket

DatagramPacket

java.net包中的 DatagramPacket 类用来表示数据报包,数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。

UDP Demo

服务端
public static void main(String[] args) throws Exception{
    //1、创建UDP对象,自定义端口
    DatagramSocket datagramSocket = new DatagramSocket(8080);
    //2、创建容器接收数据
    byte[] bytes = new byte[1024];
    //3、创建接收数据包对象,将数据接收到bytes中
    DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
    while (true){
        //4、接收数据
        datagramSocket.receive(datagramPacket);
        SocketAddress address = datagramPacket.getSocketAddress();
        //5、获取接收数据的长度
        int length = datagramPacket.getLength();
        System.out.println("收到数据:" + new String(bytes,0,length) + ",来自:" + address);
    }
}
客户端
public static void main(String[] args) throws Exception{
    //1、创建UDP对象
    DatagramSocket datagramSocket = new DatagramSocket();
    //发送五次数据
    for (int i = 0; i < 5; i++) {
        String s = "来自客户端的数据,第" + i + "次";
        byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
        //2、创建发送数据包对象
        DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("127.0.0.1"),8080);
        //3、发送数据
        datagramSocket.send(datagramPacket);
    }
    //4、关闭资源
    datagramSocket.close();
}