最新Java基础系列课程--Day15-网络编程(二)

简介: 最新Java基础系列课程--Day15-网络编程

最新Java基础系列课程--Day15-网络编程(一)https://developer.aliyun.com/article/1423553


四、UDP通信代码(多发多收)

刚才的案例,我们只能客户端发一次,服务端接收一次就结束了。下面我们想把这个代码改进一下,

需求:实现客户端不断的发数据,而服务端能不断的接收数据,客户端发送exit时客户端程序退出。

4.1 客户端程序

/**
 * 目标:完成UDP通信快速入门:实现客户端反复的发。
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建客户端对象(发韭菜出去的人)
        DatagramSocket socket = new DatagramSocket();
        // 2、创建数据包对象封装要发出去的数据(创建一个韭菜盘子)
       /* public DatagramPacket(byte buf[], int length,
             InetAddress address, int port)
               参数一:封装要发出去的数据。
               参数二:发送出去的数据大小(字节个数)
               参数三:服务端的IP地址(找到服务端主机)
               参数四:服务端程序的端口。
             */
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            // 一旦发现用户输入的exit命令,就退出客户端
            if("exit".equals(msg)){
                System.out.println("欢迎下次光临!退出成功!");
                socket.close(); // 释放资源
                break; // 跳出死循环
            }
            byte[] bytes = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length
                    , InetAddress.getLocalHost(),  6666);
            // 3、开始正式发送这个数据包的数据出去了
            socket.send(packet);
        }
    }
}

4.2 服务端程序

/**
 * 目标:完成UDP通信快速入门-服务端反复的收
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("----服务端启动----");
        // 1、创建一个服务端对象(创建一个接韭菜的人) 注册端口
        DatagramSocket socket = new DatagramSocket(6666);
        // 2、创建一个数据包对象,用于接收数据的(创建一个韭菜盘子)
        byte[] buffer = new byte[1024 * 64]; // 64KB.
        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(rs);
            System.out.println(packet.getAddress().getHostAddress());
            System.out.println(packet.getPort());
            System.out.println("--------------------------------------");
        }
    }
}

五、TCP通信(一发一收)

学习完UDP通信的代码编写之后,接下来我们学习TCP通信的代码如何编写。Java提供了一个java.net.Socket类来完成TCP通信。

我们先讲一下Socket完成TCP通信的流程,再讲代码怎么编写就很好理解了。如下图所示

  1. 当创建Socket对象时,就会在客户端和服务端创建一个数据通信的管道,在客户端和服务端两边都会有一个Socket对象来访问这个通信管道。
  2. 现在假设客户端要发送一个“在一起”给服务端,客户端这边先需要通过Socket对象获取到一个字节输出流,通过字节输出流写数据到服务端
  3. 然后服务端这边通过Socket对象可以获取字节输入流,通过字节输入流就可以读取客户端写过来的数据,并对数据进行处理。
  4. 服务端处理完数据之后,假设需要把“没感觉”发给客户端端,那么服务端这边再通过Socket获取到一个字节输出流,将数据写给客户端
  5. 客户端这边再获取输入流,通过字节输入流来读取服务端写过来的数据。

5.1 TCP客户端

下面我们写一个客户端,用来往服务端发数据。由于原始的字节流不是很好用,这里根据我的经验,我原始的OutputStream包装为DataOutputStream是比较好用的。

/**
 *  目标:完成TCP通信快速入门-客户端开发:实现1发1收。
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建Socket对象,并同时请求与服务端程序的连接。
        Socket socket = new Socket("127.0.0.1", 8888);
        // 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
        OutputStream os = socket.getOutputStream();
        // 3、把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        // 4、开始写数据出去了
        dos.writeUTF("在一起,好吗?");
        dos.close();
        socket.close(); // 释放连接资源
    }
}

5.2 TCP服务端

上面我们只是写了TCP客户端,还没有服务端,接下来我们把服务端写一下。这里的服务端用来接收客户端发过来的数据。

/**
 *  目标:完成TCP通信快速入门-服务端开发:实现1发1收。
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);
        // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();
        // 3、从socket通信管道中得到一个字节输入流。
        InputStream is = socket.getInputStream();
        // 4、把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);
        // 5、使用数据输入流读取客户端发送过来的消息
        String rs = dis.readUTF();
        System.out.println(rs);
        // 其实我们也可以获取客户端的IP地址
        System.out.println(socket.getRemoteSocketAddress());
        dis.close();
        socket.close();
    }
}

六、TCP通信(多发多收)

到目前为止,我们已经完成了客户端发送消息、服务端接收消息,但是客户端只能发一次,服务端只能接收一次。现在我想要客户端能过一直发消息,服务端能够一直接收消息。

下面我们把客户端代码改写一下,采用键盘录入的方式发消息,为了让客户端能够一直发,我们只需要将发送消息的代码套一层循环就可以了,当用户输入exit时,客户端退出循环并结束客户端。

6.1 TCP客户端

/**
 *  目标:完成TCP通信快速入门-客户端开发:实现客户端可以反复的发消息出去
 */
