网络编程

害,人和人和差别比人和猪的差别还大,我算是见识到了,大佬太多了,自己真菜狗哭了

笔记

TCP/IP四层概念模型    
应用层,http,ftp,smtp,dns    
传输层,tcp,udp     
网络层,ip    
数据链路层网络编程中有两个主要问题    
	1,如何准确定位到网络上的一台电脑,ip和端口    
	2,找到主机后如何进行通信,网络通信协议tcp/udp 
	
IP,InetAddress类使用静态方法创建对象,工具类    
	方法:        
	InetAddress address = InetAddress.getByName("keyi.world"),返回一个指定IP对象        
	address.getHostAddress(),返回主机ip地址字符串        
	address.getHostName,返回域名,或者自己电脑名称字符串
	
端口:区分计算机不同的软件,0-65535
	tcp协议和udp协议分别都有0-65535端口号,同一协议下,端口号不同相同
	端口分类:    
	公有端口:操作系统自身使用,0-1023    
	程序注册端口:用户端口,1024-49151        
		tomcat:8080        
		mysql:3306    
	动态,私有端口,49152-65535    
	查看电脑所有端口命令:netstat -ano    
	查看指定的端口命令:netstat -ano|findstr "8080"
	
udp
    udp是一种不可靠的网络协议,它在通信两端各建立一个socket对象,
    但这两个socket只是发送和接收的对象,udp不存在客户端和服务器的概念
    java提供了DatagramSocket类作为基于udp协议的socket
    udp发送端步骤:
        1,创建DatagramSocket对象
            DatagramSocket socket = new DatagramSocket();
        2,创建数据,并把数据打包,DatagramPacket,数据报包
            DatagramPacket packet = new DatagramPacket(bytes,bytes.length, 
				InetAddress.getByName("localhost"),10086);
        3,调用socket对象send方法发送数据
            socket.send(packet);
        4,关闭socket对象
            socket.close();
    udp接收端:
        1,创建DatagramSocket对象,绑定端口
            DatagramSocket socket = new DatagramSocket(10086);
        2,创建数据报包DatagramPacket,指定字节数组保存数据
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        3,调用socket对象的receive方法接收数据
            socket.receive(packet);
        4,展示数据并关闭socket
            byte[] data = packet.getData();
            System.out.println(new String(data));
            socket.close();
tcp
    tcp是可靠的网络协议,需要经过三次握手四次挥手才会建立连接
    三次握手,四次挥手:
        三次握手
        1.客户端向服务端发送请求,一次,表明自己发送能力没问题,
        2.但客户端不知道服务端有没有收到消息,所以服务端发送消息给客户端,二次,表明自己已收到消息, 
        3.客户端接收后,就知道,服务端接收能力没问题,发送能力没问题, 
            但服务端还不知道客户端有没有接收到消息,所以,客户端再次发送消息给服务端,三次, 
            表示自己已收到,证明自己接收能力没有问题
    	四次挥手
    	1.客户端发送请求给服务端,表示自己要断开连接,自己已经不会再发送数据了,
    		但如果还有数据没接收完,服务端可以继续发给我,挥手一次,
    	2.服务端收到第一次挥手后,就会发送消息给客户端,表示服务端已经知道了,
    		等我数据发送完再通知你,挥手二次, 
    	3.服务端发送完全部数据后,再次发送消息给客户端,我数据处理完了,
    		此时服务端进入等待,等待客户端发消息,挥手三次,	
    	4.客户端接收到消息,就知道,服务端已经把数据全部发给我了,此时可以断开了,
    		客户端再次发消息给服务端,彻底断开连接,挥手四次
    tcp客户端:
        1,创建socket对象,指定服务器的地址和端口号
            Socket socket = new Socket("localhost",10086);
        2,通过socke获取字节输入流/字节输出流,从而向socket中读取/写入数据
            BufferReader read = new BufferedReader(new 
            	FileReader("C:\\Users\\OneForAll\\Desktop\\IDEA快捷键.txt"));
            BufferReader reader = new BufferedReader(new 
            	InputStreamReader(socket.getInputStream()));
            BufferedWriter writer = new BufferedWriter(new 
            	OutputStreamWriter(socket.getOutputStream()));
            String data;
            while ((data= read.readLine())!=null){
                writer.write(data);
                writer.newLine();
                writer.flush();
            }
        3,关闭socket
    tcp服务端:
        1,创建服务端套接字对象,绑定端口
            ServerSocket serverSocket = new ServerSocket(10086);
        2,serverSocket对象等待接收客户端的请求从而获得socket对象,是个阻塞方法
            Socket socket = serverSocket.accept();
        3,通过socket对象获取输入输出流来传输数据
        4,关闭socket

