网络编程

2020-12-14  本文已影响0人  笨比乔治

day11【网络编程】

教学目标

第一章 网络编程入门

1.1软件结构

01_CS架构.png

B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。

02_BS架构.png

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。

1.2 网络通信协议

03_通讯协议.png

1.3 协议分类

通信的协议还是比较复杂的,java.net 包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。

java.net 包中提供了两种常见的网络协议的支持:

04_TCP协议三次握手.png

完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。

1.4 网络编程三要素

协议

IP地址

IP地址分类 o o o o

常用命令

ipconfig
ping 空格 IP地址
ping 220.181.57.216
ping www.baidu.com

特殊的IP地址

端口号

网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?

如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。

利用协议+IP地址+端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。

/**
 InetAddress类概述
 * 一个该类的对象就代表一个IP地址对象。
​
 InetAddress类成员方法
 * static InetAddress getLocalHost()
 * 获得本地主机IP地址对象
 * static InetAddress getByName(String host)
 * 根据IP地址字符串或主机名获得对应的IP地址对象
​
 * String getHostName();获得主机名
 * String getHostAddress();获得IP地址字符串
 */
public class InetAddressDemo01 {
 public static void main(String[] args) throws Exception {
 // 获得本地主机IP地址对象
 InetAddress inet01 = InetAddress.getLocalHost();
 // pkxingdeMacBook-Pro.local/10.211.55.2
 // 主机名/ip地址字符串
 System.out.println(inet01);
 // 根据IP地址字符串或主机名获得对应的IP地址对象
 // InetAddress inet02 = InetAddress.getByName("192.168.73.97");
 InetAddress inet02 = InetAddress.getByName("baidu.com");
 System.out.println(inet02);
​
 // 获得主机名
 String hostName = inet01.getHostName();
 System.out.println(hostName);
 // 获得IP地址字符串
 String hostAddress = inet01.getHostAddress();
 System.out.println(hostName);
 System.out.println(hostAddress);
 }
}

第二章 UDP通信程序

2.1 UDP协议概述

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP通信过程如下图所示:

05_UDP通信过程.png

UDP协议的特点

2.2 UDP通信案例

2.2.1 UDP发送端代码实现

// UDP发送端代码实现
public class UDPSender {
 public static void main(String[] args)throws Exception{
 // 定义一个字符串:要发送的内容
 String message = "约吗";
 // 字符串转字节数组
 byte[] buf = message.getBytes();
 // 创建数据包对象
 DatagramPacket dp = new DatagramPacket(buf,buf.length,
 InetAddress.getLocalHost(),6666);
 // 创建发送端的发送对象
 DatagramSocket ds = new DatagramSocket(8888);
 // 发送数据包
 ds.send(dp);
 // 关闭发送对象释放端口号
 ds.close();
 }
}

2.2.2 UDP接收端代码实现

/**
 UDP协议接收端代码实现
 */
public class UDPReceive {
 public static void main(String[] args)throws Exception{
 // 创建接收对象DatagramSocket
 DatagramSocket ds = new DatagramSocket(6666);
 // 创建字节数组用来存储接收接收到的内容
 byte[] buf = new byte[1024];
 // 创建数据包对象
 DatagramPacket dp = new DatagramPacket(buf,buf.length);
 // 接收数据包
 ds.receive(dp);
​
 // 获得实际接收到的字节个数
 int len = dp.getLength();
 System.out.println("len = " + len);
 // 将字节数组的内容转换为字符串输出
 System.out.println(new String(buf,0,len));
​
 // 获得发送端的ip地址
 String sendIp = dp.getAddress().getHostAddress();
 // 获得发送端的端口号
 int port  = dp.getPort();
 System.out.println(sendIp);
 System.out.println(port);
​
 // 关闭Socket对象
 ds.close();
 }
}

第三章 TCP通信程序

3.1 TCP协议概述

``
TCP ==> Transfer Control Protocol ==> 传输控制协议
TCP协议的特点
 * 面向连接的协议
 * 只能由客户端主动发送数据给服务器端,服务器端接收到数据之后,可以给客户端响应数据。
 * 通过三次握手建立连接,连接成功形成数据传输通道。
 * 通过四次挥手断开连接
 * 基于IO流进行数据传输
 * 传输数据大小没有限制
 * 因为面向连接的协议,速度慢,但是是可靠的协议。
​
TCP协议的使用场景
 * 文件上传和下载
 * 邮件发送和接收
 * 远程登录
​
TCP协议相关的类
 * Socket
 * 一个该类的对象就代表一个客户端程序。
 * ServerSocket
 * 一个该类的对象就代表一个服务器端程序。
​
Socket类构造方法
 * Socket(String host, int port)
 * 根据ip地址字符串和端口号创建客户端Socket对象
 * 注意事项:只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会抛出异常。
 如果连接成功,则表示三次握手通过。
​
Socket类常用方法
 * OutputStream getOutputStream(); 获得字节输出流对象
 * InputStream getInputStream();获得字节输入流对象

3.2 TCP通信案例

3.2.2 客户端向服务器发送数据

/*
TCP客户端代码实现步骤
 * 创建客户端Socket对象并指定服务器地址和端口号
 * 调用Socket对象的getOutputStream方法获得字节输出流对象
 * 调用字节输出流对象的write方法往服务器端输出数据
 * 调用Socket对象的getInputStream方法获得字节输入流对象
 * 调用字节输入流对象的read方法读取服务器端返回的数据
 * 关闭Socket对象断开连接。
 */
// TCP客户端代码实现
public class TCPClient {
 public static void main(String[] args) throws Exception{
 // 要发送的内容
 String content = "你好TCP服务器端,约吗";
 // 创建Socket对象
 Socket socket = new Socket("192.168.73.99",9999);
 // System.out.println(socket);
 // 获得字节输出流对象
 OutputStream out = socket.getOutputStream();
 // 输出数据到服务器端
 out.write(content.getBytes());
​
 // 获得字节输入流对象
 InputStream in = socket.getInputStream();
 // 创建字节数组:用来存储读取到服务器端数据
 byte[] buf = new byte[1024];
 // 读取服务器端返回的数据
 int len = in.read(buf);
 System.out.println("len = " + len);
 System.out.println("服务器端返回的内容 = " + new String(buf,0,len));
​
 // 关闭socket对象
 socket.close();
 }
}

3.3.3 服务器向客户端回写数据

/**
    TCP服务器端代码实现

    ServerSocket类构造方法
        * ServerSocket(int port) 根据指定的端口号开启服务器。

    ServerSocket类常用方法
        *  Socket accept() 等待客户端连接并获得与客户端关联的Socket对象

    TCP服务器端代码实现步骤
        * 创建ServerSocket对象并指定端口号(相当于开启了一个服务器)
        * 调用ServerSocket对象的accept方法等待客端户连接并获得对应Socket对象
        * 调用Socket对象的getInputStream方法获得字节输入流对象
        * 调用字节输入流对象的read方法读取客户端发送的数据
        * 调用Socket对象的getOutputStream方法获得字节输出流对象
        * 调用字节输出流对象的write方法往客户端输出数据
        * 关闭Socket和ServerSocket对象
 */
public class TCPServer {
    public static void main(String[] args)throws Exception{
        // 创建服务器ocket对象
        ServerSocket serverSocket = new ServerSocket(9999);
        // 等待客户端连接并获得与客户端关联的Socket对象
        Socket socket = serverSocket.accept();
        // 获得字节输入流对象
        InputStream in = socket.getInputStream();
        // 创建字节数组:用来存储读取到客户端发送的数据
        byte[] buf = new byte[1024];
        // 读取客户端发送过来的数据
        int len = in.read(buf);
        System.out.println("len = " + len);
        System.out.println("客户端发送的数据 = " + new String(buf,0,len));

        // 获得字节输出流对象
        OutputStream out = socket.getOutputStream();
        // 往客户端输出数据
        out.write("约你妹".getBytes());

        // 关闭socket
        socket.close();
        // 关闭服务器(在实际开发中,服务器一般不会关闭)
        serverSocket.close();
    }
}

第四章 综合案例

4.1 文件上传案例

文件上传分析图解

  1. 【客户端】输入流,从硬盘读取文件数据到程序中。

  2. 【客户端】输出流,写出文件数据到服务端。

  3. 【服务端】输入流,读取文件数据到服务端程序。

  4. 【服务端】输出流,写出文件数据到服务器硬盘中。

  5. 【服务端】获取输出流,回写数据。

  6. 【客户端】获取输入流,解析回写数据。

07_文件上传图解.png

案例实现

服务器端实现:

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
                 System.out.println("服务器 启动.....  ");
        // 1\. 创建服务端ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
        // 2\. 循环接收,建立连接
        while (true) {
            Socket accept = serverSocket.accept();
            /*
            3\. socket对象交给子线程处理,进行读写操作
               Runnable接口中,只有一个run方法,使用lambda表达式简化格式
            */
            new Thread(() -> {
                try (
                    //3.1 获取输入流对象
                    BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                    //3.2 创建输出流对象, 保存到本地 .
                    FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                    BufferedOutputStream bos = new BufferedOutputStream(fis);
                ) {
                    // 3.3 读写数据
                    byte[] b = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(b)) != -1) {
                        bos.write(b, 0, len);
                    }

                    // 4.=======信息回写===========================
                    System.out.println("back ........");
                    OutputStream out = accept.getOutputStream();
                    out.write("上传成功".getBytes());
                    out.close();
                    //================================

                    //5\. 关闭 资源
                    bos.close();
                    bis.close();
                    accept.close();
                    System.out.println("文件上传已保存");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

客户端实现:

public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
        // 1.创建流对象
        // 1.1 创建输入流,读取本地文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
        // 1.2 创建输出流,写到服务端
        Socket socket = new Socket("localhost", 6666);
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        //2.写出数据.
        byte[] b  = new byte[1024 * 8 ];
        int len ;
        while (( len  = bis.read(b))!=-1) {
            bos.write(b, 0, len);
        }
        // 关闭输出流,通知服务端,写出数据完毕
        socket.shutdownOutput();
        System.out.println("文件发送完毕");
        // 3\. =====解析回写============
        InputStream in = socket.getInputStream();
        byte[] back = new byte[20];
        in.read(back);
        System.out.println(new String(back));
        in.close();
        // ============================

        // 4.释放资源
        socket.close();
        bis.close();
    }
}

4.2 模拟B\S服务器

模拟网站服务器,使用浏览器访问自己编写的服务端程序,查看网页效果。

案例分析

  1. 准备页面数据,web文件夹。

  2. 我们模拟服务器端,ServerSocket类监听端口,使用浏览器访问,查看网页效果

案例实现

浏览器工作原理是遇到图片会开启一个线程进行单独的访问,因此在服务器端加入线程技术。

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8888);
        while(true){
            Socket socket = server.accept();
            new Thread(new Web(socket)).start();
        }
    }
}  
class Web implements Runnable{
    private Socket socket;

    public Web(Socket socket){
        this.socket=socket;
    }

    public void run() {
        try{
            //转换流,读取浏览器请求第一行
            BufferedReader readWb = new
                    BufferedReader(new InputStreamReader(socket.getInputStream()));
            String requst = readWb.readLine();
            //取出请求资源的路径
            String[] strArr = requst.split(" ");
            System.out.println(Arrays.toString(strArr));
            String path = strArr[1].substring(1);
            System.out.println(path);

            FileInputStream fis = new FileInputStream(path);
            System.out.println(fis);
            byte[] bytes= new byte[1024];
            int len = 0 ;

            //向浏览器 回写数据
            OutputStream out = socket.getOutputStream();
            out.write("HTTP/1.1 200 OK\r\n".getBytes());
            out.write("Content-Type:text/html\r\n".getBytes());
            out.write("\r\n".getBytes());
            while((len = fis.read(bytes))!=-1){
                out.write(bytes,0,len);
            }
            fis.close();
            out.close();
            readWb.close();
            socket.close();
        }catch(Exception ex){

        }
    }
}

访问效果:

08_BS服务器案例效果图.png

图解:

09_BS通讯图解.png
上一篇 下一篇

猜你喜欢

热点阅读