java学习之旅(day.18)

网络编程

概述

计算机网络:自己百度吧

网络编程的目的:传播交流信息、数据交换、通信

想要达到这个效果需要什么:

  • 如何准确的定位网络上的一台主机 端口 定位到这个计算机上的某个资源
  • 找到了这个主机,如何传输数据呢?

javaWeb开发 :网页编程 B/S架构

网络编程:主要针对TCP/IP C/S架构

网络通信的要素

如何实现网络的通信?

通信双方地址:

  • IP
  • 端口号

规则:网络通信的协议

http ftp smtp等

IP地址

IP地址:InetAddress(没有构造器,就不用new了,new不了,用静态方法)

  • 可以唯一的定位一台网络上的计算机

  • 一些特殊的IP,如:127.0.0.1 代表本机(localhost)

  • IP地址的分类,分类方式有两种

    • 通过IP地址分类 ipv4/ipv6

      • ipv4 像127.0.1,是由4个字节组成,每个字节的长度是0-255,ipv4都给外国人了,亚洲就那几个吧,早用光了
      • ipv6 128位,8个无符号整数 0-9 a-e

      ipv6写法:

      2001:0bb2:aaaa:0000:0000:1aaa:1311:0025

    • 通过公网(互联网使用)还是私网(局域网使用)分类

    ​ 局域网:192开头的,专门给组织内部使用的

    ABCD类地址有时间自己查查

  • 域名的诞生就是为了解决记忆IP问题

package com.zhang.WLBC.Lesson01;

import java.net.InetAddress;
import java.net.UnknownHostException;

//测试IP
public class TestInetAddress {
    public static void main(String[] args) {
        //InetAddress z=new InetAddress();没有构造器,无法new,只能通过它的静态方法把他返回过来
        try {
            //查询本机地址
            InetAddress inetAddress1=InetAddress.getByName("127.0.0.1");//通过获取名字返回 这就代表一个IP对象  //静态方法返回的就是本身这个对象
            System.out.println(inetAddress1);
            InetAddress inetAddress3=InetAddress.getByName("localhost");
            System.out.println(inetAddress3);//localhost/127.0.0.1
            InetAddress inetAddress4=InetAddress.getLocalHost();
            System.out.println(inetAddress4);//DESKTOP-VKFSHV1/192.168.1.3

            //查询网站的IP地址
            InetAddress inetAddress2=InetAddress.getByName("www.baidu.com");//跟ping是一样的作用
            System.out.println(inetAddress2);//www.baidu.com/39.156.66.18

            //常用方法
            System.out.println(inetAddress2.getAddress());
            System.out.println(inetAddress2.getCanonicalHostName());//获得规范的名字
            System.out.println(inetAddress2.getHostAddress());//IP
            System.out.println(inetAddress2.getHostName());//域名,或自己电脑的名字




        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //上面报错了(未知的主机异常),用try catch捕获一下
    }

}

端口

端口表示计算机上一个程序的进程,一个端口对应一个程序的进程

  • 不同的进程有不同的端口号,用来区分软件

  • 端口被规定0-65535

  • 分为TCP端口和UDP端口,单个协议下,端口号不能冲突,但是不同协议下的端口号可以相同。如:TCP:80与UDP:80

  • 端口分类-

    公有端口:0-1023

    • HTTP:80
    • HTTP5:443
    • FTP:21
    • Telent:23

    程序注册端口:1024-49151,分配给用户或程序

    • Tomcat:8082
    • MySQL:3306
    • Oracle:1521

​ 动态或私有端口:49152-65535

常见的dos命令

netstat -ano 查看所有的端口

netstat -ano|findstr "5900" 查看指定的端口

tasklist|findstr "8696" 查看指定端口的进程

package com.zhang.WLBC.Lesson01;

import java.net.InetSocketAddress;

public class TestInetSocketAddress {
    public static void main(String[] args) {
        InetSocketAddress socketAddress=new InetSocketAddress("127.0.0.1",80);//这个类可以new
        System.out.println(socketAddress);///127.0.0.1:80
        InetSocketAddress socketAddress1=new InetSocketAddress("localhost",80);//这个类可以new
        System.out.println(socketAddress1);//localhost/127.0.0.1:80

        //里面的方法
        System.out.println(socketAddress.getAddress());//  /127.0.0.1
        System.out.println(socketAddress.getHostName());//127.0.0.1
        System.out.println(socketAddress.getPort());// 80
    }
}

通信协议

协议:约定,就像现在说的是汉语才能听懂,说外语就jj了

网络通信协议:针对网络产生的协议

TCP/IP协议簇:实际上是一组协议

TCP:用户传输协议 类似于打电话

UDP:用户数据报协议 类似于发短信

比较出名的协议

