(三)通过Socket实现UDP编程


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”,模拟多客户端登录,重新运行客户端代码,服务器端结果如下:


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


版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作!             ↓↓↓
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,014评论 11 349
  • 不过分奢求,不过分低促,不过分将就,不过分张扬,既能沉伏,亦能生长,既可沧海,也能月明,每个字眼每句话用心说出来都...
    春蚕勿散阅读 345评论 0 0
  • 这是我的第65篇日记,相信日积月累的力量。 早晨舞蹈。第一首舞曲是心肾相交舞曲。第二首是印度欢快舞曲,在这个舞曲中...
    妍华阅读 204评论 0 3