18.网络编程

网路编程入门

网络编程概述

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

image-20201022174238963

网络编程

  • 在网络通信写一下, 实现网络互连的不同计算机上运行的程序间可以进行数据交换.

网络编程三要素

ip地址:

  • 计算机在网络中的标志号, 用于找到改计算机

端口

  • 网络通信, 本质上是两个应用程序通信. 端口号就是计算机上用来唯一标识设备中的应用程序.

协议

  • 同一个网络的计算机连接和通讯时需要遵守一定的规则.称为网络通信协议, 对数据的传输格式, 传输速率, 传输步骤做了统一的规则, 必须同时遵守,才能完成数据交换. 常见UDP和TCP

IP地址

IP地址: 设备在网络中的唯一标识

IP地址分类:

  • IPV4: 给连接在网络上的每一台主机分配一个32bit的地址, 按照TCP/IP堆顶, 使用二进制表示,每个长32bit, 也就是4个字节. 一般用"点分十进制表示", 如"192.168.1.66"

  • IPV6: 为了扩大地址空间, 重新定义IPV6规则, 采用128位地址长度, 分成8组,每组16个字节

查看命令

  • ipconfig: 查看本机Ip地址
  • ping IP地址: 检查网络是否连通

InetAddress类

为了方便对IP地址的获取和操作, java提供了一个类InetAddress供使用

InetAddress: 此类表示Internet协议(IP)地址

方法名 说明
Static InetAddress getByName(String host) 确定主机名的IP地址, 主机名可以是机器名称, 也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串

Demo

package netProgram;

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

public class inetAddress {
    public static void main(String[] args) throws UnknownHostException {
        // Static InetAddress getByName(String host): 确定主机名的IP地址, 主机名可以是机器名称, 也可以是IP地址
        // InetAddress address = InetAddress.getByName("mac");
        InetAddress address = InetAddress.getByName("192.168.110.47");

        // String getHostName(): 获取此IP地址的主机名
        String name = address.getHostName();

        // public String getHostAddress(): 返回文本显示中的IP地址字符串
        String ip = address.getHostAddress();

        System.out.println("主机名:" + name);
        System.out.println("IP地址:" + ip);
    }

}

端口

端口是设备上应用程序的唯一标识

用两个字节表示的整数, 取值范围是0~65535. 其中, 0~1023之间的端口用于一些知名网络服务和应用. 端口占用会导致程序启动失败.

协议

协议: 计算机中, 连接和通信的规则被称为网络通信协议

UDP协议:

  • 用户数据报协议(User Datagram Protocal)
  • 无连接通信协议, 消耗小, 通信效率高, 用于音频, 视频和普通数据的传输

TCP协议:

  • 传输控制协议(Transminssion Control Protocal)

  • 面向连接的通信协议, 提供可靠无差错的数据传输. 必须明确客户端与服务器端, 有客户端向服务器发出连接请求, 每次连接经过"三次握手", 端口经过"四次挥手".

UDP通信原理

UDP是一种不可靠协议, 在通信两端个建立一个Socket对象, 但是这两个Socket只是发送, 接受数据的对象.

Java提供了DatagramSocket类作为基于UDP协议的socket

UDP发送数据

Demo

package netProgram;

import java.io.IOException;
import java.net.*;

public class UDPSendDemo {
    public static void main(String[] args) throws IOException {
        // 创建发送端的Socket对象(DatagramSocket)
        // DatagramSocket(): 构造数据报套接字并将其绑定到本地主机的任何可用端口
        DatagramSocket ds = new DatagramSocket();

        // 创建数据,并打包
        // DatagramPacket (byte[] buf, int length, InetAddress address, int port): 构造一个数据包, 发送长度为length的数据报到指定主机上的指定端口
        byte[] bys = "hello, i am comming".getBytes();
        // int length = bys.length;
        // InetAddress address = InetAddress.getByName("mac");
        // int port = 10086;
        // DatagramPacket dp = new DatagramPacket(bys, length, address, port);
        DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("mac"), 10086);

        // 调用DatagramSocket发送数据的方法
        // void send(DatagramPacket p) 从此套接字发送数据报包
        ds.send(dp);

        // 关闭发送端
        ds.close();
    }
}

UDP接受数据

Demo

package netProgram;

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

public class UDPRecvDemo {
    public static void main(String[] args) throws IOException {
        // 创建发送端的Socket对象(DatagramSocket)
        // DatagramSocket(int port): 构造数据报套接字并将其绑定到本地主机的指定端口
        DatagramSocket ds = new DatagramSocket(10086);

        // 创建数据包, 接受数据
        // DatagramPacket (byte[] buf, int length): 构造一个数据包,用于接受长度length数据报
        byte[] bys = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, bys.length);

        // 调用DatagramSocket接受数据的方法
        // void receive(DatagramPacket p) 从此套接字接收数据报包
        ds.receive(dp);