public class Client {
    public static void main(String[] args) throws Exception {
        // 1、创建Socket对象,并同时请求与服务端程序的连接。
        Socket socket = new Socket("127.0.0.1", 8888);
        // 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
        OutputStream os = socket.getOutputStream();
        // 3、把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            // 一旦用户输入了exit,就退出客户端程序
            if("exit".equals(msg)){
                System.out.println("欢迎您下次光临!退出成功!");
                dos.close();
                socket.close();
                break;
            }
            // 4、开始写数据出去了
            dos.writeUTF(msg);
            dos.flush();
        }
    }
}

6.2 TCP服务端

为了让服务端能够一直接收客户端发过来的消息,服务端代码也得改写一下。我们只需要将读取数据的代码加一个循环就可以了。

但是需要我们注意的时,如果客户端Socket退出之后,就表示连接客户端与服务端的数据通道被关闭了,这时服务端就会出现异常。服务端可以通过出异常来判断客户端下线了,所以可以用try…catch把读取客户端数据的代码套一起来,catch捕获到异常后,打印客户端下线。

/**
 *  目标:完成TCP通信快速入门-服务端开发:实现服务端反复发消息
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);
        // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
        Socket socket = serverSocket.accept();
        // 3、从socket通信管道中得到一个字节输入流。
        InputStream is = socket.getInputStream();
        // 4、把原始的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);
        while (true) {
            try {
                // 5、使用数据输入流读取客户端发送过来的消息
                String rs = dis.readUTF();
                System.out.println(rs);
            } catch (Exception e) {
                System.out.println(socket.getRemoteSocketAddress() + "离线了!");
                dis.close();
                socket.close();
                break;
            }
        }
    }
}

七、TCP通信(多线程改进)

上一个案例中我们写的服务端程序只能和一个客户端通信,如果有多个客户端连接服务端,此时服务端是不支持的。

为了让服务端能够支持多个客户端通信,就需要用到多线程技术。具体的实现思路如下图所示:每当有一个客户端连接服务端,在服务端这边就为Socket开启一条线程取执行读取数据的操作,来多少个客户端,就有多少条线程。按照这样的设计,服务端就可以支持多个客户端连接了。

按照上面的思路,改写服务端代码。

7.1 多线程改进

首先,我们需要写一个服务端的读取数据的线程类,代码如下

public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            while (true){
                try {
                    String msg = dis.readUTF();
                    System.out.println(msg);
                } catch (Exception e) {
                    System.out.println("有人下线了:" + socket.getRemoteSocketAddress());
                    dis.close();
                    socket.close();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

接下来,再改写服务端的主程序代码,如下:

/**
 *  目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
 */
