UDP协议网络编程及聊天室案例

一.UDP协议

UDP协议是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。 

二.UDP通信用到的类

 1.DatagramPacket

用于封装UDP通信中传输或者要接收的数据,而在发送端和接收端进行创建DatagramPacket对象时,使用的构造方法不同。在进行数据接收时,只需要定义一个字节数组存放接收的数据,并指定这个数组的长度即可;而在进行数据发送时,不仅要指定一个字节数组存放发送的数据,定义它的长度,还要指定接收端的IP地址和接收的端口号。示例如下:

        //定义接收端的DatagramPacket对象
        byte[] buffer = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buffer, 1024);


        //定义发送端的DatagramPacket对象
        byte[] buffer = "hello".getBytes();
        DatagramPacket sendPocket = 
        new DatagramPacket(buffer, buffer.length,InetAddress.getByName("192.168.1.105"), 12306);

 DatagramPacket对象中的常用方法

        //获得发送者的ip地址
        InetAddress ip = dp.getAddress();
        //获得发送者的端口号
        int port = dp.getPort();
        //获得接收的数据
        byte[] data = dp.getData();
        //获得数据长度
        int length = dp.getLength();
        String dataStr = new String(data,0,length);

 2.DatagramSocket

我们在上面已经将数据封装好了,但是数据不能自己从发送端发送到接收端,因此就需要一个对象将DatagramPocket数据包进行传输,这个对象就是DatagramSocket。在接收端定义时必须要定义端口号,这样发送端才能根据端口号找到接收端。而在发送端定义时则不需要,因为发送端不需要接收数据,通过系统默认分配一个端口号即可。

        //接收端必须要指定自己的端口号
        DatagramSocket recieveSocket = new DatagramSocket(9999);

        //发送端不需要指定端口号,通过系统默认分配即可
        DatagramSocket sendSocket = new DatagramSocket();

DatagramSocket对象中的常用方法

既然我们已经知道了,DatagramSocket是用来传输和接收数据包的,那么它最主要的方法就是如下两个发送和接收数据的方法。

        //发送端将数据包发送出去
        sendSocket.send(sendPocket);

        //接收端对数据进行接收
        recieveSocket.receive(dp);

三.一个完整的UDP通信过程代码

上面我们已经了解了UDP通信过程中需要用的类和方法,那么一个完整的UDP通信过程就很好理解了,代码如下

发送端:

/**
 * 1.定义一个DatagramSocket对数据包进行发送,不需要指定端口号
 * 2.定义一个DatagramPacket封装数据,里面有四个参数
 *    2.1要传输的字节数组
 *    2.2字节数组的长度
 *    2.3要传输的目的IP地址
 *    2.4要传输的目的端口号
 * 3.发送数据
 * 4.释放流资源
 */
public class UDPSender {
    public static void main(String[] args) throws IOException {
        //1.创建一个ds发送数据,不需要指定端口号
        DatagramSocket ds = new DatagramSocket();
        //2.创建一个dp封装数据
        byte[] bytes = "Hello UDP".getBytes();
        //InetAddress.getByName()方法可以通过域名映射到ip地址
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.43.104"), 9999);
        //3.发送数据
        ds.send(dp);
        //4.释放流资源
        ds.close();
    }
}

接收端:

/**
 * 1.定义一个DatagramSocket用于接收数据数据包,要指定自己的端口号
 * 2.定义一个DatagramPacket用于封装接收的数据包,定义下面的两个参数
 *      2.1要接受的字节数组
 *      2.2字节数组的长度
 * 3.处理接收到的数据
 * 4.释放流资源
 */


public class UDPReciever {
    public static void main(String[] args) throws Exception {
        /*
        *1.定义一个DatagramSocket接收数据包,指定端口号,这个端口号,要和
        * 发送端定义的端口号一致,这样才能进行联系。
        */
        DatagramSocket ds = new DatagramSocket(9999);
        //2.定义一个DatagramPacket封装接收来的数据包
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
        ds.receive(dp);
        //3.处理封装好的数据包
        int port = dp.getPort(); //发送端的端口号,我们没有指定,系统自动分配的。
        byte[] data = dp.getData();//发送端发送过来的数据
        InetAddress address = dp.getAddress();//发送端的IP地址
        int length = dp.getLength();//数据长度
        String str = new String(data, 0, length);
        System.out.println(port+"\t"+address+"\t"+str);

        //4.释放流资源
        ds.close();
    }
}

四.多线程聊天室案例

客户端:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class ChatRoomClient implements Runnable {
    //发送数据时 要知道ip地址和端口号
    private String ip;
    private int port;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        DatagramSocket ds = null;

        try {
            ds = new DatagramSocket();
            System.out.println("请输入您要发送的信息");

            while (true){
                Scanner sc = new Scanner(System.in);
                String s = sc.nextLine();
                byte[] bytes = s.getBytes();
                int length = bytes.length;
                DatagramPacket dp = new DatagramPacket(bytes, length, InetAddress.getByName(ip), port);
                ds.send(dp);
            }
        }catch (Exception e ){
            e.printStackTrace();
        }finally {
            if (ds!=null){
                ds.close();
            }
        }

    }
}

 服务器:

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

public class ChatRoomServer implements Runnable {
    private int port;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(port);
            byte[] bytes = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            System.out.println("服务端已经启动,坐等接收数据");
            while (true){
                ds.receive(dp);
                InetAddress address = dp.getAddress();
                byte[] data = dp.getData();
                int length = dp.getLength();
                String s = new String(data, 0, length);
                if("exit".equals(s)){
                    System.out.println("数据接收完毕");
                    break;
                }
                System.out.println("服务端"+address+"接受了"+s);
                System.out.println("再次输入你要发送的数据");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (ds!=null){
                ds.close();
            }
        }

    }
}

两个Main方法,代表两个用户:

public class ChatRoomMain {
    public static void main(String[] args) {

        ChatRoomServer crs = new ChatRoomServer();
        crs.setPort(10086);

        ChatRoomClient crc = new ChatRoomClient();
        crc.setIp("192.168.43.104");
        crc.setPort(10087);

        Thread t1 = new Thread(crs);
        Thread t2 = new Thread(crc);

        t1.start();
        t2.start();

    }
}

/*********************************************************/

public class ChatRoomMain2 {
    public static void main(String[] args) {

        ChatRoomServer crs = new ChatRoomServer();
        crs.setPort(10087);

        ChatRoomClient crc = new ChatRoomClient();
        crc.setIp("192.168.43.104");
        crc.setPort(10086);

        Thread t1 = new Thread(crs);
        Thread t2 = new Thread(crc);

        t1.start();
        t2.start();

    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值