Java攻城狮的入门课程@IT·互联网程序员

(三)通过Socket实现UDP编程

2017-05-23  本文已影响54人  黒猫

1、基础简介

UDP协议即用户数据报协议,是无连接、不可靠、无序的,但相对而言,UDP协议的传输速度会更快一些;UDP协议以数据报作为数据传输的载体,在进行数据传输时,首先需要将待传输的数据定义成数据报(Datagram),在数据报中指明所要到达的Socket,即目标主机地址及端口号,之后再将数据报发送即可;在java.net包中,提供了DatagramPacket类来表示数据报包,以及DatagramSocket类来表示端到端的通信。


2、通过编程实现“用户登录功能”之客户端

创建客户端的具体步骤:

  1. 定义待发送的信息,例如服务器端的主机地址、端口号、信息的内容等等
  2. 创建DatagramPacket,其中包含将要发送的信息
  3. 创建DatagramSocket,实现数据的发送

示例代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPclient {
    public static void main(String[] args) throws IOException {

        /*
         * 向服务器端发送数据
         */

        /*
         * 定义服务器地址 
         * 本案例中,服务器端和客户端都在本地同一台主机中 
         * 因此服务器地址可填“localhost” 此处选择抛出异常
         */
        InetAddress address = InetAddress.getByName("localhost");
        // 定义接收方的端口号
        int port = 6666;
        // 定义数据,并将字符串转化为字节数组
        byte[] data = "用户名:admin;密码:123456".getBytes();
        // 创建数据报,包含待发送的数据信息
        DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
        // 创建DatagramSocket对象,并抛出异常
        DatagramSocket socket = new DatagramSocket();
        // 向服务器端发送数据报
        socket.send(packet);

        /*
         * 接收服务器端的响应信息
         */

        // 创建空的数据报,用于接收响应信息
        byte[] data2 = new byte[1024];
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
        // 接收服务器端的响应数据
        socket.receive(packet2);
        // 读取服务器端的响应信息
        String reply = new String(data2, 0, packet.getLength());
        System.out.println("客户端——读取到服务器端反馈如下信息:" + reply);
        // 关闭相关资源
        socket.close();

    }

}


3、通过编程实现“用户登录功能”之服务器端

创建服务器端的具体步骤:

  1. 创建DatagramSocket,指明端口号
  2. 创建DatagramPacket,用来接收客户端发送的数据
  3. 读取接收的数据

示例代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPserver {
    public static void main(String[] args) throws IOException {

        /*
         * 接收客户端数据
         */

        // 创建服务器端DatagramSocket,指定监听端口,并抛出异常
        DatagramSocket socket = new DatagramSocket(6666);
        /*
         * 创建空的数据报,用于接收客户端发送的数据 
         * 数据报中的数据储存在字节数组中 
         * 因此首先创建字节数组,指定长度为1024
         */
        byte[] data = new byte[1024];
        // 创建DatagramPacket,参数为用于接收的数组及长度
        DatagramPacket packet = new DatagramPacket(data, data.length);
        // 为了便于查看结果,添加一句输出
        System.out.println("****服务器已启动,正在等待客户端发送数据****");
        /*
         * 接收客户端发送的数据 receive()方法会在接收到数据报之前一直阻塞 
         * 此处可抛出异常
         */
        socket.receive(packet);
        /*
         * 读取数据,将字节数组转换为字符串 
         * 使用packet.getLength()方法获取数据报长度
         */
        String info = new String(data, 0, packet.getLength());
        System.out.println("服务器端——读取到客户端提交如下信息:" + info);

        /*
         * 向客户端发送数据
         */

        /*
         * 定义客户端地址、端口号 
         * 通过之前接收到得客户端数据报来获取地址及端口号
         */
        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        byte[] data2 = "欢迎登录!".getBytes();
        // 创建数据报,包含响应的数据信息
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
        // 响应客户端
        socket.send(packet2);
        // 关闭相关资源
        socket.close();

    }

}

此时启动服务器端,结果如下:

之后在运行客户端代码,服务器端显示结果如下:

此时客户端结果如下:



4、使用多线程实现服务器与多客户端进行通信

使用多线程实现的具体步骤:

  1. 创建服务器端DatagramSocket及空数组,循环调用receive()方法等待客户端发送数据
  2. 客户端定义待发送的信息,创建DatagramSocket及DatagramPacket并发送数据
  3. 服务器端接收客户端发送的数据,创建新的线程与该客户端建立专线连接
  4. 建立专线连接的服务器端会在一个单独的线程上处理客户端发送的数据并给予响应
  5. 之后服务器端继续等待新的客户端发送数据