        // 解析数据包
        // byte[] getData(): 返回数据缓冲区数据
        byte[] data = dp.getData();
        // int getLength(): 获取返回数据的长度
        int len = dp.getLength();
        String dataString = new String(data, 0, len);
        System.out.println("数据是:" + dataString);

        // 关闭发送端
        ds.close();
    }
}

UDP通信案例

UDPSendDemo

package netProgram.correspondence;

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

public class UDPSendDemo {
    public static void main(String[] args) throws IOException {
        // 创建socket对象
        DatagramSocket ds = new DatagramSocket();

        // 自己封装键盘录入数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while ((line=br.readLine())!=null) {
            if ("886".equals(line)) {
                break;
            }
            // 创建数据并打包
            byte[] bys = line.getBytes();
            DatagramPacket dp = new DatagramPacket(bys,bys.length, InetAddress.getByName("mac"), 12345);

            // 发送数据
            ds.send(dp);
        }
        // 关闭
        ds.close();
    }
}

UDPRecvDemo

package netProgram.correspondence;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPRecvDemo {
    public static void main(String[] args) throws IOException {
        // 创建socket对象
        DatagramSocket ds = new DatagramSocket(12345);

        while (true) {
            // 创建数据包接收数据
            byte[] bys = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bys, bys.length);

            // 接收数据
            ds.receive(dp);

            // 解析数据包, 并把数据在控制台显示
            System.out.println("数据:" + new String(dp.getData(),0, dp.getLength()));
        }

    }
}

TCP通信原理

TCP通信是一种可靠的网络协议, 他在通信两端各建立一个Socket对象, 从而在通信的两端形成网络虚拟链路, 一旦建立虚拟的网络链路, 两端的程序可以通过虚拟链路进行通信

Java对TCP协议的网络进行了封装, 使用Socket对象来代表两端的通信端口, 通过Socket产生IO流来进行网络通信

TCP发送数据

发送数据步骤

  1. 创建客户端Socket对象(Socket)
  2. 获取输出流, 写数据
  3. 释放资源

TCPClientDemo

package netProgram.tcp;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建Socket对象
        // Socket(InetAddress address, int port): 创建流套接字并将其连接到指定IP地址的指定端口
        // Socket s = new Socket(InetAddress.getByName("mac"), 10000);

        // Socket(String host, int port): 创建流套接字并将其连接到指定IP地址的指定端口
        Socket s = new Socket("192.168.110.47", 10000);

        // 获取输出流, 写数据
        // OutputStream getOutputStream() 返回此套接字的输出流
        OutputStream os = s.getOutputStream();
        os.write("hello, tcp, i am comming".getBytes());

        // 释放资源
        s.close();
    }
}

TCP接收数据

接受数据步骤

  1. 创建服务器端的Socket对象(ServerSocket)
  2. 监听客户端连接, 返回一个Socket对象
  3. 获取输入流, 读数据, 并把数据显示在控制台
  4. 释放资源

TCPServerDemo

package netProgram.tcp;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        // ServerSocket​(int port): 创建绑定到指定端口的服务器套接字
        ServerSocket ss = new ServerSocket(10000);

        // Socket accept(): 侦听对此套接字的连接并接受它
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并且将数据显示在控制台
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String data = new String(bys, 0, len);
        System.out.println("数据:" + data);

        // 释放资源
        s.close();
        ss.close();
    }
}

TCP通信案例

TCPClientDemo

package netProgram.correspondence;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象(Socket)
        Socket s = new Socket("192.168.110.47", 10000);

        // 获取输出流,写数据
        OutputStream os = s.getOutputStream();
        os.write("hello, tcp, i am comming".getBytes());

        // 接收服务器反馈
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String data = new String(bys, 0, len);
        System.out.println("客户端:" + data);

        // 释放资源
        s.close();  // 会关闭 is, os 资源

    }

}

TCPServerDemo

package netProgram.correspondence;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        // 监听客户端连接, 返回一个Socket对象
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并把数据显示在控制台
        InputStream is = s.getInputStream();
        byte[] bys = new byte[1024];
        int len = is.read(bys);
        String data = new String(bys, 0, len);
        System.out.println("服务器:" + data);

        // 给出反馈
        OutputStream os = s.getOutputStream();
        os.write("数据已经收到".getBytes());

        // 释放资源
        // s.close();
        ss.close();  // 这一步也会关闭s
    }

}

案例二: 字符流实现

TCPClientDemo

package netProgram.TCPCorrespondence;

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

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket s = new Socket("192.168.110.47", 10000);

        // 数据来自键盘输入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        // 封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String line;
        while ((line=br.readLine())!=null){
            if ("886".equals(line)){
                break;
            }
            // 获取输出对象流
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        s.close();
    }
}

