网络基础
IP IPV4(4个字节 32位) IPV6
特殊IP
192.168.0.0至192.168.255.255 内网IP
127.0.0.1 本地IP
域名(主机名)
DNS服务器解析
本地域名localhost(字符串)
InetAddress 此类表示IP地址
方法(无构造器)
静态方法 getByname(主机名) 根据主机名返回对应的InetAddress类
getByAddress(byte[ ]) 根据byte格式IP创建InetAddress类
getLocalHost() 返回本地主机的InetAddress类
成员方法 getHostAddress() 获取字符串的IP地址
getHostName 获取字符串的本地主机名
端口 区分不同的软件
0-65535个端口(2个字节)
自定义端口至少大于8000
常见端口 8000 预留端口号
80 http协议
8080 tomcat
1521 Oracle
3306 mysql
InetSocketAddress 此类实现IP套接字地址(IP+端口号)
构造器
InetSocketAddress(InetAddress,int port) 指定IP类和端口
InetSocketAddress(int port) 指定端口并默认IP地址
InetSocketAddress(主机名, int port) 指定主机名和端口
成员方法
getHostName() 获取主机名
getPort() 获取端口
getAddress() 获取InetAddress对象格式的IP地址
URL 统一资源定位符 区分不同的资源
协议 域名 端口 资源
路径 文件名 锚点
URL类
构造器
URL(String) 根据绝对路径直接创建
URL(String protocol, String host, int port, String file)将协议,域名,端口,资源依次导入
方法
get getAuthority() 获取字符串格式的路径
getProtocol() 获取协议
getHost() 获取主机名
getPort() 获取端口
getFile() 获取字符串的资源路径
getPath() 获取url的路径部分(文件名与端口之间的路径)
getQuery() 获取查询部分(文件名)
getRef() 获取锚点(引用)
套接字Socket:
在java中只关注传输层为应用层之间传输代码
套接字Socket是传输层为应用层开的通道,不同协议对于Socket的实现是不同的
互联网三大基石http/html/url
UDP协议数据传输
单向高效发送但不安全
非面向连接的 只管发送,不安全 开销小,效率高 传输大小有限制(60k) 底层基于字节数组
通过DatagramSocket类创建连接通过DatagramPacket对文件进行拆装箱
DatagramSocket用来发送和接收数据报包的套接字
构造器
DatagramSocket(端口号) 创建连接并绑定到本机的指定端口上
DatagramSocket(端口号,InetAddress) 根据端口和IP类绑定
DatagramSocket(InetSocketAddress) 根据(端口+IP)类绑定
方法
receive(DatagramPacket) 阻塞式接收 并将接收文件保存在打包类的对象中
send(DatagramPacket) 发送打包类的对象
close()
DatagramPacket
构造器
发送端 传入参数为发送的数组,起始索引,长度,以及目标
其中起始起始索引可省略, 目标可以是InetAddress和InetSocket格式
DatagramPacket(byte[], 起始索引, 长度, 目标InetAddress, 目标端口)
接收端 传入参数为 接收数组 起始索引(可省略) 长度
DatagramPacket(byte[],int,int)
方法
getlength() 返回包中的数组的长度
getOffset() 返回包中数组的起始索引
实例(数据打包和数据收发可以循环)
接收端 定义接收端--准备字节数组--打包准备接收--接收(阻塞式)—拆包处理--关闭
//定义接收端 DatagramSocket get=new DatagramSocket(8888); //准备接收数组 byte[] arr=new byte[1024]; //接收打包 DatagramPacket packet=new DatagramPacket(arr,0,arr.length); //文件大可执行循环 while(true){ //接收数据包 get.receive(packet); //处理数据包 可以通过IO流将数据转存至本地 byte[] arr2=packet.getData(); int a =packet.getLength(); System.out.println(new String(arr2,0,a)); if(a<arr.length)break; } get.close(); |
发送端 定义发送端—准备数据—打包数据—数据发送—关闭
//定义输出端 DatagramSocket send =new DatagramSocket(8888,InetAddress.getLocalHost()); //准备数据 byte[] arr=new String("你好").getBytes(); //数据打包 DatagramPacket packet=new DatagramPacket(arr,0,arr.length,new InetSocketAddress("localHost",8888)); //数据发送 send.send(packet); send.close(); |
TCP协议数据传输
基于面向连接的 基于io流传输 较udp更为安全但占用资源多,开销大,效率低
三次握手包括1.请求2.回应3.传输
Socket 实现客户端的套接字
构造器 Scoket(InetAddress ,port) 指定IP类与端口
Scoket(String host,poer) 指定主机名和端口
方法 getOutputStream() 获取字节输出流
getInputStream() 获取字节输入流
ServerScoket 实现服务器端的套接字
构造器 ServerSocket(port) 指定端口
方法 accept() 监听并接受Socket套接字
close()
客户端
定义客户端—准备数据—创建输出流—输出数据—创建接收流—接收数据—刷出关闭
注意:创建流可以套接各种功能流(缓冲流,字符流,转换流等)
//定义客户端 Socket client =new Socket("localhost",8888);//指定目标主机和端口 //准备数据 String s="呵呵"; byte[] arr1=s.getBytes(); //根据Socket创建输出流 OutputStream out=client.getOutputStream(); //数据输出 out.write(arr1); //根据Socket创建输入流 InputStream in=client.getInputStream(); //准备接收容器 byte[] arr2=new byte[1024]; //数据接收 in.read(arr2); //数据处理 System.out.println(new String(arr2)); //刷出和关闭 in.close(); out.flush(); out.close(); client.close(); |
服务器端
定义服务器—获取客户端—获取客户端输入(出)流—接收(发送)数据
通过接口获取输入流和输出流分别执行输入输出操作
//定义服务器 ServerSocket server=new ServerSocket(8888); //从监听获取客户端 Socket target=server.accept(); //从监听客户端获取输入流(可以增加功能流) InputStream in=target.getInputStream(); //准备接收数组 byte[] arr=new byte[1024]; //接收数据(io流可返回接收长度) int len=in.read(arr); //数据接收数据处理 System.out.println(new String(arr,0,len));
//准备写入数据 byte[] arr2="哈哈".getBytes(); //从监听客户端获取输出流(可以增加功能流) OutputStream out=target.getOutputStream(); //写出数据 out.write(arr2); //刷出及关闭 out.flush(); out.close(); in.close(); target.close(); server.close(); |
服务器端的多线程接收
1多线程前的代码
public static void main(String[] args) throws IOException { //定义服务器 ServerSocket server=new ServerSocket(9999); //获取客户端 Socket client=server.accept(); //准备获取数组 byte[] arr=new byte[1024]; //获取输入流 可以使用其他功能流(字符流,转换流等) InputStream in=new BufferedInputStream(client.getInputStream()); //接收数据 String txt=""; while(true){ int len=in.read(arr); txt.concat(new String(arr,0,len));//处理长文本数据 if(len<arr.length){ break; } } //判断数据,调用外部方法对接收的登录数据进行数据,直接返回结果 String result=loadjudgment(txt); //将结果返回客户端 //创建输出流 字节流外套缓存流外套字符转换流外套字符缓存流 Writer out1=new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(client.getOutputStream()))); out1.write(txt); //根据判断结果调用图片复制 if(result.equals("登录成功载入bug中")){ copypicture(result,client); } }
//判断登录数据的方法 static String loadjudgment(String txt){ if("程序员".equals(txt)){ return new String("登录成功载入bug中"); }else{ return new String("登录失败,我怀疑你是蔡徐坤"); } }
//图片传输进行封装的方法 static void copypicture(String result,Socket client) throws IOException{ //执行图片传输 OutputStream out2 =new BufferedOutputStream(client.getOutputStream()); //准备传输载具 InputStream localin=new FileInputStream("D:/test.jpg"); byte[] car=new byte[1024]; int x; //循环读取本地文件 while(true){ x=localin.read(car); //循环输出 out2.write(car); if(x<car.length)break; } } |
2多线程后的代码
public static void main(String[] args) throws IOException { // 定义服务器 ServerSocket server = new ServerSocket(9999); // 死循环会导致close无法执行,需要通过变量处理 boolean flag = true; while (flag) { // 获取客户端 Socket client = server.accept(); //启动多线程 new Thread(new Channel(client)).start(); //关闭连接 client.close(); } //关闭服务器 server.close(); }
// 创建多线程类 (内部类形式) 静态主方法只能调用静态内容, static class Channel implements Runnable { Socket client = null;
public Channel(Socket client) { // 构造器调入套接字 super(); this.client = client; }
// ------------------以下是多线程代码--------------------------------- @Override public void run() { // 准备获取数组 byte[] arr = new byte[1024]; String txt; try { // 获取输入流 可以使用其他功能流(字符流,转换流等) InputStream in = new BufferedInputStream(client.getInputStream()); // 接收数据 txt = ""; while (true) { int len = in.read(arr); txt.concat(new String(arr, 0, len));// 处理长文本数据 if (len < arr.length) break; } // 判断数据,调用外部方法对接收的登录数据进行数据,直接返回结果 String result = loadjudgment(txt); // 将结果返回客户端 // 创建输出流 字节流外套缓存流外套字符转换流外套字符缓存流 Writer out1 = new BufferedWriter( new OutputStreamWriter(new BufferedOutputStream(client.getOutputStream()))); out1.write(txt); // 根据判断结果调用图片复制 if (result.equals("登录成功载入bug中")) { copypicture(result, client); } in.close(); out1.flush(); out1.close(); } catch (IOException e) { e.printStackTrace(); } // IO流异常处理 } // ------------------以上是多线程代码---------------------------------
// -------------------以下是封装方法--------------------------------- // 判断登录数据的方法 String loadjudgment(String txt) { if ("程序员".equals(txt)) { return new String("登录成功载入bug中"); } else { return new String("登录失败,我怀疑你是蔡徐坤"); } }
// 图片传输进行封装的方法 void copypicture(String result, Socket client) throws IOException { // 执行图片传输 OutputStream out2 = new BufferedOutputStream(client.getOutputStream()); // 准备传输载具 InputStream localin = new FileInputStream("D:/test.jpg"); byte[] car = new byte[1024]; int x; // 循环读取本地文件 while (true) { x = localin.read(car); // 循环输出 out2.write(car); if (x < car.length) break; } out2.flush(); out2.close(); } // -------------------以上是封装方法--------------------------------- } |