java 网络编程

1. 网络通信概述

可以参考link中的第二点网络基础

1.1 软件的结构

  1. C/S 结构:客户端、服务器

  2. B/S 结构: 浏览器、服务器

1.2 网络通信协议

  1. 网络通信协议
    一个网络中的计算机需要通信,他们需要遵循一些规则
    在计算机中这些链接通信规则就称之为网络通信协议
    他们对数据的传输格式,传输速率,传输步骤等统一规定,通信双方必须同时遵循这些规则才能通信

  2. TCP/IP协议

    又称为 传输控制协议,因特网互联协议

    定义了计算机如何介入因特网,数据在节点之间传输的标准
    内部包含一系列用于处理数据通信的协议,采用了4层的分层模型,每层都呼叫自己的下一层为自己提供协议完成自己的需求

链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动

网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。

运输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。

应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。

1.3 协议分类

  1. UDP——无连接通信协议
    1. 发送端给接收段发送数据不需要接收端同意,也不会判断是否存在
    2. 耗资少,通信效率高 通常用于音视频和普通数据的传输 视频会议、视频聊天一般都采用的UDP协议
      偶尔会丢一两个数据包,但对结果不会与太大影响。
    3. 因为UDP的无连接性,所有我们传输重要数据时最好不要用UDP协议
  1. TCP——面向连接通信协议
    在传输数据之前会先建立连接,然后才会开始传输数据,可以提供两个节点之间无差错的数据传输。
    三次握手:
    1. 客户端向服务端发送连接请求,等待服务器确认
    2. 服务端向客户端发送一个响应,回应收到了请求
    3. 客户端再次向服务端发送已经收到确认信息的响应,确认建立连接
      通过三次握手建立连接后,客户端与服务端就可以进行数据传输了。因为此特性,TCP协议可以保证传输数据的安全

1.4网络编程的3要素

  1. 协议
    计算机网络通信必须遵循的规则,详情见上述

  2. IP地址
    互联网协议地址,设备的唯一编号
    ipV4:32位
    ipV6:128位

  3. 端口号

  • 指定了ip只能准确的找到计算机,但是计算机上有很多的软件。
  • 如何准确的与计算机上的软件进行通信呢?
  • ip:端口 就可以准确的找到软件
  • 1024之前的端口基本上被已知软件占用
  • 端口不能多个软件共同使用
  • 端口的范围为 0——65535

2. TCP协议

TCP通信能实现两台计算机之间进行数据交换,通信的两端,严格的区分客户端和服务端

TCP通信: 面向连接的通信,客户端和服务端必须进行三次握手才能建立逻辑连接,才能安全通信

2.1 通信的步骤:

  1. 服务器先启动,服务器不会主动发起对客户段的连接。
  2. 客户端发起请求,客户端与服务端就会建立一个逻辑连接
    连接中包括一个对象——IO对象
  3. 客户端与服务端就可以使用
    传输的数据不限于字符,所以IO对象是字节流对象

2.2 服务端必须明确的事情

  1. 多个客户端与服务端进行交互时,服务端必须明确是哪个客户端与其交互
    在服务端有一个方法叫,accept可以获取到请求客户端对象
  2. 多个客户端与服务器进行交互时,就需要使用多个IO流对象
    服务端是没有IO流的,服务端可以获取到发起请求的客户端的Socket对象,从而使用每个客户端中的Socket中提供的IO流与客户端进行交互
    • 服务器使用客户端的字节输入流读取客户端发送的数据
    • 服务器使用客户端的字节输出流给客户端会写数据
      简单说就是服务器使用客户端的流进行交互
image.png

code:

  1. TcpClient服务类
public class TcpClient {
    public static void main(String[] args) throws IOException {
        //1. 创建一个客户端对象Socket,构造方法写入IP地址和端口号
        Socket socket = new Socket("127.0.0.1",8888);

        //2. 使用Socket对象中的 方法getOutputStream();获取到网络字节输出流
        OutputStream outputStream = socket.getOutputStream();

        //3. 使用网络字节输出流中的write方法来给服务器发送数据
        outputStream.write("你好服务器!!".getBytes());

        //拿到回复
        InputStream inputStream = socket.getInputStream();

        //读取类容
        ReaderMsg.readers(inputStream);

        // 释放资源
        socket.close();
    }
}
  1. TcpServer 服务类
