通过java程序实现网络之间的数据传输 底层基于网络来传输的流
网路模型
IP地址:确定再网络中的位置 ipv4 由4位0-255之间的数组成的--192.168.0.1 ipv6
端口:计算机和外部进行数据交互的媒介---端口号(0-65535 16位二进制数) 0-1023这些端口号大部分被
我们的系统占用了紧密绑定一些服务,
注册端口:1024到49151.它们松散的绑定一些服务
动态和/或私有端口:从49152到65535,这些端口时应用程序使用的动态端口,应用程序一般不会主动使用这些端口
域名:给ip取得好记的名称 通过DNS中央解析器可以映射到对应的IP
一:InetAddress 类
java提供了InetAddress类来代表IP地址,InetAddress下还有2个子类:Inet4Address、Inet6Address
UDP: 底层基于流,底层是通过数据包来进行数据的传输,数据包大小一般不能超过64kb。不会建立连接(不检测连接状态,不检测传输东西是否有用),所以对我们来说
传输数据不可靠,但是传输速度快。使用场景 :视频聊天
创建UDP数据连接采用的类是 DatagramSocket(实现类) Datagrampacket(数据包类)
发送端:
1.创建套接字对象
2.创建需要发送的数据包(指定要发送的数据长度以及ip地址和端口号)
3.发送数据包
4.关流
public class UDPSenderDemo { public static void main(String[] args) throws IOException { //UDP传输的发送端 //创建套接字的对象 -------指定要传输的IP和端口 DatagramSocket ds=new DatagramSocket(); //创建一个待传输的数据包 //因为是通过数据包传输的,所以IP地址我只要给数据包指定就好 //第一个参数是用传输的数据的字节数组 //第二个参数真正要发送的数据长度(最大和byte数组长度一致) //第三个参数指明要传输的IP地址和端口 DatagramPacket dp=new DatagramPacket("你好".getBytes(), "你好".getBytes().length,new InetSocketAddress("127.0.0.1", 8009)); //发送数据包 ds.send(dp); //关流 -----底层字节流 ds.close(); } }
接收端
1.创建套接字对象(绑定具体的端口号)
2.创建需要接收的数据包(指定真实接收数据的长度)
3.接收数据包
4.关流
5.解析数据包
public class UDPReceiverDemo { public static void main(String[] args) throws IOException { //创建接收端套接字对象 //接收端的套接字的话就是要采用含端口的构造方法,因为不管什么IP地址发送给我数据,我都是通过端口来交互数据 DatagramSocket ds=new DatagramSocket(8009); //创建数据包用于接收数据 //第二个参数代表实际接收数据的长度,可以设置的小一点 DatagramPacket dp=new DatagramPacket(new byte[1024], 1024); //接收数据把数据放置在数据包中 ds.receive(dp); //关流 ds.close(); //解析数据包 //dp.getData() --获取数据---字节数组 //dp.getLength()--获取数据的长度 System.out.println(new String(dp.getData(),0,dp.getLength())); //获取IP地址和端口 System.out.println(dp.getAddress()); System.out.println(dp.getPort()); //先开启接收端 //后开启发送端 } }
案例:
1.通过UDP实现检测的聊天室(通过线程实现)
public class UDPsenderDemo2 { public static void main(String[] args) { //开启线程 new Thread(new Sender()).start(); new Thread(new Receiver()).start(); } } //发送端 class Sender implements Runnable{ //声明对象 DatagramSocket ds; Scanner sc; @Override public void run() { // TODO Auto-generated method stub //对象初始化 try { ds=new DatagramSocket(); sc=new Scanner(System.in); while(true) //保证一直发送数据 { //录入数据 byte[]bs=sc.nextLine().getBytes(); //创建发送的数据包 DatagramPacket dp=new DatagramPacket(bs,bs.length,new InetSocketAddress("127.0.0.1",8090)); //发送数据包 ds.send(dp); } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //接收端 class Receiver implements Runnable{ DatagramSocket ds; DatagramPacket dp; @Override public void run() { //对象初始化 try { ds=new DatagramSocket(8090); dp=new DatagramPacket(new byte[1024],1024); } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); } while(true) { try { //接收数据包 ds.receive(dp); //解析数据包 System.out.println(new String(dp.getData(),0,dp.getLength())); System.out.println(dp.getAddress()); System.out.println(dp.getPort()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }} } }
TCP:底层基于流:建立连接。可靠,传输速度慢
TCP通过字节流直接传输数据不需要数据包,就没有传输数据的限制
适用场景:传输文件,和下载电影等
客户端(Socket)
1.创建TCP客户端对象
2.发起链接(指明要发送的IP和端口)
3.获取自带的字节输出流
4.根据自带的字节流往服务器端写出数据
5.通知服务器已经写完、关流
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; public class TCPClientDemo { public static void main(String[] args) throws IOException { //创建TCP套接字对象 Socket s=new Socket(); //发起链接---指定链接的IP和端口 s.connect(new InetSocketAddress("127.0.0.1",9008)); //connect会有阻塞 //获取套接字对象自带的字节输出流 //写出的数据默认往服务器写 OutputStream os=s.getOutputStream(); //通过自带的字节输出流写数据 os.write("服务器你好。。。".getBytes()); //通知服务器数据已写完 s.shutdownOutput(); //获取自带字节输入流 InputStream in =s.getInputStream(); //读取数据 byte[]bs=new byte[1024]; int len=-1; while((len=in.read(bs))!=-1) { System.out.println(new String(bs,0,len)); } //通知服务器已经读取完成 s.shutdownInput(); //关流 os.close(); } }
服务器端(ServiceSocket)
1.创建TCP服务器端对象。绑定端口
2.接收链接
3.获取自带的字节流
4.通过自带的字节流进行数据读取
5.通知客户端已经读取完成、关流
6关流
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TCPServiceDemo { public static void main(String[] args) throws IOException { //创建一个TCP服务器端对象---绑定端口 ServerSocket ss=new ServerSocket(9008); //接收链接,为什么呢因为Socket有自带的InputStream System.out.println("接收"); Socket s=ss.accept(); //阻塞 System.out.println("接收完成"); //读取传过来的数据 //获取自带的输入流 InputStream in=s.getInputStream(); //自建缓冲区 byte[]bs=new byte[1024]; int len=-1; while((len=in.read(bs))!=-1) { System.out.println(new String(bs,0,len)); } //通知客户端数据以读完 s.shutdownInput(); //获取一个自带的字节输出流 OutputStream os =s.getOutputStream(); //往客户端写出数据 os.write("你也好".getBytes()); //通知客户端已经写完 s.shutdownOutput(); in.close(); } }
用TCP实现客户端上传文件,服务端复制文件
客户端
package cn.tedu.inernet.tcp; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; public class TCPFileCopyClient { public static void main(String[] args) throws IOException { //创建TCP客户端对象 Socket s=new Socket(); //发起链接 s.connect(new InetSocketAddress("127.0.0.1", 9009)); //文件类对象 File file=new File("D:\1.mp4"); //把外部文件读取进来 FileInputStream fis=new FileInputStream (file); //获取自带输出流 OutputStream os=s.getOutputStream(); //获取文件名称 //先传文件名长度 os.write(file.getName().getBytes().length-128);//文件名长度值 //传文件名内容 os.write(file.getName().getBytes()); byte[] bs=new byte[1024*1024*10]; int len=-1; while((len=fis.read(bs))!=-1){ //往服务器端写数据 os.write(bs,0,len); } //通知服务器端已写完 s.shutdownOutput(); //关流 os.close(); fis.close(); } }
服务端
package cn.tedu.inernet.tcp; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class TCPFileCopyServer { public static void main(String[] args) throws IOException { //获取TCP服务器端的对象---绑定端口 ServerSocket ss=new ServerSocket(9009); //接收链接 Socket s=ss.accept(); //获取自带字节输入流---读取客户端发来的数据 InputStream in=s.getInputStream(); //接收文件名长度值 byte length=(byte)in.read(); //新建字节数组 byte[] bts=new byte[length+128]; //按照这个字节数组读取文件名内容 in.read(bts);//字节数组里存满了文件名内容 //创建文件字节输出流对象 FileOutputStream fos=new FileOutputStream(new File("D:\javase\"+new String(bts))); byte[] bs=new byte[1024*1024*10]; int len=-1; while((len=in.read(bs))!=-1){ //往外部文件写数据 fos.write(bs, 0, len); } //通知客户端已经读取完毕 s.shutdownInput(); //关流 in.close(); fos.close(); } }