首先创建单独的线程类,用来处理客户端的请求,示例代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
 * 此类为服务器线程处理类
 * 继承Thread类
 */
public class thread extends Thread {
    // 创建与本线程相关的元素
    DatagramSocket socket = null;
    DatagramPacket packet = null;
    byte[] data = null;

    // 使用构造方法初始化元素
    public thread(DatagramSocket socket, DatagramPacket packet, byte[] data) {
        this.socket = socket;
        this.packet = packet;
        this.data = data;
    }

    // 线程执行操作,重写父类的run()方法
    public void run() {
        /*
         * 读取数据,将字节数组转换为字符串 
         * 使用packet.getLength()方法获取数据报长度
         */
        String info = new String(data, 0, packet.getLength());
        System.out.println("服务器端——读取到客户端提交如下信息:" + info);
        
        /*
         * 定义客户端地址、端口号 
         * 通过之前接收到得客户端数据报来获取地址及端口号
         */
        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        byte[] data2 = "欢迎登录!".getBytes();
        // 创建数据报,包含响应的数据信息
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
        // 响应客户端
        try {
            socket.send(packet2);
        } catch (IOException e) {

            e.printStackTrace();
        }

    }
}

之后创建服务器端,示例代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPserver {
    public static void main(String[] args) throws IOException {
        // 创建服务器端DatagramSocket,指定监听端口,并抛出异常
        DatagramSocket socket = new DatagramSocket(6666);
        /*
         * 创建空的数据报,用于接收客户端发送的数据 
         * 数据报中的数据储存在字节数组中 
         * 因此首先创建字节数组,指定长度为1024
         */
        byte[] data = new byte[1024];
        // 记录连接过的客户端数量
        int count = 0;
        // 为了便于查看结果,添加一句输出
        System.out.println("****服务器已启动,正在等待客户端发送数据****");
        // 循环监听等待客户端的连接
        while (true) {
            // 创建DatagramPacket,参数为用于接收的数组及长度
            DatagramPacket packet = new DatagramPacket(data, data.length);
            /*
             * 接收客户端发送的数据 receive()方法会在接收到数据报之前一直阻塞 
             * 此处可抛出异常
             */
            socket.receive(packet);
            // 创建一个新的线程
            thread thread = new thread(socket, packet, data);
            /*
             * 设置线程优先级,范围是[1,10],默认是5 
             * 未设置线程优先级可能会导致运行时速度非常慢 
             * 可降低优先级
             */
            thread.setPriority(4);  
            // 启动线程
            thread.start();
            // 统计连接过的客户端的数量
            count++;
            System.out.println("已累计服务" + count + "台客户端!");
            // 获取连接的客户端的IP地址
            InetAddress address = packet.getAddress();
            System.out.println("当前客户端的IP地址是:" + address.getHostAddress());
        }

    }

}

最后创建客户端,示例代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPclient {
    public static void main(String[] args) throws IOException {

        /*
         * 向服务器端发送数据
         */

        /*
         * 定义服务器地址 
         * 本案例中,服务器端和客户端都在本地同一台主机中 
         * 因此服务器地址可填“localhost” 此处选择抛出异常
         */
        InetAddress address = InetAddress.getByName("localhost");
        // 定义端口号
        int port = 6666;
        // 定义数据,并将字符串转化为字节数组
        byte[] data = "用户名:admin;密码:123456".getBytes();
        // 创建数据报,包含待发送的数据信息
        DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
        // 创建DatagramSocket对象,并抛出异常
        DatagramSocket socket = new DatagramSocket();
        // 向服务器端发送数据报
        socket.send(packet);

        /*
         * 接收服务器端的响应信息
         */

        // 创建数据报,用于接收响应信息
        byte[] data2 = new byte[1024];
        DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
        // 接收服务器端的响应数据
        socket.receive(packet2);
        // 读取服务器端的响应信息
        String reply = new String(data2, 0, packet.getLength());
        System.out.println("客户端——读取到服务器端反馈如下信息:" + reply);
        // 关闭相关资源
        socket.close();

    }

}


此时启动服务器端,结果如下:

之后在运行客户端代码,服务器端显示结果如下:


之后修改客户端的用户名为“Mike”,密码为“aaaaaa”,模拟多客户端登录,重新运行客户端代码,服务器端结果如下:


可见成功实现了服务器端与多个客户端进行通信。


版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作!             ↓↓↓
上一篇下一篇

猜你喜欢

热点阅读