public class TcpServer {
    public static void main(String[] args) throws IOException {
        //创建服务器对象ServerSocket,并通过构造方法指定端口号
        ServerSocket serverSocket = new ServerSocket(8888);

        //使用ServerSocket中的accpet方法来得到客户端的Socket对象
        Socket socket = serverSocket.accept();

        //使用Socket中的getInputStream();方法来获取到网络输入流
        InputStream inputStream = socket.getInputStream();

        //读取类容
        ReaderMsg.readers(inputStream);

        //使用Socket中的getOutputStream();方法来获取到网络输出流
        OutputStream outputStream = socket.getOutputStream();

        outputStream.write("我收到你的问候!".getBytes());

        //关闭流
        socket.close();
        serverSocket.close();

    }
}
  1. 字符输出类
public class ReaderMsg {
    public static void readers(InputStream inputStream) throws IOException {
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        System.out.println(new String(bytes,0,len));
    }
}

3. 综合案例_文件上传

客户端:

public class TcpFileClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8888);
        OutputStream outputStream = socket.getOutputStream();

        BufferedInputStream biStream = new BufferedInputStream(
                new FileInputStream("I:\\download\\myeclise-2018.8.0破解文件-小笨\\readme.txt"));

        System.out.println("客户端:我开始向服务器上传数据");

        byte[] bytes = new byte[512];
        int lenth = 0;
        while ((lenth = biStream.read(bytes))!=-1){
            outputStream.write(bytes,0,lenth);
        }
        //不写的话服务器将不知道什么时候才将文件上传结束
        socket.shutdownOutput();

        InputStream inputStream = socket.getInputStream();

        lenth = 0;
        while ((lenth = inputStream.read(bytes))!=-1){
            System.out.println(new String(bytes,0,lenth));
        }

        System.out.println("客户端:数据上传完毕");

        biStream.close();
        socket.close();
    }
}

服务端:

public class TcpFileServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);

        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();

        File file = new File("I:\\chenpengFiles\\test");
        if (!file.exists()){
            file.mkdirs();
        }

        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                new FileOutputStream(file+"//test.txt"));
        System.out.println("服务器:开始上传文件");
        byte[] bytes = new byte[512];
        int lenth = 0;
        while ((lenth = inputStream.read(bytes))!=-1){
            bufferedOutputStream.write(bytes,0,lenth);
        }

        socket.getOutputStream().write("文件上传成功!".getBytes());

        System.out.println("服务器:文件上传成功");
        bufferedOutputStream.close();
        socket.close();
        serverSocket.close();
    }
}

优化版:

public class TcpFileServerThread {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true){
            Socket socket = serverSocket.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        InputStream inputStream = socket.getInputStream();

                        File file = new File("I:\\chenpengFiles\\test");
                        if (!file.exists()){
                            file.mkdirs();
                        }
                        String fileName = "\\"+new Random().nextInt(99999)+".txt";
                        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                                new FileOutputStream(file+fileName));
                        System.out.println("服务器:开始上传文件");
                        byte[] bytes = new byte[512];
                        int lenth = 0;
                        while ((lenth = inputStream.read(bytes))!=-1){
                            bufferedOutputStream.write(bytes,0,lenth);
                        }

                        socket.getOutputStream().write("文件上传成功!".getBytes());

                        System.out.println("服务器:文件上传成功");
                        bufferedOutputStream.close();

                    }catch (IOException e){
                        System.out.println(e.getMessage());
                        throw new RuntimeException();
                    }finally {
                        try {
                            socket.close();
                        }catch (Exception e){
                            throw new RuntimeException();
                        }
                    }
                }
            }).start();
        }
    }
}

4. 模拟BS服务器案例

code:

public class WebServer {
    private String paths = "H:\\javaCode\\ideaCode\\java2019\\demo\\src\\com\\looc\\demo12网络编程\\demo2\\";

    public void webServer() throws IOException {
        ServerSocket serverSocket = new ServerSocket(80);

        //监听事件
        while (true){
            //拿到socket对象
            Socket socket = serverSocket.accept();

            //开启多线程提高效率
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        InputStream inputStream = socket.getInputStream();

                        //读响应体
                        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"US-ASCII"));

                        //读取到文件
                        String str = br.readLine().split(" ")[1].substring(1);
                        BufferedInputStream bfs = new BufferedInputStream(
                                new FileInputStream(paths+str));

                        //回显
                        OutputStream oStream = socket.getOutputStream();
                        oStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                        oStream.write("Content-Type:text/html\r\n".getBytes());
                        oStream.write("\r\n".getBytes());

                        byte[] bytes = new byte[1024];
                        int len = 0;
                        while ((len = bfs.read(bytes))!=-1){
                            oStream.write(bytes,0,len);
                        }
                        //关闭流
                        bfs.close();
                        br.close();
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }finally {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

        }
    }


    public static void main(String[] args) throws IOException {
        WebServer webServers = new WebServer();
        webServers.webServer();
    }
}

你可能感兴趣的:(java 网络编程)