(99)网络编程:IP地址类、DatagramSocket(UDP)、DatagramPacket

一、网络通讯要素
①找到对方IP
②端口:数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以要给这些网络应用程序都用数字进行标识,为了方便称呼这个数字,叫做端口(逻辑端口)
下图主要看本地端口
这里写图片描述
web服务:80 tomat:8080 mySql:3306
③定义通信规律,这个通讯规则称为协议。
国际组织定义了通讯协议:TCP\IP

这里写图片描述

二、IP地址:InetAddress对象
IP地址:
网络中设备的标识、
不易记忆,可用主机名
本地回环地址:127.0.0.1主机名:localhost

 InetAddress ia=InetAddress.getLocalHost();//返回本地地址

         System.out.println(ia.toString());//返回地址字符串+主机名
         System.out.println(ia.getHostAddress());//获取此IP地址字符串
         System.out.println(ia.getHostName());//获取此IP地址的主机名

         InetAddress i=InetAddress.getByName("www.baidu.com");//给主机名返回IP地址
         System.out.println(i.getHostAddress());

三、端口号
用于标识进程的逻辑地址,不同进程的标识
有效端口:0-65535,其中0-1024系统使用或保留端口
四、传输协议特点
UDP特点:
①将数据及源和目的封装成数据包中,不需要建立连接
②每个数据报的大小在限定的64k内
③因无连接,是不可靠的协议
④不需要建立连接,速度快
应用:聊天工具(QQ)、网络视频会议、桌面共享
TCP特点:
①建立连接,形成传输数据的通道
②在连接中进行大数据量传输(不用封包)
③通过三次握手完成连接,是可靠协议
④必须建立连接,效率低
应用:下载
五、网络编程Socket
就是为网络服务提供 的一种机制
通讯的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
①UDP
DatagramSocket:此类表示用来发送和接收数据报 的套接字
因为要封装成包,而包又比较复杂,所以将此包封装承对象DatagramPacket
在方法中只要参数带InetAddress就是发送端的,该地址是目的地址。
需求:通过udp传输方式,将一段文字发送出去(发送端)
思路:
1,建立udpsocket服务
2,提供数据,并将数据封装承包
3,通过socket服务的发送功能,将数据包发送出去
4,关闭资源

public static void main(String[] args)throws Exception {
        //1,创建udp服务,通过DatagramSocket对象
        DatagramSocket ds=new DatagramSocket();

        //2,确定数据,并封装成数据包DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
         byte[]buf="udp hahah".getBytes();
         DatagramPacket dp=new   DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10000);

         //3,通过socket服务,将已有的数据发送出去,通过send方法
         ds.send(dp);

         //关闭资源
         ds.close();

    }

需求:定义一个应用程序,用于接收udp协议传输的数据并处理(接收端)
思路:
1,定义udpsocket服务,通常会监听一个端口,其实就是给这个接收网络应用程序定义一个数字表示,方便哪个应用程序进行处理
2,定义一个数据包,因为要存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息
3,通过socket服务的receive方法将接收的数据存入已经定义好的数据包中
4,通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上
5,关闭资源

import java.net.*;
public class udpReceive {

    public static void main(String[] args)throws Exception {
        System.out.println("接收端开启***********************");
        //1,创建udp socket,建立端点
        DatagramSocket ds=new DatagramSocket(10000);

        //2,定义数据包,用于存储数据
        byte[] buf=new byte[1024];
        DatagramPacket dp=new DatagramPacket(buf,buf.length);

        //3,通过服务的receive方法接收数据存入数据包中
        ds.receive(dp);//阻塞式方式

        //4,通过数据包的方法获取其中的数据
        InetAddress ia=dp.getAddress();//获取IP地址
        String ip=ia.getHostAddress();
        String data=new String(dp.getData(),0,dp.getLength());
        int port=dp.getPort();

        System.out.println(ip+"---"+data+"---"+port);

        //5,关闭资源
        ds.close(); 
    }

}
//Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
//接收端监听端口,这个端口不能是已经被其他应用程序占用的,否则会抛出此异常↑
//注意以上两个应用程序,第一个是发送端,第二个是接收端,因为是无连接形式,所以在eclipse中要先开启接收端

需求:发送端通过键盘键入,输入一行就发送给接收端,接收端一直开启while(true)

public class send {

    public static void main(String[] args)throws Exception {

        DatagramSocket ds=new DatagramSocket();

        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
        String line=null;
        while((line=bufr.readLine())!=null)//也不会造成死循环,因为readline中也调用read()方法,
        //该方法是阻塞方法,键盘没输入就等待
        {
            if("886".equals(line))
                break;

            byte[] buf=line.getBytes();
            DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.103"),10001);
            ds.send(dp);

        }
        ds.close();

    }

}


public class receive {

    public static void main(String[] args)throws Exception {
        DatagramSocket ds=new DatagramSocket(10001);
        while(true) //不会造成死循环,因为receive是阻塞式方法,若发送方不发送数据,则阻塞在该处
        {
            byte[] buf=new byte[1024];
            DatagramPacket dp=new DatagramPacket(buf,buf.length);
            ds.receive(dp);

            InetAddress ia=dp.getAddress();
            String ip=ia.getHostAddress();
            String data=new String(dp.getData(),0,dp.getLength());

            System.out.println(ip+":::"+data);
            //将关闭去掉,只要发送端想连,就发,就能接收
        }


    }

}

编写一个聊天程序,有收数据的部分,和发数据的部分,这两部分需要同时执行。那就需要用到多线程技术。
一个线程控制收,一个线程控制发。因为收和发动作不一致,所以要定义两个run方法,相应的应该定义在两个类中

//发送端
import java.io.*;
import java.net.*;

public class send implements Runnable{

    private DatagramSocket ds;
       send(DatagramSocket  ds){
           this.ds=ds;
       }
       public void run() {

           BufferedReader bufr=new BufferedReader(new InputStreamReader( System.in));
           String line=null;
           try {
            while((line=bufr.readLine())!=null) {

                if("886".equals(line))
                    break;
                byte[] buf=line.getBytes();
                DatagramPacket dp=new DatagramPacket(buf,0,buf.length,InetAddress.getByName("192.168.1.255"),10003);
                ds.send(dp);


               }
            bufr.close();
        } catch (IOException e) {

            throw new RuntimeException("读取失败");
        }
       }
}
//接收端
import java.io.*;
import java.net.*;
public class rece implements Runnable {
    DatagramSocket  ds;
    rece(DatagramSocket ds){
        this.ds=ds;
    }

    public void run() {
        byte[] buf=new byte[1024];
        DatagramPacket dp=new DatagramPacket(buf,buf.length);

        try {
            while(true) {

            ds.receive(dp);
            String ip=dp.getAddress().getHostAddress();
            String data=new String(dp.getData(),0,dp.getLength());
            System.out.println(ip+"::"+data);
            }   
        } catch (IOException e) {

            throw new RuntimeException("无法获取");
        }

    }

}
//主方法
import java.net.*;
public class demo {
    public static void main(String[] args)throws Exception {
        DatagramSocket ds1=new DatagramSocket();
        DatagramSocket ds2=new DatagramSocket(10003);
        new Thread(new send(ds1)).start();
        new Thread(new rece(ds2)).start();

    }

}
posted @ 2017-07-28 14:04  测试开发分享站  阅读(363)  评论(0编辑  收藏  举报