黑马全套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

目录
相关文章
|
22天前
|
Java
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
33 1
|
22天前
|
XML JSON 搜索推荐
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
43 0
|
2天前
|
Java API
Java时间戳教程
本文详细介绍Java中时间戳的处理方法,包括获取当前时间戳、使用`java.time`包、时间戳与日期的相互转换及格式化等。示例代码展示了如何利用`System.currentTimeMillis()`和`java.time.Instant`获取时间戳,以及如何通过`Date`和`ZonedDateTime`进行日期转换和时区处理。随着Java 8引入的`java.time`包,日期时间操作变得更加强大和便捷,推荐在新项目中优先采用。
|
22天前
|
Java
【实战演练】JAVA网络编程高手养成记:URL与URLConnection的实战技巧,一学就会!
【实战演练】JAVA网络编程高手养成记:URL与URLConnection的实战技巧,一学就会!
29 3
|
22天前
|
安全 Java 网络安全
【认知革命】JAVA网络编程新视角:重新定义URL与URLConnection,让网络资源触手可及!
【认知革命】JAVA网络编程新视角:重新定义URL与URLConnection,让网络资源触手可及!
31 2
|
23天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
21天前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
42 0
|
22天前
|
缓存 Java API
【技术前沿】JAVA网络编程黑科技:URL与URLConnection的创新应用,带你飞越极限!
【技术前沿】JAVA网络编程黑科技:URL与URLConnection的创新应用,带你飞越极限!
28 0
|
23天前
|
Java API
Java与Lua互相调用简单教程
【8月更文挑战第29天】在软件开发中,Java以其强大的稳定性和广泛的生态系统著称,而Lua则因其轻量级、灵活和嵌入式的特点在脚本编写、游戏开发等领域大放异彩。将两者结合使用,可以充分利用Java的底层能力和Lua的快速开发优势。本文将通过一个简单的教程,介绍如何在Java程序中嵌入并执行Lua脚本,以及如何在Lua中调用Java方法。
19 0
|
Java 数据库 容器