  • TCP:用户传输协议
  • IP:网络互联协议

TCP与UDP对比

  • TCP:类似打电话

    • 连接,稳定
    • 三次握手,四次挥手

    建立稳定连接至少要三次

    断开连接至少要四次

    • 客户端,服务端连接
    • 传输完成就会释放连接,效率低
  • UDP:类似发短信

    • 不连接,不稳定
    • 客户端,服务端没有明确的界限
    • 不管有没有准备好,都可以发给你
    • DDOS:洪水(饱和)攻击,也就是人海战术吧

TCP实现聊天

​ 聊天就要两个人(客户端和服务器)

得编写两个类:客户端、服务器

客户端

  1. 通过socket连接服务器
  2. 发送消息
package com.zhang.WLBC.Lesson02;
//运行时先启动服务端,再启动客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;

//客户端
public class TcpClientDemo01 {
    public static void main(String[] args) {
        Socket socket=null;
        OutputStream os=null;
        //1.客户端连接服务器要先知道服务器的地址,所以对服务器来说得先有一个地址,做一个地址
        //连接
        try {
            InetAddress severIP=InetAddress.getByName("127.0.0.1");//要连接的地址
        //2.端口号
            int port =9999;
            //把上面两行和服务端连接
            //用socket 创建一个socket连接
            socket=new Socket(severIP,port);//这样就连接到服务端了,这里会出现异常,要把catch中的作用域提升到最大(把UnknownHostException改为Exception)把UnknownHostException改为Exception
        //3.发送消息,用到IO
            os=socket.getOutputStream();
            os.write("你好,我正在自学java".getBytes());//然后就是客户端接收了

        } catch (Exception e) {//catch (UnknownHostException e) {
            e.printStackTrace();
        }finally {
            if (os!=null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket!=null) {
                try {
                    socket.close();//继续提升作用域,捕获异常
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

服务器

  1. 建立服务的端口Seversocket

  2. 通过accept等待客户端的连接,会返回客户端连接过来的socket

  3. 接收用户的消息

package com.zhang.WLBC.Lesson02;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

//服务端
public class TcpSeverDemo01 {
    public static void main(String[] args) {
        //提升作用域?
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
            try {
                //1.做一个地址localhost:9999,再去客户端让客户端连这个9999
                serverSocket = new ServerSocket(9999);
                //2.等待客户端连接过来
                socket = serverSocket.accept();//这里的Socket就是客户端连接过来的socket
                //3.读取客户端的消息
                is = socket.getInputStream();

           /* byte[] buffer=new byte[1024];//用缓冲区去接
            int len;
            while ((len=is.read(buffer))!=-1){//读
                String msg=new String(buffer,0,len);//然后写出去,new一个string后拼接上去
                System.out.println(msg);
                //但一般不这样写了,因为有中文的话会乱码
                }
            */
                //而用管道流
                baos = new ByteArrayOutputStream(); //把输入流通过管道流接一下,再输出来
                byte[] buffer = new byte[1024];//用缓冲区去接
                int len;
                while ((len = is.read(buffer)) != -1) {//读
                    baos.write(buffer, 0, len);
                }
                System.out.println(baos.toString());


            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关闭资源,先开后关
                if (baos != null) {
                    try {
                        baos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                 if (socket!= null) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (serverSocket != null) {
                        try {
                            serverSocket.close();//这几行直接加不进来,要提升作用域
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

//也可以不写try catch,直接抛出异常

文件上传

读取后,把文件变成一个流,再传出去

客户端(路径一直不对,报错)

package com.zhang.WLBC.Lesson02;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

//客户端读取发送文件
public class TcpClientDemo02 {
    public static void main(String[] args) throws Exception{
        //1.创建一个socket连接
        Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),9000);
        //2.创建一个输出流
        OutputStream os=socket.getOutputStream();

        //3.读取文件
       FileInputStream fis= new FileInputStream(new File("B.PNG"));
       //4.写出文件
        byte[] buffer=new byte[1024];//缓冲区
        int len;
        while ((len=fis.read(buffer))!=-1){
            os.write(buffer,0,len);
        }

        //通知服务器,我已经结束了
        socket.shutdownOutput();//我已经传输完了
        
        //确定服务器接收完毕才能断开连接,再在服务器端通知客户端我接收完毕了
        InputStream inputStream=socket.getInputStream();
        ByteArrayOutputStream baos=new ByteArrayOutputStream();//传过来的东西不认识,只有通过管道流才能认识

        byte[] buffer2=new byte[1024];
        int len2;
        while ((len2=inputStream.read())!=-1){
            baos.write(buffer2,0,len2);
        }

        System.out.println(baos.toString());
        //5.关闭资源
        baos.close();
        inputStream.close();
        fis.close();
        os.close();
        socket.close();
    }
}

服务器端

package com.zhang.WLBC.Lesson02;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

//服务端接收文件
public class TcpSeverDemo02 {
    public static void main(String[] args) throws Exception{
        //1.创建服务端口
        ServerSocket serverSocket=new ServerSocket(9000);
        //2.监听客户端的连接
        Socket socket=serverSocket.accept();//阻塞式监听,会一直等待客户端连接
        //3.获取输入流
        InputStream is=socket.getInputStream();//这样就把文件拿到了

        //4.文件输出
        FileOutputStream fos=new FileOutputStream(new File("receive.PNG"));
        byte[] buffer=new byte[1024];
        int len;
        while ((len=is.read(buffer))!=-1){
            fos.write(buffer,0,len);
        }

        //通知客户端我接收完毕了
        OutputStream os=socket.getOutputStream();
        os.write("我接收完毕了,可以断开了".getBytes());


        //关闭资源
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

Tomcat

服务端

  • 自定义s
  • 也可以用Tomcat服务器

客户端

  • 自定义c
  • 浏览器B

UDP消息发送

相当于发短信:不用连接,只需知道对方的地址就可

发送消息

package com.zhang.WLBC.Lesson02.Lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//不需要连接到服务器
public class UdpClientDemo01 {
    public static void main(String[] args) throws Exception{
        //1.建立一个socket
        DatagramSocket socket=new DatagramSocket();//用来发东西的   此处要抛出异常


        //2.建个包
        String msg="hello";
        new DatagramPacket(msg.getBytes(),0,msg.getBytes().length);//msg.getByte 变成数组


        //发送给谁
        InetAddress localhost=InetAddress.getByName("localhost");
        int port=9090;
        DatagramPacket packet=new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);//msg.getByte 变成数组
                         //数据             数据长度的起始            要发给谁


        //3.发送包(通过socket发送包)
        socket.send(packet);

        //4.关闭资源
        socket.close();//   包不用关
    }
}

接收消息

package com.zhang.WLBC.Lesson02.Lesson03;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

//服务器端要开放端口,其实还是好比要等待客户端的连接
public class UdpServerDemo01 {
    public static void main(String[] args) throws Exception{
        //开放端口
        DatagramSocket socket=new DatagramSocket(9090);
        //接收数据包
        byte[] buffer=new byte[1024];
        DatagramPacket packet=new DatagramPacket(buffer,0,buffer.length);

        socket.receive(packet);//阻塞接收(随时等待接收)

        System.out.println(packet.getAddress());//输出包裹从哪来的
        System.out.println(packet.getData());//    [B@45ee12a7  data是一个byte,要转为String(new一个string),见下一行
        System.out.println(new String(packet.getData(),0,packet.getLength()));//得到包裹的内容
        //关闭连接
        socket.close();
    }
}

实现聊天

循环发送消息

package com.zhang.WLBC.Lesson02.Lesson03.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;

//两者互为发送者和接收者
public class UdpSenderDemo01 {
    public static void main(String[] args) throws Exception{
        DatagramSocket socket=new DatagramSocket(8888);

        //准备数据,聊天,需要从控制台读取(System.in)
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in ));
        while (true) {
            String data = reader.readLine();//读取一行
            byte[] dates = data.getBytes();//转换成数据,因为data是不可读的,要转换为字节
            DatagramPacket packet = new DatagramPacket(dates, 0, dates.length, new InetSocketAddress("localhost", 6666));//这里需要数据,所以要准备数据
            socket.send(packet);
        if (data.equals("bye")) {
            break;
        }
        }
            socket.close();


    }
}

循环接收消息

package com.zhang.WLBC.Lesson02.Lesson03.chat;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UdpReceiveDemo01 {
    public static void main(String[] args) throws Exception{
        DatagramSocket socket=new DatagramSocket(6666);
        
        //实现循环接收
        while (true){
            //准备接收包裹
            byte[] container=new byte[1024];
            DatagramPacket packet=new DatagramPacket(container,0,container.length);
            socket.receive(packet);////这个packet需要一个地方去放置它,所以需要一个准备接收的包裹
            //接收过来的消息还得读一下
                //断开连接(接收的数据为bye的时候)
            byte[] data=packet.getData();
            String receiveData=new String(data,0,data.length);//读取接收到的消息
            System.out.println(receiveData);
            if (receiveData.equals("bye")){
                break;
            }
            
        }
        socket.close();
    }
}

UDP多线程在线咨询

两个人都可以是发送方,也都可以是接收方

posted on 2021-01-29 22:31  懵逼的程序小白  阅读(99)  评论(0)    收藏  举报