注解
    注解Annotation是一种引用类型,编译之后也是生成xxx.class文件
    创建语法格式:
        修饰符列表 @interface 注解类型名{
        }
    使用格式:@注解类型名
    使用地方:类上,属性上,方法上,变量上,注解还可以出现在注释上
    jdk内置了哪些注解?
        java.lang包下有三个注解:
        @Deprecated,表示过时的,废弃的
        @override,表示重写的方法,标识性注解,给编译器做检查,只在编译时期起作用,跟运行期无关
        @SuppressWarnings
    元注解:修饰注解的注解就是元注解
        常见的元注解:
        Target,用来标注注解的使用范围,例如Target(ElementType.METHOD),只能出现在方法上
        Retention,用来标注注解最终保存在哪里,例如
            @Retention(RetentionPolicy.SOURCE),该注解只被保留在源文件中
            @Retention(RetentionPolicy.CLASS),该注解被保存在class文件中
            @Retention(RetentionPolicy.RUNTIME),该注解被保存在class文件中,并可以被反射机制所读取
    注解定义属性:
        public @interface MyAnnotation {
            //这是注解的name属性,如果注解有属性则使用时必须给属性赋值,除非该属性使用default指定了默认值
            String name() default "";
        }
        如果注解中只有一个属性,且属性名为value,则使用注解时,属性名可以省略
        public @interface MyAnnotation {
            //这是注解的name属性
            String name();
            int[] age();    //属性的类型可以是八大类型加上String,Class和枚举,以及他们的数组都可以
        }
        public class Test {
            //@MyAnnotation(name="Coco",age ={20,25})
            @MyAnnotation(name="Coco",age = 20)     //数组只有一个值的话,大括号可以省略
            public void show(){
                System.out.println("show time");
            }
        }
        注意:如果注解中属性是数组类型,且数组中只有一个值,则大括号可以省略
    通过反射得到注解中属性值:
        1,获取被注解类的字节码对象
            Class<?> aClass = Class.forName("keyi.world.annotation.Test");
        2,如果注解在方法上,则通过反射获取该方法对象
            Method show = aClass.getMethod("show");
        3,if判断是否有定义的注解
            if(aClass.isAnnotationPresent(MyAnnotation.class)){}    //注解在类上
            if(show.isAnnotationPresent(MyAnnotation.class)){}      //注解在方法上
        4,得到注解对象
            MyAnnotation annotation = aClass.getAnnotation(MyAnnotation.class);
            MyAnnotation annotation = show.getAnnotation(MyAnnotation.class);
        5,像调用方法一样,获取注解属性
            System.out.println(annotation.name());

网络编程代码

  • UDP

    发送端:
    public class SendUDP {
        public static void main(String[] args) {
            DatagramSocket socket=null;
            BufferedReader reader=null;
            try {
                socket = new DatagramSocket();
                reader = new BufferedReader(new InputStreamReader(System.in));
                InetAddress address = InetAddress.getByName("localhost");
                String data =null;
                while((data=reader.readLine())!=null){
                    if(data.equals("886")){
                        break;
                    }
                    DatagramPacket packet = new 
                      DatagramPacket(data.getBytes(),data.getBytes().length,
                      	address,3800);
                    socket.send(packet);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (socket != null) {
                    socket.close();
                }
            }
        }
    }
    
    接收端:
    public class ReceiveUDP {
        public static void main(String[] args) {
            DatagramSocket socket=null;
            try {
                socket = new DatagramSocket(3800);
                while (true){
                    byte[] bytes = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
                    socket.receive(packet);
                    byte[] data = packet.getData();
                    System.out.println(new String(data));
                }
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (socket != null) {
                    socket.close();
                }
            }
        }
    }
  • TCP

    客户端:
    public class FileClientTCP {
        public static void main(String[] args) {
            /*
            *   功能:客户端发送文件给服务端,服务端接收后保存下来,并给客户端反馈
            *   服务端使用多线程,可以同时接受多个客户端的请求
            * */
            Socket socket=null;
            BufferedReader read=null;
            BufferedReader reader;
            BufferedWriter writer;
            try {
                socket = new Socket("localhost",10086);
                read = new BufferedReader(new 
                	FileReader("C:\\Users\\OneForAll\\Desktop\\IDEA快捷键.txt"));
                reader = new BufferedReader(new
                	InputStreamReader(socket.getInputStream()));
                writer = new BufferedWriter(new 
                	OutputStreamWriter(socket.getOutputStream()));
                String data;
                while ((data= read.readLine())!=null){
                    writer.write(data);
                    writer.newLine();
                    writer.flush();
                }
                socket.shutdownOutput();
                while ((data= reader.readLine())!=null){
                    System.out.println("服务端发来消息:"+data);
                }
            }catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (read!=null){
                    try {
                        read.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    服务端
    public class FileServerThreadTCP implements Runnable {
        private Socket socket;
    
        public FileServerThreadTCP(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedWriter writer = null;
            BufferedReader reader = null;
            PrintStream printStream = null;
            try {
                //服务端多线程解决写入文件时重复名问题
                int count = 0;
                File file = new File("C:\\Users\\OneForAll\\Desktop\\IDEA快捷键
                	[" + count + "].txt");
                while (file.exists()) {
                    count++;
                    file = new File("C:\\Users\\OneForAll\\Desktop\\IDEA快捷键
                    	[" + count + "].txt");
                }
                writer = new BufferedWriter(new FileWriter(file));
                reader = new BufferedReader(new 
                	InputStreamReader(socket.getInputStream()));
                printStream = new PrintStream(socket.getOutputStream(), true);
                String data;
                while ((data = reader.readLine()) != null) {
                    writer.write(data);
                    writer.newLine();
                    writer.flush();
                }
                printStream.println("文件上传成功");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (printStream != null) {
                    printStream.close();
                }
                if (writer != null) {
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    服务端启动
    public class ThreadTCP {
        public static void main(String[] args) {
            try {
                ServerSocket serverSocket = new ServerSocket(10086);
                while (true){
                    Socket socket = serverSocket.accept();
                    new Thread(new FileServerThreadTCP(socket)).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }