Java网络编程


01.什么是计算机网络

网络编程

打电话 -- 连接 -- 接了电话 -- 通话 (TCP)

发短信 -- 发送了就完事了 -- 接收 (UDP)

计算机网络:

计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程的目的

传播交流信息,数据交换,通讯

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

  1. 如何准确的定位网络上的主机--IP
  2. 定位到这个计算机上的某个资源--Port
  3. 找到了这个主机,如何传输数据呢?

javaWeb:网页编程 (B/S架构)

网络编程:TCP/IP (C/S架构)

02.网路通讯的两个要素

如何实现网络的通讯

通讯双方的地址:

  • IP
  • 端口号Port

规则:网络通讯的协议

TCP/IP参考模型

preview

小结:

  1. 网络编程中的两个主要的问题
    1. 如何准确的定位到网络上的一台或者多台主机
    2. 找到主机之后如何进行通讯
  2. 网络编程中要素
    1. IP和端口号
    2. 网络通讯协议 udp,tcp
  3. 万物皆对象

03.IP地址

ip地址:InetAddress

  • 唯一定位一台网络计算机

  • 127.0.0.1 :本地localhost

  • ip地址分类

    • ipv4/ipv6

      • ipv4 127.0.0.1 ,4个字节组成,0~255, 42亿~,30亿都在北美,亚洲4亿。2011就用尽了
      • ipv6 :128位。 8个无符号整数(够用)
      d40e:d41e:d42e:d43e:d44e:d45e:d46e:d407e
      
    • 公网(互联网)-私网(局域网)

      • ABCD类地址
      • 192.168.xxx.xxx专门给组织内部使用的
  • 域名:记忆IP问题

public class TestInerAddress {
    public static void main(String[] args) {
        try {
            //查询本机地址
            InetAddress inetAddress01 = InetAddress.getByName("127.0.0.1");
            InetAddress inetAddress03 = InetAddress.getByName("localhost");
            InetAddress inetAddress04 = InetAddress.getLocalHost();
            System.out.println(inetAddress01);
            System.out.println(inetAddress03);
            System.out.println(inetAddress04);
            //查询网站地址
            InetAddress inetAddress02 = InetAddress.getByName("www.baidu.com");
            System.out.println(inetAddress02);
            //常用方法
            System.out.println(inetAddress02.getAddress());
            System.out.println(inetAddress02.getCanonicalHostName());//获得规范名
            System.out.println(inetAddress02.getHostAddress());//获得主机名
            System.out.println(inetAddress02.getHostName());//域名,或者自己电脑的名字
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //InetAddress inetAddress= new InetAddress();//构造方法中没有public标识
    }
}

04.端口Port

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

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

  • 被规定0~65535

  • TCP,UDP: 65535 *2 ,单个协议下,端口号不能冲突

  • 端口分类

    • 公有端口0~1023
      • http:80
      • https:443
      • ftp:21
      • telnet:23
    • 程序注册端口:1024~49151,分配用户或者程序
      • tomcat:8080
      • mysql:3306
      • oracle:1521
    • 动态、私有:49152~65535
    netstat -ano #查看所有的端口
    netstat -ano|findstr "57766" #查看指定的端口
    tasklist|findstr "8088" #查看指定端口的进程
    
    public static void main(String[] args) {
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1",8080);
        InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost",8080);
        System.out.println(inetSocketAddress);
        System.out.println(inetSocketAddress2);
    
        System.out.println(inetSocketAddress.getAddress());
        //地址
        System.out.println(inetSocketAddress.getHostName());
        //端口
        System.out.println(inetSocketAddress.getPort());
        System.out.println(inetSocketAddress.getHostString());
    }
    

05.通讯协议

协议:约定,就好比我们现在说的普通话

网络通信协议:速率,传输码率,代码结构,传输控制。。。

问题:非常的复杂

大事化小:分层

tcp/ip协议簇:实际上是一组协议

重要

  • TCP:用户传输协议
  • UDP:用户数据报协议

出名的协议

  • TCP
  • IP:网络互连协议

tcp udp对比

tcp:打电话

  • 连接,稳定
  • 三次握手,四次挥手
最少需要三次,保证稳定连接
A:你愁啥?
B:瞅你咋地?
A:干一架!

A:我要走了!
B:你真的要走了吗?
B:你真的真的要走了吗?
A:我真的要走了!
  • 客户端、服务端
  • 传输完成,释放连接, 效率低

udp:发短信

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

06.TCP实现聊天

客户端

  1. 连接服务器 Socket
  2. 发送消息
public class ClientDemo {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            //连接服务+端口
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            socket = new Socket(inetAddress, 9000);
            //发送消息
            outputStream = socket.getOutputStream();
            outputStream.write("网络通讯学习中".getBytes("UTF-8"));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务器