TCPServerDemo

package netProgram.TCPCorrespondence;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        // 监听客户端连接, 返回一个Socket对象
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并把数据显示在控制台
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line;
        while ((line=br.readLine())!=null) {
            System.out.println(line);
        }

        // 释放资源
        // s.close();
        ss.close();  // 这一步也会关闭s
    }

}

案例三: 接受数据写入文本

TCPClientDemo一致

TCPServerDemo

package netProgram.TCPCorrespondence.demo2;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        // 监听客户端连接, 返回一个Socket对象
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并把数据显示在控制台
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/tcp.txt"));
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        // s.close();
        bw.close();
        ss.close();  // 这一步也会关闭s
    }

}

案例四: 客户端数据来自文件, 服务器写入文本

TCPClientDemo

package netProgram.TCPCorrespondence.demo3;

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

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket s = new Socket("192.168.110.47", 10000);

        // 封装文本文件的数据
        BufferedReader br = new BufferedReader(new FileReader("learn_java/tcp.txt"));
        // 封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String line;
        while ((line=br.readLine())!=null){
            // 获取输出对象流
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        br.close();
        s.close();
    }
}

TCPServerDemo

package netProgram.TCPCorrespondence.demo3;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        // 监听客户端连接, 返回一个Socket对象
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并把数据显示在控制台
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/tcp_server.txt"));
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 释放资源
        // s.close();
        bw.close();
        ss.close();  // 这一步也会关闭s
    }

}

案例五: 上传文件, 并反馈

TCPClientDemo

package netProgram.TCPCorrespondence.demo4;

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

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket s = new Socket("192.168.110.47", 10000);

        // 封装文本文件的数据
        BufferedReader br = new BufferedReader(new FileReader("learn_java/tcp.txt"));
        // 封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String line;
        while ((line=br.readLine())!=null){
            // 获取输出对象流
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        // 自定义结束标记
        /*
        bw.write("886");
        bw.newLine();
        bw.flush();
         */

        // 使用java提供的停止方法
        // public void shutdownOutput
        s.shutdownOutput();

        // 接受反馈
        BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String data = brClient.readLine();  // 等待服务器响应
        System.out.println("响应:" + data);

        // 释放资源
        br.close();
        s.close();
    }
}

TCPServerDemo

package netProgram.TCPCorrespondence.demo4;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        // 监听客户端连接, 返回一个Socket对象
        Socket s = ss.accept();

        // 获取输入流, 读数据, 并把数据显示在控制台
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/tcp_server.txt"));
        String line;
        while ((line=br.readLine())!=null) {  // 一直在等待读取数据
            /*
            if("886".equals(line)){
                break;
            }
             */
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        // 给出反馈
        BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bwServer.write("文件上传成功");
        bwServer.newLine();
        bwServer.flush();

        // 释放资源
        // s.close();
        bw.close();
        ss.close();  // 这一步也会关闭s
    }

}

案例六: 多线程上传文件

ServerThread

package netProgram.TCPCorrespondence.demo5;

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

public class ServerThread implements Runnable {
    private Socket s;
    public ServerThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        // 接受数据写入文件
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            // BufferedWriter bw = new BufferedWriter(new FileWriter("learn_java/tcp_server5.txt"));
            // 处理名称冲突问题
            int count = 0;
            File file = new File("learn_java/tct_server" + count + ".txt");
            while (file.exists()) {
                count++;
                file = new File("learn_java/tct_server" + count + ".txt");
            }
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));

            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            // 给出反馈
            BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            bwServer.write("文件上传成功");
            bwServer.newLine();
            bwServer.flush();

            // 释放资源
            s.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

TCPClientDemo

package netProgram.TCPCorrespondence.demo5;

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

public class TCPClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建客户端Socket对象
        Socket s = new Socket("192.168.110.47", 10000);

        // 封装文本文件的数据
        BufferedReader br = new BufferedReader(new FileReader("learn_java/tcp.txt"));
        // 封装输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String line;
        while ((line=br.readLine())!=null){
            // 获取输出对象流
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        // 使用java提供的停止方法
        // public void shutdownOutput
        s.shutdownOutput();

        // 接受反馈
        BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String data = brClient.readLine();  // 等待服务器响应
        System.out.println("响应:" + data);

        // 释放资源
        br.close();
        s.close();
    }
}

TCPServerDemo

package netProgram.TCPCorrespondence.demo5;

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

public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 创建服务器端的Socket对象(ServerSocket)
        ServerSocket ss = new ServerSocket(10000);
        while (true){
            // 监听客户端连接, 返回一个Socket对象
            Socket s = ss.accept();
            // 为每个客户端开启一个线程
            new Thread(new ServerThread(s)).start();
        }
    }

}

原文地址:https://www.cnblogs.com/ryxiong-blog/p/13890464.html