网络编程学习笔记(二)UDP协议及聊天小程序的实现

来源:互联网 发布:windows 10 ltsb iso 编辑:程序博客网 时间:2024/05/16 21:07

UDP协议是传输层协议,它是无连接,不保证可靠的传输层协议。那么如果要进行发送端和接收端的通讯应该如何进行?

两个基本概念:

1.Socket 套接字

  • Socket就是为网络服务提供的一种机制
  • 网络通信其实就是Socket间的通信
  • (网络想要进行通信需要两个端点)数据在两个Socket间通过IO传输

2.UDP传输(Java中建立了一些对象对UDP进行封装,方便我们进行操作)

  • DatagramSocket 此类用来发送和接收数据报包的套接字
  • DatagramPacket 此类表示数据报包,数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证,因此是不可靠的。(构造参数中带有地址信息的DatagramPacket对象是用来发送数据报包的)

UDP协议-发送端

创建UDP传输的发送端
(1)建立UDP的Socket服务
(2)将要发送的数据封装到数据包中
(3)通过UDP的Socket服务将数据包发送出去
(4)关闭Socket服务

public class UDPSendDemo {    public static void main(String[] args) throws IOException {        System.out.println("发送端启动");        //1.udpsocket服务,使用DatagramSocket对象        DatagramSocket ds = new DatagramSocket();        //2.将要发送的数据装到数据包中        String str = "udp传输演示";        //使用DatagramPacket将数据封装到该对象包中        byte[] buf = str.getBytes();        /*        构造方法:        DatagramPocket(byte[] buf,int length,InetAddress address,int port):        构造数据包,用来将长度为length的包发送到指定主机上的指定端口号。        端口号在0-65535之间即可,尽量避免0-1024,避免与系统冲突         */        DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);//10000为目的端口号        //3.通过UDP的Socket服务,将数据包发送出去        ds.send(dp);        ds.close();    }}

UDP协议-接收端

建立UDP接收端的思路
(1)建立UDP Socket服务,因为要接收数据,必须要明确一个端口号
(2)创建数据包,用于存储接收到的数据,方便用数据包对象的方法解析这些数据
(3)使用Socket服务的receive方法,将接收到的数据存储到数据包中
(4)通过数据包的方法解析数据包中的数据
(5)关闭资源

public class UDPReceDemo {    public static void main(String[] args) throws IOException {        System.out.println("接收端启动");        //1.建立UDP Socket服务        //构造数据报套接字并将其绑定到本地主机上任何可用的端口。套接字将被绑定到通配符地址,IP地址由内核来选择        DatagramSocket ds = new DatagramSocket(10000);        //2.创建数据包        byte[] buf = new byte[1024];        DatagramPacket dp = new DatagramPacket(buf,buf.length);        //3.使用接收方法将数据存储到数据包中        ds.receive(dp);//阻塞式的        //4.通过数据包对象的方法,解析其中的数据,比如地址,端口,数据内容        String ip = dp.getAddress().getHostAddress();//dp.getAddress()是获取IP地址对象        int port = dp.getPort();//注意,此处的端口指的不是本地端口,而是指发送源的端口,即由谁发送来的        String text = new String(dp.getData(),0,dp.getLength());//用于存储的buf数组是1024大小,但是实际可能很小,因此将其有效位变为字符串返回        System.out.println(ip+":"+port+":"+text);        //5.关闭资源        ds.close();    }}

运行结果

这里写图片描述

这里写图片描述

注意:62086指的是源端口号,即由哪个端口发送过来的

聊天小程序

为了使聊天内容在同一窗口显示,我们在这里使用多线程技术,让接收和发送分别在不同线程进行运行:

这里写图片描述

发送端

为了达到键盘输入的目的,我们这里使用BufferedReader,通过设置特殊字符串来判断是否截止,例如这里使用的“over”

public class Send implements Runnable {    private DatagramSocket ds;    public Send(DatagramSocket ds){        this.ds = ds;    }    @Override    public void run(){        try{            BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));            String line = null;            while ((line=bufr.readLine())!=null) {                //使用DatagramPacket将数据封装到该对象包中                byte[] buf = line.getBytes();                DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10001);                ds.send(dp);                if ("over".equals(line))                    break;//注意此时over已经发送出去            }            ds.close();        }catch(Exception e){        }    }}

接收端

public class Rece implements Runnable{    private DatagramSocket ds;    public Rece(DatagramSocket ds){        this.ds = ds;    }    @Override    public void run(){        try{            while (true){                //2.创建数据包                byte[] buf = new byte[1024];                DatagramPacket dp = new DatagramPacket(buf,buf.length);                //3.使用接收方法将数据存储到数据包中                ds.receive(dp);//阻塞式的                //4.通过数据包对象的方法,解析其中的数据,比如地址,端口,数据内容                String ip = dp.getAddress().getHostAddress();//dp.getAddress()是获取IP地址对象                int port = dp.getPort();//注意,此处的端口指的不是本地端口,而是指发送源的端口,即由谁发送来的                String text = new String(dp.getData(),0,dp.getLength());//用于存储的buf数组是1024大小,但是实际可能很小,因此将其有效位变为字符串返回                System.out.println(ip+":"+port+":"+text);                if (text.equals("over")){                    System.out.println(ip+"...退出聊天室");                }            }        }catch(Exception e){        }    }}

主程序

public class ChatDemo {    public static void main(String[] args) throws SocketException {        DatagramSocket send = new DatagramSocket();        DatagramSocket rece = new DatagramSocket(10001);//注意发送端可以不指定端口,但是接收端必须指定端口        new Thread(new Send(send)).start();        new Thread(new Rece(rece)).start();    }}

这里写图片描述

由于地址使用的是127.0.0.1为本地主机地址,因此只实现了本地单向的一个功能,那么如何实现局域网内群聊的功能?

只要改变这个ip地址就可以了,以如下c类地址(有三个字节的网络号字段,最前面的3位是(110),还有21位可以进行分配)举例:

这里写图片描述

子网掩码3个255代表IP地址中的192.168.1为网络位,即代表当前所处的192.168.1这个网络,后面一位是ip地址位,从0到255,其中0不能使用,其代表网络位,即192.168.1网段;255代表广播地址,如为192.168.1.255,则会将信息发送到192.168.1网段的所有机器上,因此使用255即可实现局域网内的群聊功能,将上述程序中的127.0.0.1改为192.168.1.255即可。

阅读全文
2 0
原创粉丝点击