  1. 建立服务的端口 ServerSocket
  2. 等待用户的连接 accept
  3. 接受用户的消息
public class ServiceDemo {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket accept = null;
        InputStream inputStream = null;
        ByteArrayOutputStream os = null;
        try {
            //建立服务的端口
            serverSocket = new ServerSocket(9000);
            while (true) {
                //等待用户的连接
                accept = serverSocket.accept();
                //接受用户的消息
                inputStream = accept.getInputStream();
                os = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int count;
                while ((count = inputStream.read(buffer)) != -1) {
                    os.write(buffer, 0, count);
                }
                System.out.println("服务端收到客户端报文:" + os.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (accept != null) {
                try {
                    accept.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

07.TCP文件上传实现

客户端

public class FileClientDemo {
    public static void main(String[] args) {
        try {
            //连接服务器的端口
            Socket socket = new Socket(InetAddress.getByName("localhost"), 9001);
            //发送消息
            OutputStream outputStream = socket.getOutputStream();
            //读取本地文件
            InputStream fileInputStream = new FileInputStream("C:\\Users\\ZHAYUYAO\\Desktop\\test.txt");
            //写文件
            byte[] buffer = new byte[1024];
            int count;
            while ((count = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, count);
            }
            outputStream.flush();
            //通知服务器我已经传输完了
            socket.shutdownOutput();
            //确定服务器接受完毕,才开始断开连接
            InputStream inputStream = socket.getInputStream();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer2 = new byte[1024];
            int count2;
            while ((count2 = inputStream.read(buffer2)) != -1) {
                byteArrayOutputStream.write(buffer2, 0, count2);
            }
            System.out.println("客户端接受到服务器端的返回报文:" + byteArrayOutputStream.toString());
            //关闭
            byteArrayOutputStream.close();
            inputStream.close();
            outputStream.close();
            fileInputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

服务端

public class FileServiceDemo {
    public static void main(String[] args) {

        try {
            //建立服务的端口
            ServerSocket serverSocket = new ServerSocket(9001);
            //等待客户端连接(监听客户端连接,阻塞式监听,会一直等待客户端连接)
            Socket accept = serverSocket.accept();
            //接受客户端发送的消息
            InputStream inputStream = accept.getInputStream();
            //接收文件
            FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\ZHAYUYAO\\Desktop\\testUp.txt");
            byte[] buffer = new byte[1024];
            int count;
            while ((count = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, count);
            }
            fileOutputStream.flush();
            //通知客户端,我接收完了
            OutputStream outputStream = accept.getOutputStream();
            outputStream.write("我服务端接收完了!客户端可以断开连接了".getBytes("UTF-8"));
            //关闭
            outputStream.close();
            fileOutputStream.close();
            inputStream.close();
            accept.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

08.初始Tomcat

服务器

  • 自定义 S
  • tomcat服务器 S :java后端开发!

客户端

  • 自定义 C
  • 浏览器 B

09.UDP消息发送

发送短信:不需要连接,需要知道对方的地址

发送端

public class SendDemo {
    public static void main(String[] args) {

        try {
            //建立socket连接
            DatagramSocket datagramSocket = new DatagramSocket();
            //创建数据包
            String data = "send data";
            byte[] datas = data.getBytes("UTF-8");
            //发送给谁
            InetAddress inetAddress = InetAddress.getByName("localhost");
            int port = 9009;
            DatagramPacket datagramPacket = new DatagramPacket(datas, 0, datas.length, inetAddress, port);
            //发送数据包
            datagramSocket.send(datagramPacket);
            //关闭
            datagramSocket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

接收端

public class ReceiveDemo {
    public static void main(String[] args) {

        try {
            //开放端口
            DatagramSocket datagramSocket = new DatagramSocket(9009);
            byte[] buffer = new byte[1024];

            DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);

            //接受数据包(阻塞式监听)
            datagramSocket.receive(datagramPacket);
            System.out.println(datagramPacket.getAddress());
            System.out.println("接收到了:" + new String(datagramPacket.getData(), 0, datagramPacket.getLength()));
            datagramSocket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

10.UDP聊天实现

循环发送

public class UdpSendDemo02 {    public static void main(String[] args) {        try {            DatagramSocket datagramSocket = new DatagramSocket(8888);            //准备数据 控制台读取System.in            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));            while (true) {                String str = bufferedReader.readLine();                byte[] datas = str.getBytes("UTF-8");                DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress("localhost", 6666));                datagramSocket.send(packet);                if ("quit".equals(str)) {                    break;                }            }            datagramSocket.close();        } catch (SocketException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}

循环接收(TODO:停不下来。。。)

public class UdpReceiveDemo02 {    public static void main(String[] args) {        try {            DatagramSocket datagramSocket = new DatagramSocket(6666);            while (true) {                byte[] buffer = new byte[1024];                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);                datagramSocket.receive(packet);                byte[] datas = packet.getData();                String data = new String(datas, 0, datas.length);                System.out.println("接受到了:" + data);                if ("quit".equals(data)) {                    break;                }            }            datagramSocket.close();        } catch (SocketException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}

11.UDP多线程在线咨询

发送

public class TalkSendDemo implements Runnable {    private DatagramSocket datagramSocket;    private BufferedReader bufferedReader;    private int fromPort;    private int toPort;    private String toHostName;    public TalkSendDemo(int fromPort, int toPort, String toHostName) {        try {            this.datagramSocket = new DatagramSocket(fromPort);        } catch (SocketException e) {            e.printStackTrace();        }        this.bufferedReader = new BufferedReader(new InputStreamReader(System.in));        this.fromPort = fromPort;        this.toPort = toPort;        this.toHostName = toHostName;    }    @Override    public void run() {        send();    }    private void send() {        try {            //准备数据 控制台读取System.in            while (true) {                String str = bufferedReader.readLine();                byte[] datas = str.getBytes("UTF-8");                DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toHostName, this.toPort));                datagramSocket.send(packet);                if ("quit".equals(str)) {                    break;                }            }        } catch (IOException e) {            e.printStackTrace();        } finally {//            System.exit(0);            if (bufferedReader != null) {                try {                    bufferedReader.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (datagramSocket != null) {                datagramSocket.close();            }        }    }}

接收

public class TalkReceiveDemo implements Runnable {    private DatagramSocket datagramSocket;    private int port;    private String msgFrom;    public TalkReceiveDemo(int port, String msgFrom) {        this.port = port;        this.msgFrom = msgFrom;        try {            this.datagramSocket = new DatagramSocket(port);        } catch (SocketException e) {            e.printStackTrace();        }    }    @Override    public void run() {        receive();    }    private void receive() {        try {            while (true) {                byte[] buffer = new byte[1024];                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);                datagramSocket.receive(packet);                byte[] datas = packet.getData();                String data = new String(datas, 0, datas.length);                System.out.println(this.msgFrom + ":" + data);                if ("quit".equals(data)) {                    break;                }            }        } catch (IOException e) {            e.printStackTrace();        } finally {            if (datagramSocket != null) {                datagramSocket.close();            }        }    }}

老师

public class TalkTeacher {    public static void main(String[] args) {        new Thread(new TalkSendDemo(7777, 7778, "localhost")).start();        new Thread(new TalkReceiveDemo(7779, "学生")).start();    }}

学生

public class TalkStudent {    public static void main(String[] args) {        new Thread(new TalkSendDemo(7776, 7779, "localhost")).start();        new Thread(new TalkReceiveDemo(7778, "老师")).start();    }}

12.URL下载网络资源

https://www.baidu.com

统一资源定位符:定位资源的,定位互联网上的某一个资源

DNS域名解析

协议://ip地址:端口/项目名/资源
public static void main(String[] args) {    try {        URL url = new URL("http://localhost:8080/hello/index.jsp?username=zyy&password=1234");        //http 协议        System.out.println("===url===getProtocol()===》"+url.getProtocol());        //localhost  主机名        System.out.println("===url===getHost()===》"+url.getHost());        //8080 端口        System.out.println("===url===getPort()===》"+url.getPort());        //  /hello/index.jsp  路径        System.out.println("===url===getPath()===》"+url.getPath());        // /hello/index.jsp?username=zyy&password=1234 文件名,返回的文件部分将与getPath()相同,加上值为getQuery()(如果有)。如果没有查询部分,此方法和getPath()将返回相同的结果        System.out.println("===url===getFile()===》"+url.getFile());        // username=zyy&password=1234  参数        System.out.println("===url===getQuery()===》"+url.getQuery());    } catch (MalformedURLException e) {        e.printStackTrace();    }}

本地(互联网)下载

public class URLDownDemo {    public static void main(String[] args) {        try {            //也可以下载网络资源  https://isure.stream.qqmusic.qq.com/C400003L8wZo0tTMmr.m4a?guid=9143190098&vkey=D230FEA2C97C6A7D0AB646772CFBC15565768B38196DB4236792081D77D2D4F78BA0F10EAA128A3D99E00CE1DD76D7F950FB0014D03C2151&uin=1152921504752017967&fromtag=66            URL url = new URL("http://localhost:8080/zyy/test.txt");            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();            InputStream inputStream = urlConnection.getInputStream();            //C:\\Users\\ZHAYUYAO\\Desktop\\test.m4a            FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\ZHAYUYAO\\Desktop\\test.txt");            byte[] buffer = new byte[1024];            int length;            while ((length = inputStream.read(buffer))!=-1) {                fileOutputStream.write(buffer, 0, length);            }            fileOutputStream.flush();            fileOutputStream.close();            inputStream.close();            urlConnection.disconnect();        } catch (MalformedURLException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }    }}