udp和tcp
2018-06-30 18:28 yelena 阅读(149) 评论(0) 编辑 收藏 举报网络通信协议
tcp/ip协议:包括TCP协议和IP协议,UDP协议和其它一些协议的协议组
层次结构:应用层---传输层---网络层---链路层
ip地址:唯一标识一台计算机
ipv4版本:4个字节的二进制数表示(一共4个字节,一个字节有8位,用0和1表示),转换成十进制后就是常见的形式,127.0.0.1
端口:通过ip地址找到 计算机,然后通过端口号来找到指定的应用程序
inetaddress类:封装一个ip地址,包含主机名
构造方法
getbyname():静态方法,需要传一个字符串表示的ip地址,返回一个inetaddress对象
getlocalhost():静态方法,空参,返回本地主机的inetaddress对象
方法
gethostname():空参,返回表示此ip地址的主机名的字符串
gethostaddress():空参,返回表示ip地址的字符串
InetAddress inet = InetAddress.getLocalHost(); //System.out.println(inet); // String[] str = inet.toString().split("/"); // for(String s:str){ // System.out.println(s); // } //System.out.println(inet.getHostName()); //System.out.println(inet.getHostAddress()); InetAddress inet1 = InetAddress.getByName("123-pc"); System.out.println(inet1);
udp协议:无连接通信协议,数据传输时,数据的发送端和接收端不建立逻辑连接
占用资源小,通信效率高,视频、音频和普通数据的传输,丢包不会对结果产生太多影响
传输重要数据不适用udp
数据大小被限制在64k以内
tcp协议:面向连接的通信协议,传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,提供了两台计算机之间可靠无差错的数据传输
面向连接的特效,保证了数据传输的安全性(完整性),下载文件时采用tcp协议
udp的使用
datagrampocket类:用来打包用户的数据,相当于集装箱
getaddress():返回一个inetaddress对象
getport():返回端口号
getlength():用来获取数据的大小
datagramsocket类:用来传输集装箱,相当于码头
send():发送数据
receive():接收数据
发送端:使用datagrampocket类四个参数的构造方法;使用datagramsocket类的空参构造(不需要指定端口号,系统自动分配一个没被占用的端口号)
接收端:使用datagrampocket类两个参数的构造方法;使用datagramsocket类的有参构造(指定端口号,可以监听指定的端口号)
byte[] bytes = "你好".getBytes(); InetAddress inet = InetAddress.getLocalHost(); DatagramPacket dp = new DatagramPacket(bytes, bytes.length, inet, 8000); DatagramSocket ds = new DatagramSocket(); ds.send(dp); ds.close();
DatagramSocket ds = new DatagramSocket(8000); byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); ds.receive(dp); int len = dp.getLength(); String ip = dp.getAddress().getHostAddress(); int port = dp.getPort(); System.out.println(ip+"..."+port+"..."+new String(bytes,0,len)); ds.close();
tcp的使用
客户端:scocket
构造方法:有参构造,传入一个表示服务器端ip地址的字符串和端口号
方法:getinputstream()获得输入流;getoutputstream()获得输出流
不需要自己去创建流,用方法调用
服务器端:serversocket
构造方法:有参构造,传入端口号
方法:accept()获得一个socket对象,调用其方法
Socket socket = new Socket("127.0.0.1", 8888); OutputStream out = socket.getOutputStream(); FileInputStream fis = new FileInputStream("d:\\12\\123.jpg"); int len =0; byte[] bytes = new byte[1024]; while((len=fis.read(bytes))!=-1){ out.write(bytes, 0, len); } socket.shutdownOutput(); InputStream in = socket.getInputStream(); len = in.read(bytes); System.out.println(new String(bytes,0,len)); fis.close(); socket.close();
ServerSocket server = new ServerSocket(8888); Socket socket = server.accept(); InputStream in = socket.getInputStream(); File upload = new File("d:\\12\\upload"); if(!upload.exists()){ upload.mkdirs(); } String filename = "oracle"+System.currentTimeMillis()+new Random().nextInt(9999)+".png"; FileOutputStream fos = new FileOutputStream(upload+File.separator+filename); byte[] bytes = new byte[1024]; int len =0; while((len=in.read(bytes))!=-1){ fos.write(bytes, 0, len); } OutputStream out = socket.getOutputStream(); out.write("上传成功".getBytes()); fos.close(); socket.close(); server.close();
服务器端多线程:
public class Upload implements Runnable { private Socket socket; private FileOutputStream fos; public Upload(Socket socket){ this.socket = socket; } @Override public void run() { // TODO Auto-generated method stub try{ InputStream in = socket.getInputStream(); File upload = new File("d:\\12\\upload"); if(!upload.exists()){ upload.mkdirs(); } String filename = "oracle"+System.currentTimeMillis()+new Random().nextInt(9999)+".png"; fos = new FileOutputStream(upload+File.separator+filename); byte[] bytes = new byte[1024]; int len =0; while((len=in.read(bytes))!=-1){ fos.write(bytes, 0, len); } OutputStream out = socket.getOutputStream(); out.write("上传成功".getBytes()); }catch(Exception e){ e.printStackTrace(); }finally{ try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
ServerSocket server = new ServerSocket(8888); while (true) { Socket socket = server.accept(); Upload upload = new Upload(socket); Thread thread = new Thread(upload); thread.start(); }
类加载
类未被加载到内存中,系统通过加载,连接,初始化三步对此类进行初始化
加载:把class文件加载到内存中,并生成一个class文件
连接:1、验证,验证类的内部结构,并与其它类协调;2、准备,为静态成员分配内存,并赋值;3、解析,将二进制的符号引用变成直接引用
初始化:学过的
类初始化时机:1、创建类的对象;2、给静态成员变量赋值;3、使用静态方法;4、反射;5、初始化某个类的对象;6、直接java.exe来运行某个类
类的加载器:根类加载器 扩展类加载器 系统类加载器
反射
在java中,动态获取信息及动态调用对象方法的功能叫做反射机制
class类
构造方法:没有,只能通过方法获得对象
1、某类的对象调用getclass()方法
2、类名直接调用class静态成员变量
3、class.forname(),传入一个字符串,可以和properties文件一起使用
Person p = new Person(); // Class c = p.getClass(); // System.out.println(c); // Class c1 = Person.class; // System.out.println(c1); // System.out.println(c==c1); // System.out.println(c.equals(c1)); // Class c2 = Class.forName("com.oracle.demo02.Person"); // System.out.println(c2);
方法:
constructor:表示构造方法
field:表示成员变量
method:表示成员方法
declared:可以获得私有和公有的所有方法
setAccessible():允许对私有化的成员进行修改,暴力反射中的
constructor中的newinstance()方法,返回的是一个obj类型的对象,如果需要使用本类的方法,需要强转
//反射获取空参构造 Class c = Class.forName("com.oracle.demo02.Person"); //获取所有的公共构造方法 // Constructor[] con = c.getConstructors(); // for(Constructor c1:con){ // System.out.println(c1); // } Constructor con = c.getConstructor(); //Object obj = con.newInstance(); Person p = (Person)con.newInstance(); p.work("zhangsan"); //System.out.println(obj);
//获取有参构造 Class c = Class.forName("com.oracle.demo02.Person"); Constructor con = c.getConstructor(String.class,int.class); System.out.println(con); Object obj = con.newInstance("zhangsan",18); System.out.println(obj);
//快速获取空参构造方法并创建对象 // Class c = Class.forName("com.oracle.demo02.Person"); // Object obj = c.newInstance(); // System.out.println(obj); //获取私有的构造方法 //暴力反射,破坏了程序的封装性和安全性 Class c = Class.forName("com.oracle.demo02.Person"); // Constructor[] con = c.getDeclaredConstructors(); // for(Constructor cc:con){ // System.out.println(cc); // } Constructor con = c.getDeclaredConstructor(int.class,String.class); //System.out.println(con); con.setAccessible(true); Object obj = con.newInstance(18,"zhangsan"); System.out.println(obj); }
//通过反射获取成员变量并改值 Class c = Class.forName("com.oracle.demo02.Person"); Object obj = c.newInstance(); // Field[] fields = c.getFields(); // for(Field f:fields){ // System.out.println(f); // } Field field = c.getField("name"); Field field1 = c.getDeclaredField("age"); //System.out.println(field); field.set(obj, "zhangsan"); field1.setAccessible(true); field1.set(obj, 25); System.out.println(obj); }
//获取所有公共的方法,包括继承来的 // Method[] m = c.getMethods(); // for(Method mm:m){ // System.out.println(mm); // } Method method = c.getMethod("eat"); System.out.println(method); method.invoke(c.newInstance());
//获取有参方法并运行 Class c = Class.forName("com.oracle.demo02.Person"); Method method = c.getMethod("work", String.class); method.invoke(c.newInstance(), "zhangsan");
泛型擦除
有泛型的类,在程序进行编译后生成的class文件中,没有泛型约束,这叫做泛型擦除
//有一个ArrayList<String> list //然后往里面添加int类型数据 //泛型擦除,字节码文件中没有泛型 ArrayList<String> arr = new ArrayList<String>(); arr.add("abc"); Class c = arr.getClass(); Method addd = c.getMethod("add", Object.class); addd.invoke(arr, 1); for(Object o:arr){ System.out.println(o); }
反射配置文件
//类不清楚,方法也不清楚 //通过配置文件去实现,运行类名和方法名已键值对的形式 //保存到properties中,具体运行哪个类里面的方法通过改配置文件去设置 //1.准备配置文件,写好键值对 //2.IO读取配置文件reader //3.文件中的键值对存储到集合中,集合中保存的键值对就是类名和方法名 //4.反射获取指定类的class文件对象 //5.class文件对象获取指定方法 //6.运行方法 //Person p = new Person(); //p.eat(); FileReader fr = new FileReader("config.properties"); Properties pro = new Properties(); pro.load(fr); fr.close(); String className = pro.getProperty("className"); String methodName = pro.getProperty("method"); Class c = Class.forName(className); Object obj = c.newInstance(); Method method = c.getMethod(methodName); method.invoke(obj);