黑马全套Java教程(九):网络编程(三)

简介: 黑马全套Java教程(九):网络编程

黑马全套Java教程(九):网络编程(二)+https://developer.aliyun.com/article/1556497

37 网络编程

网络编程可以让程序与网络上的其他设备中的程序进行数据交互

常见的通信模式:B/S,C/S

37.1 网络通信的三要素

IP地址:设备在网络中的地址,是唯一的标识

端口:应用程序在设备中唯一的标识

协议:数据在网络中传输的规则,常见的协议有UDP协议和TCP协议

要素一:IP地址

package d1_inetAddress;
import java.net.InetAddress;
/*
 *目标:InetAddress类概述
 * 一个该类的对象就代表一个IP地址对象
 *
 *
 * InetAddress类的方法:
 *          static InetAddress getLocalHost()
 *              * 获取本地主机IP地址对象
 *          static InetAddress getByName(String host)
 *              * 根据IP地址字符串或主机名获得对应的IP地址对象
 *          String getHostName()
 *              * 获得主机名
 *          String getHostAddress()
 *              * 获得IP地址字符串
 */
public class InetAddressDemo01 {
    public static void main(String[] args) throws Exception{
        //1. 获取本机地址对象
        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());
        //3. 获取公网IP对象
        InetAddress ip3 = InetAddress.getByName("110.242.68.4");
        System.out.println(ip3.getHostName());
        System.out.println(ip3.getHostAddress());
        //4. 判断是否能通:ping 5s之前测试是否可通
        System.out.println(ip3.isReachable(5000));
    }
}
LAPTOP-7NLRI4B2
192.168.111.1
www.baidu.com
110.242.68.3
110.242.68.4
110.242.68.4
true


要素二:端口号

要素三:协议



37.2 UDP通信

  • UDP是一种无连接、不可靠传输的协议
  • 将数据源IP、目的地IP和端口封装成数据包,不需要建立连接
  • 每个数据包的大小限制在64KB内
  • 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
  • 可以广播发送,发送数据结束时无需释放资源,开销小,速度快
  • 使用场景:语音通话,视频会话

例:UDP实现一发一收

ServerDemo2.java

package d2_udp1;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ServerDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动=====");
        //1. 创建接收端对象,注册端口
        DatagramSocket socket = new DatagramSocket(8888);
        //2. 创建一个数据包对象接收数据(韭菜盘子)
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        //3. 等待,接受数据
        socket.receive(packet);
        //4. 取出数据即可
        //读取多少倒出多少
        int len = packet.getLength();
        String rs = new String(buffer, 0, len);
        System.out.println("收到了:" + rs);
        //获取发送端的ip和端口
        String ip = packet.getSocketAddress().toString();
        System.out.println("对方地址:" + ip);
        int port = packet.getPort();
        System.out.println("对方端口:" + port);
        
        socket.close();
    }
}

ClientDemo1.java

package d2_udp1;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//发送端   一发一收
public class ClientDemo1 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====客户端启动=====");
        //1. 创建发送端对象  发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6666);   //可指定可不指定端口
        //2. 创建一个数据报对象封装数据
        /*
        * public DatagramPacket(byte buf[], int length,
        * InetAddress address, int port)
        * 参数一:封装要发送的数据
        *参数二:发送的数据大小
        * 参数三:服务端的主机IP地址
        * 参数四:服务端的端口
        * */
        byte[] buffer = "我是一个快乐的韭菜".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
        //3. 发送数据出去
        socket.send(packet);
        socket.close();
    }
}


例:UDP实现多发多收

ServerDemo2.java

package d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ServerDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动=====");
        //1. 创建接收端对象,注册端口
        DatagramSocket socket = new DatagramSocket(8888);
        //2. 创建一个数据包对象接收数据(韭菜盘子)
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        while (true) {
            //3. 等待,接受数据
            socket.receive(packet);
            //4. 取出数据即可
            //读取多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到了来自:" + packet.getAddress() + ",对方端口:" + packet.getPort() + "的消息:" + rs);
        }
    }
}

ClientDemo1.java

package d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
//发送端   多发多收
public class ClientDemo1 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====客户端启动=====");
        //1. 创建发送端对象  发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6666);
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            if("exit".equals(msg)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }
            //2. 创建一个数据报对象封装数据
            byte[] buffer = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
            //3. 发送数据出去
            socket.send(packet);
        }
    }
}