public class Server {
    public static void main(String[] args) throws Exception {
        System.out.println("-----服务端启动成功-------");
        // 1、创建ServerSocket的对象,同时为服务端注册端口。
        ServerSocket serverSocket = new ServerSocket(8888);
        while (true) {
            // 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
            Socket socket = serverSocket.accept();
            System.out.println("有人上线了:" + socket.getRemoteSocketAddress());
            // 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
            new ServerReaderThread(socket).start();
        }
    }
}

7.2 案例拓展(群聊)

接着前面的案例,下面我们案例再次拓展一下,这个并不需要同学们必须掌握,主要是为了锻炼同学们的编程能力、和编程思维。

我们想把刚才的案例,改进成全能够实现群聊的效果,就是一个客户端发的消息,其他的每一个客户端都可以收到。

刚才我们写的多个客户端可以往服务端发现消息,但是客户端和客户端是不能直接通信的。想要试下全群聊的效果,我们还是必须要有服务端在中间做中转。 具体实现方案如下图所示:

我们可以在服务端创建一个存储Socket的集合,每当一个客户端连接服务端,就可以把客户端Socket存储起来;当一个客户端给服务端发消息时,再遍历集合通过每个Socket将消息再转发给其他客户端。


最新Java基础系列课程--Day15-网络编程(三)https://developer.aliyun.com/article/1423555

相关文章
|
4天前
|
存储 监控 安全
单位网络监控软件:Java 技术驱动的高效网络监管体系构建
在数字化办公时代,构建基于Java技术的单位网络监控软件至关重要。该软件能精准监管单位网络活动,保障信息安全,提升工作效率。通过网络流量监测、访问控制及连接状态监控等模块,实现高效网络监管,确保网络稳定、安全、高效运行。
32 11
|
1月前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
63 9
|
1月前
|
人工智能 Java 物联网
JAVA网络编程的未来:URL与URLConnection的无限可能,你准备好了吗?
随着技术的发展和互联网的普及,JAVA网络编程迎来新的机遇。本文通过案例分析,探讨URL与URLConnection在智能API调用和实时数据流处理中的关键作用,展望其未来趋势和潜力。
46 7
|
1月前
|
网络协议 Java 物联网
Java网络编程知识点
Java网络编程知识点
43 13
|
1月前
|
Java 开发者
JAVA高手必备:URL与URLConnection,解锁网络资源的终极秘籍!
在Java网络编程中,URL和URLConnection是两大关键技术,能够帮助开发者轻松处理网络资源。本文通过两个案例,深入解析了如何使用URL和URLConnection从网站抓取数据和发送POST请求上传数据,助力你成为真正的JAVA高手。
64 11
|
1月前
|
安全 Java API
深入探索Java网络编程中的HttpURLConnection:从基础到进阶
本文介绍了Java网络编程中HttpURLConnection的高级特性,包括灵活使用不同HTTP方法、处理重定向、管理Cookie、优化安全性以及处理大文件上传和下载。通过解答五个常见问题,帮助开发者提升网络编程的效率和安全性。
107 9
|
1月前
|
JSON 安全 算法
JAVA网络编程中的URL与URLConnection:那些你不知道的秘密!
在Java网络编程中,URL与URLConnection是连接网络资源的两大基石。本文通过问题解答形式,揭示了它们的深层秘密,包括特殊字符处理、请求头设置、响应体读取、支持的HTTP方法及性能优化技巧,帮助你掌握高效、安全的网络编程技能。
66 9
|
29天前
|
数据采集 Java API
java怎么设置代理ip:简单步骤,实现高效网络请求
本文介绍了在Java中设置代理IP的方法,包括使用系统属性设置HTTP和HTTPS代理、在URL连接中设置代理、设置身份验证代理,以及使用第三方库如Apache HttpClient进行更复杂的代理配置。这些方法有助于提高网络请求的安全性和灵活性。
|
5月前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解
|
5月前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解