UDP实现广播:

  1. 发送端发送的数据包的目的地写的是广播地址,且指定端口。(255.255.255.255,9999)
  2. 本机所在网段的其他主机的程序只要匹配端口成功就可以收到消息了。(9999)

ClientDemo1.java

package d4_udp3_broadcast;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
//发送端   多发多收
public class ClientDemo1 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====客户端启动=====");
        //1. 创建发送端对象  发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6666);
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            if("exit".equals(msg)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }
            //2. 创建一个数据报对象封装数据
            byte[] buffer = msg.getBytes();
            //填入接收方的IP和端口
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);
            //3. 发送数据出去
            socket.send(packet);
        }
    }
}

ServerDemo2.java

package d4_udp3_broadcast;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ServerDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动=====");
        //1. 创建接收端对象,注册端口
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 创建一个数据包对象接收数据(韭菜盘子)
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        while (true) {
            //3. 等待,接受数据
            socket.receive(packet);
            //4. 取出数据即可
            //读取多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到了来自:" + packet.getAddress() + ",对方端口:" + packet.getPort() + "的消息:" + rs);
        }
    }
}


UDP实现组播:

  1. 发送端的数据包的目的地是组播IP。(例如:224.0.1.1,端口:9999)
  2. 接收端必须绑定该IP(224.0.1.1),端口还要对应发送端的目的端口9999,这样即可接收该组播消息
  3. DatagramSocket的子类MulticastSocket可以在接收端绑定组播IP

ServerDemo2.java

package d5_udp4_multicast;
import java.net.*;
//接收端
public class ServerDemo2 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动=====");
        //1. 创建接收端对象,注册端口
        MulticastSocket socket = new MulticastSocket(9999);
        //把当前接收端加入到一个组播组当中,绑定对应的组播消息的组播IP
        socket.joinGroup(InetAddress.getByName("224.0.1.1"));   //两个方法都可以
        //Socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"), 9999),
        //       NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
        //2. 创建一个数据包对象接收数据(韭菜盘子)
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
        while (true) {
            //3. 等待,接受数据
            socket.receive(packet);
            //4. 取出数据即可
            //读取多少倒出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到了来自:" + packet.getAddress() + ",对方端口:" + packet.getPort() + "的消息:" + rs);
        }
    }
}

ClientDemo1.java

package d5_udp4_multicast;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
//发送端   多发多收
public class ClientDemo1 {
    public static void main(String[] args) throws Exception{
        System.out.println("=====客户端启动=====");
        //1. 创建发送端对象  发送端自带默认的端口号
        DatagramSocket socket = new DatagramSocket(6666);
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            if("exit".equals(msg)){
                System.out.println("离线成功!");
                socket.close();
                break;
            }
            //2. 创建一个数据报对象封装数据
            byte[] buffer = msg.getBytes();
            //填入接收方的IP和端口
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("224.0.1.1"), 9999);
            //3. 发送数据出去
            socket.send(packet);
        }
    }
}


37.3 TCP通信


例:TCP实现一发一收

ServerDemo2.java

package d5_socket1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
//目标:开发socket网络编程入门的艾玛的服务端,实现接收消息
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=====服务端启动成功=====");
            //1. 注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //2. 必须调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
            Socket socket = serverSocket.accept();
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            if((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientDemo1.java

package d5_socket1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
//目标:完成Socket网络编程入门案例的客户端开发,实现1发1收
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("=====客户端启动成功=====");
            //1. 创建Socket通信管道请求有服务端的连接
            //public Socket(String host, int port)
            //参数一:服务器的IP
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);
            //2. 从socket通信管道中得到一个字节输出流,负责发送数据
            OutputStream os = socket.getOutputStream();
            //3. 把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            //4. 发送消息
            ps.println("我是TCP的客户端");
            ps.flush();
            //关闭资源
            //socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


例:TCP实现多发多收

ServerDemo2.java

package d6_socket2;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
//目标:开发socket网络编程入门的艾玛的服务端,实现接收消息
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=====服务端启动成功=====");
            //1. 注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //2. 必须调用accept方法,等待接收客户端的Socket连接请求,建立Socket通信管道
            Socket socket = serverSocket.accept();
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            while((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientDemo1.java

package d6_socket2;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//目标:完成Socket网络编程入门案例的客户端开发,实现多发多收
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("=====客户端启动成功=====");
            //1. 创建Socket通信管道请求有服务端的连接
            //public Socket(String host, int port)
            //参数一:服务器的IP
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);
            //2. 从socket通信管道中得到一个字节输出流,负责发送数据
            OutputStream os = socket.getOutputStream();
            //3. 把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                //4. 发送消息
                System.out.println("请说:");
                String msg = sc.nextLine();
                ps.println(msg);
                ps.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


例:实现服务端接收多个客户端

ServerDemo2.java

package d7_socket3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
//目标:实现服务端可以同时处理多个客户端的消息
public class ServerDemo2 {
    public static void main(String[] args) {
        try {
            System.out.println("=====服务端启动成功=====");
            //1. 注册端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //定义一个死循环由主线程负责不断的接收客户端的Socket管道连接
            while (true) {
                //2. 每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + ":它来了,上线了!");
                //3. 开始创建独立线程处理哦socket
                new ServerReaderThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientDemo1.java

package d7_socket3;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//目标:完成Socket网络编程入门案例的客户端开发,实现多发多收
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("=====客户端启动成功=====");
            //1. 创建Socket通信管道请求有服务端的连接
            //public Socket(String host, int port)
            //参数一:服务器的IP
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",7777);
            //2. 从socket通信管道中得到一个字节输出流,负责发送数据
            OutputStream os = socket.getOutputStream();
            //3. 把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                //4. 发送消息
                System.out.println("请说:");
                String msg = sc.nextLine();
                ps.println(msg);
                ps.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerReaderThread.java

package d7_socket3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run(){
        try {
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            while((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (IOException e) {
            System.out.println(socket.getRemoteSocketAddress() + ":下线了!");
        }
    }
}

黑马全套Java教程(九):网络编程(四)+https://developer.aliyun.com/article/1556510

目录
相关文章
|
19小时前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解
|
20小时前
|
安全 网络协议 Java
Java中的网络通信:HTTP详解
Java中的网络通信:HTTP详解
|
20小时前
|
网络协议 Java 网络安全
Java中的网络编程:TCP详解
Java中的网络编程:TCP详解
|
14小时前
|
XML 测试技术 数据格式
《手把手教你》系列基础篇(八十五)-java+ selenium自动化测试-框架设计基础-TestNG自定义日志-下篇(详解教程)
【7月更文挑战第3天】TestNG教程展示了如何自定义日志记录。首先创建一个名为`TestLog`的测试类,包含3个测试方法,其中一个故意失败以展示日志。使用`Assert.assertTrue`和`Reporter.log`来记录信息。接着创建`CustomReporter`类,继承`TestListenerAdapter`,覆盖`onTestFailure`, `onTestSkipped`, 和 `onTestSuccess`,在这些方法中自定义日志输出。
17 6
|
1天前
|
Java 测试技术 Android开发
《手把手教你》系列基础篇(八十四)-java+ selenium自动化测试-框架设计基础-TestNG日志-上篇(详解教程
【7月更文挑战第2天】TestNG是一个用于自动化测试的Java框架,提供日志记录功能。日志有两种模式:底层级详细记录每个步骤,高层级仅记录关键事件。示例代码展示了如何在测试方法中使用`Reporter.log()`记录信息,这些信息会显示在TestNG HTML报告中。文章还提及了日志显示时可能出现的编码问题及解决办法。
|
1天前
|
网络协议 Java
Java网络编程基础与Socket实现技术
Java网络编程基础与Socket实现技术
|
1天前
|
算法 Java 数据库连接
Java中优化网络通信的方法和工具
Java中优化网络通信的方法和工具
|
2天前
|
XML 存储 JavaScript
黑马全套Java教程(十)(二)
黑马全套Java教程(十)
5 0
|
2天前
|
IDE Java 测试技术
黑马全套Java教程(十)(一)
黑马全套Java教程(十)
10 0
|
3天前
|
网络协议 安全 Java
Java详解:网络编程(零基础入门)
Java详解:网络编程(零基础入门)