Java网络编程套接字

news2024/11/15 7:42:54

文章目录

  • 1、网络编程基础
  • 2、Socket套接字
    • 2.1 Java数据报套接字通信模型
    • 2.2 Java流式套接字通信模型
    • 2.3 Socket编程注意事项
  • 3、UDP数据报套接字编程
  • 4、TCP流式套接字编程

1、网络编程基础

在没有网路之前,两个进程只能在同一主机上进行通信,但是无法跨距离实现通信。但是通过网络,进程之间就能跨距离通信。网络是信息传输、接收、共享的虚拟平台,通过它把各个点、面、体的信息联系到一起,从而实现这些网络资源的共享。

所谓的网络资源,其实就是在网络中可以获取的各种数据资源,并且所有的网络资源,都是通过网络编程来进行数据传输的

什么是网络编程?
网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)

在这里插入图片描述

当然,我们只要满足进程不同就行;所以即便是同一个主机,只要是不同进程,基于网络来传输据,也属于网络编程。

特殊的,对于开发来说,在条件有限的情况下,一般也都是在一个主机中运行多个进程来完成网络编

但是,我们一定要明确,我们的目的是提供网络上不同主机,基于网络来传输数据资源:

  • 进程A:编程来获取网络资源
  • 进程B:编程来提供网络资源

网络编程中的基本概念

发送端和接收端

在一次网络数据传输时:
发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念

在这里插入图片描述

请求和响应

一般来说,获取一个网络资源,涉及到两次网络数据传输

  • 第一次:请求数据的发送
  • 第二次:响应数据的发送

好比冯同学在食堂点了一份麻辣烫(贼香的那种):
冯同学要发起请求:点一份麻辣烫
其次,食堂阿姨提提供对应的响应:提供一份麻辣烫

在这里插入图片描述

客户端和服务端

服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务
客户端获取服务的一方进程,称为客户端

对于服务来说,一般是提供:

  • 客户端获取服务资源

在这里插入图片描述

  • 客户端保存资源在服务端

在这里插入图片描述

好比在银行办事:

  • 银行提供存款服务:用户(客户端)保存资源(现金)在银行(服务端)
  • 银行提供取款服务:用户(客户端)获取服务端资源(银行替用户保管的现金)

常见的客户端服务端模型

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:

  1. 客户端先发送请求到服务端
  2. 服务端根据请求数据,执行相应的业务处理
  3. 服务端返回响应:发送业务处理结果
  4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)

在这里插入图片描述

2、Socket套接字

概念
Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程

分类
Socket套接字主要针对传输层协议划分为如下三类:
流式套接字:使用传输层TCP协议
TCP,即Transmission Control Protocol(传输控制协议),传输层协议
以下为TCP的特点

有连接
可靠传输
面向字节流
有接收缓冲区,也有发送缓冲区
大小不限

对于字节流来说,可以简单的理解为,传输数据是基于IO流,流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收

数据报套接字:使用传输层UDP协议
UDP,即User Datagram Protocol(用户数据报协议),传输层协议
以下为UDP的特点

无连接
不可靠传输
面向数据报
有接收缓冲区,无发送缓冲区
大小受限:一次最多传输64k

对于数据报来说,可以简单的理解为,传输数据是一块一块的,发送一块数据假如100个字节,必须一次发送,接收也必须一次接收100个字节,而不能分100次,每次接收1个字节

原始套接字
原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据

2.1 Java数据报套接字通信模型

对于UDP协议来说,具有无连接,面向数据报的特征,即每次都是没有建立连接,并且一次发送全部数据报,一次接收全部的数据报

java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用DatagramPacket 作为发送或接收的UDP数据报。对于一次发送及接收UDP数据报的流程如下:

在这里插入图片描述

以上只是一次发送端的UDP数据报发送,及接收端的数据报接收,并没有返回的数据。也就是只有请
求,没有响应。对于一个服务端来说,重要的是提供多个客户端的请求处理及响应,流程如下:

在这里插入图片描述

2.2 Java流式套接字通信模型

流式套接字和数据报套接字通信方式有所不同,前者在通信之间需要建立连接,而且支持双向通信

在这里插入图片描述

2.3 Socket编程注意事项

  1. 客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但真实的场
    景,一般都是不同主机。
  2. 注意目的IP和目的端口号,标识了一次数据传输时要发送数据的终点主机和进程
  3. Socket编程我们是使用流套接字和数据报套接字,基于传输层的TCP或UDP协议,但应用层协议也需要考虑,这块我们在后续来说明如何设计应用层协议。
  4. 关于端口被占用的问题

如果一个进程A已经绑定了一个端口,再启动一个进程B绑定该端口,就会报错,这种情况也叫端
口被占用。对于java进程来说,端口被占用的常见报错信息如下:

在这里插入图片描述

此时需要检查进程B绑定的是哪个端口,再查看该端口被哪个进程占用。以下为通过端口号查进程
的方式:

  • 在cmd输入 netstat -ano | findstr 端口号 ,则可以显示对应进程的pid。如以下命令显示了9090进程的pid

在这里插入图片描述

  • 在任务管理器中,通过pid查找进程

在这里插入图片描述

解决端口被占用的问题:

如果占用端口的进程A不需要运行,就可以关闭A后,再启动需要绑定该端口的进程B
如果需要运行A进程,则可以修改进程B的绑定端口,换为其他没有使用的端口

3、UDP数据报套接字编程

DatagramSocket API
DatagramSocket 是UDP Socket,用于发送和接收UDP数据报

DatagramSocket 构造方法:

方法方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端
DatagramSocket(intport)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端

DatagramSocket 方法:

方法方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacketp)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket API
DatagramPacket是UDP Socket发送和接收的数据报

DatagramPacket 构造方法:

方法方法说明
DatagramPacket(byte[]buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在一个字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[]buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

DatagramPacket 方法:

方法方法说明
InetAddressgetAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建

InetSocketAddress API

InetSocketAddress ( SocketAddress 的子类 )构造方法:

方法方法说明
InetSocketAddress(InetAddress addr, int port)创建一个Socket地址,包含IP地址和端口号

例1:将英文翻译为中文(UDP)

//UdpDictServer.java

package network;

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

public class UdpDictServer{
    private HashMap<String ,String> dict = new HashMap<>();


    public String process(String request) {
        return dict.getOrDefault(request, "字典中没有该词");
    }

    //进行网络编程,第一步就是要先准备好socket实例,这是进行网络编程的大前提
    private DatagramSocket socket = null;

    //这里出现SocketException是因为构造Socket对象有很多失败的可能
    //1.端口号被其他进程占用(例如两个人不能有相同的电话号码)
    //2.每个进程能够打开的文件个数是有上限的,如果进程之前已经打开了很多文件,就可能导致此处的socket文件不能顺利打开
    public UdpDictServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
        dict.put("cat","小猫");
        dict.put("dog", "小狗");
        dict.put("hello", "你好");
        dict.put("pig","小猪");
        dict.put("fengtongxue", "冯同学");
    }

    //启动服务器
    public void start() throws IOException {
        System.out.println("启动服务器!");
        //UDP不需要建立链接,直接接受从客户端来的数据即可
        while (true) {
            //1.读取客户端发送来的请求
            //DatagramPacket表示一个UDP数据报
            //发送一次数据,就是在发送一个DatagramPacket
            //接受一次数据,也就在接受一个DatagramPacket
            DatagramPacket requestPacket = new DatagramPacket(new byte[1024], 1024);
            //如果没收到数据,就会阻塞在receive
            socket.receive(requestPacket);//为了接受数据,需要先准备好一个空间的DatagramPacket对象,由receive进行填充数据
            //把DatagramPacket解析成一个String
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength(), "UTF-8");

            //2.根据请求计算响应
            String response = process(request);

            //3.把响应写会客户端
            //IP和端口号合在一起的写法
            //response.getBytes().length拿到的是字节个数,不能写成response.length(),因为这是拿到的字符个数 
            //requestPacket.getSocketAddress(),指定数据要发给谁
            
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length, requestPacket.getSocketAddress());
            //发送数据
            socket.send(responsePacket);
            //打印请求的IP地址,端口号,请求以及响应
            System.out.printf("%s %d  req:%s , resp:%s\n",
                    requestPacket.getAddress().toString(), requestPacket.getPort(), request, response);
        }
    }


    public static void main(String[] args) throws IOException {
        UdpDictServer server = new UdpDictServer(9090);
        server.start();
    }
}
//UdpEchoClient.java

package network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;


public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;


    public UdpEchoClient(String ip, int port) throws SocketException {
        //此处的port是服务器的端口
        //客户端启动的时候,不需要给socket指定端口,客户端自己的端口是系统随机分配的
        //通常写代码的时候,客户端的端口号都是由系统指定的
        //而服务器端口号必须手动指定,后续客户端要根据这个端口号访问服务器
        //如果让系统随机分配,客户端就不知道服务器的端口号是啥,也就不能访问
        socket = new DatagramSocket();
        serverIP = ip;
        serverPort = port;
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            //1.先从控制台读取用户输入的字符串
            System.out.print("->");
            String request = scanner.next();

            //2.把用户输入的内容,构造成一个UDP请求,再发送数据
            //  构造的请求里包含两部分信息
            //  1)数据的内容,request 字符串
            //  2)数据要发给谁 服务器的IP+端口
            //IP和端口号分开的写法
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIP), serverPort);
            //发送数据
            socket.send(requestPacket);
            //3.从服务器读取响应数据,并解析
            DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(), 0,
                    responsePacket.getLength(), "UTF-8");
            //4.把响应结果显示到控制台上
            System.out.printf("req: %s, resp: %s\n", request, response);
        }
    }

    public static void main(String[] args) throws IOException {
    	//由于服务器和客户端在同一台计算机上,使用的IP仍然是127.0.0.1(本地环回),如果在不同的计算机上,就需要更改这里的IP地址
        UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

问题:为啥服务器上来就是接受,也不是发送呢?
因为,服务器的定义,就是"被动接受请求"的这一放
主动发送请求的一方,叫做客户端

注意:端口被占用的问题

一个服务器可以为很多个客户端提供服务。但是同一时刻服务器能够处理的客户端数目是一定存在上限的,因为服务器处理每个请求,都需要消耗一定的资源(包括但不限于CPU,内存,磁盘,宽带…)

至于是多少个,取决于:

处理一个请求,消耗多少资源
服务器一共有多少资源

在Java中并不容易精确的计算消耗多少资源,JVM里面有很多辅助的功能,也需要消耗额外的资源。在实际开发中,通过性能测试的方式,就知道服务器最大能给多少客户端提供服务

在idea中,当我们想再启动一个客户端时,可能会出现这样的问题

在这里插入图片描述

idea会提示我们,需要将上一个启动的实例关掉,才能再次启动。此时需要做以下操作,就可以重复启动实例

第一步:

在这里插入图片描述

第二步:

在这里插入图片描述

修改完毕后,就能多次启动客户端

通常情况下,一个服务器是要同时给多个客户端提供服务的
但是也有其他情况,一个服务器只给一个客户端提供服务,典型的就是分布式系统,两个节点之间的交互

4、TCP流式套接字编程

ServerSocket API
ServerSocket 是创建TCP服务端Socket的API

ServerSocket 构造方法:

方法方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法:

方法方法说明
Socketaccept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
voidclose()关闭此套接字

Socket API
Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法方法说明
Socket(String host, intport)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

例2:将英文翻译为中文(TCP)

//TcpEchoServer.java

package network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Scanner;

public class TcpEchoServer {
    //监听套接字
    private ServerSocket serverSocket = null;
    private HashMap<String, String> dict = new HashMap<>();

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
        dict.put("dog","小狗");
        dict.put("cat","小猫");
        dict.put("pig","小猪");
        dict.put("fengtongxue","冯同学");
    }

    public void start() throws IOException {
        System.out.println("服务启动成功");
        while (true) {
            //如果没有客户端进行请求连接,将阻塞在accept()上
            //accept()成功后返回一个Socket对象,称为clientSocket,后续和客户端进行通信,都是通过clientSocket完成的
            Socket clientSocket = serverSocket.accept();
            //处理通信
            processConnection(clientSocket);

            //ServerSocket专门负责建立连接,Socket专门负责通信
        }
    }

    private void processConnection(Socket clientSocket) {
        System.out.printf("[%s %d] 客户端建立链接\n", clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //接下来处理请求和响应

        //这里针对tcp socket的读和写跟文件的读和写是一样的
        try (InputStream inputStream = clientSocket.getInputStream()) {
            try(OutputStream outputStream = clientSocket.getOutputStream()) {
                //循环处理每个请求,分别返回响应
                Scanner scanner = new Scanner(inputStream);
                //1.读取请求
                while (true) {
                    if (!scanner.hasNext()) {
                        System.out.printf("[%s %d] 客户端断开链接!", clientSocket.getInetAddress(), clientSocket.getPort());
                        break;
                    }
                    //此处用这个Scanner更方便,如果不用Scanner,就用原生的InputStream的read也可以
                    String request = scanner.next();


                    //2.根据请求,计算响应
                    String response = process(request);

                    //3.把这个响应返回给客户端
                    //为了方便起见,可以使用PrintWriter把outputStream包裹一下
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    //将响应数据发送给客户端
                    printWriter.println(response);
                    //刷新缓冲区,如果没有这个刷新,可能客户端就不能第一时间看到响应结果
                    printWriter.flush();
					
					//打印客户端的IP,端口号,请求和响应
                    System.out.printf("[%s %d] req:%s resp:%s\n",clientSocket.getInetAddress().toString(),
                            clientSocket.getPort(), request, response);

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //记得关闭socket
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String process(String request) {
        return dict.getOrDefault(request, "无该单词");
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start();
    }
}

//TcpEchoClient.java

package network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Scanner;

public class TcpEchoClient {
    //用普通的 socket即可,不用 ServerSocket
    //此处也不用手动给客户端指定端口,让系统自由分配
    private Socket socket = null;

    public TcpEchoClient(String serverIP, int port) throws IOException {
        //其实这里IP和port是可以给的,但是这里给了之后,含义不同
        //这里传入的ip和端口号的含义不同表示的不是自己绑定,而是表示和这个ip端口建立链接
        //调用这个构造方法,就会和服务器建立链接
        socket = new Socket(serverIP, port);
    }

    public void start() {
        System.out.println("和服务器连接成功");
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream()) {
            try (OutputStream outputStream = socket.getOutputStream()) {
                while (true) {
                    //1.从控制到读取数据
                    System.out.print("->");
                    String request = scanner.next();
                    //2.根据读取到的字符串,构造请求,把请求发送给服务器
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(request);
                    printWriter.flush();//如果不刷新,可能服务器无法及时看到数据
                    //3.从服务读取响应,并解析
                    Scanner respScanner = new Scanner(inputStream);
                    String response = respScanner.next();
                    //4.把结果显示到控制台上
                    System.out.printf("req:%s , resp:%s\n", request, response);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

在上述代码中,针对这里的clientSocket特意关闭了一下,但是对于ServerSocket就没有关闭。
同样的在UDP版本的代码里,也没有针对socket的关闭,这是为什么呢?

因为关闭的目的是为了"释放资源",释放资源的前提是已经不再使用这个资源了。对于UDP的程序和serversocket来说,这些socket都是贯穿程序始终的,这些资源最迟也就是跟随进程的退出一起释放(进程才是分配资源的基本单位,而线程是CPU调度的基本单位)

先启动Server端,再启动Client端

虽然这个代码已经可以运行,但是此时还有一个很严重的问题,就是当前的服务器,同一时刻只能处理一个连接!

为啥当前的服务器,同一时刻只能处理一个客户端?
能够和客户端交互的前提是,要先调用accept,接受连接,当和第一个客户端建立连接够,会进行相互通信,如果当前这个客户端没有断开连接,就无法再次调用accept,也就不能接受第二个客户端的连接,因此同一时刻只能处理一个客户端。

想要解决上述问题,就得让processConnection的执行,和前面的accept的执行相互不干扰,不能让processConnection里面的循环导致accept无法及时调用,因此,得使用多线程

为啥前面的UDP版本的程序没用多线程,也能处理多个客户端?
因为UDP不需要处理连接,UDP是无连接的,UDP只需要一个循环,就能处理所有的客户端请求。
但是此处,TCP既要处理连接,又要处理一个连接的若干次请求,就需要两个循环,里层循环就会影响到外层循环的进度。

因此,主线程循环调用accept,当有客户端连接上来的时候,就直接让主线程创建一个新线程,由新线程负责对客户端的若干请求提供服务(新线程里,通过while循环来处理请求)。这个时候,多个线程是并发执行,就不会相互干扰。也要注意,每个客户端连上来都得分配一个线程

例3:将英文翻译为中文(TCP),线程版——只需要进行小小的改动

public void start() throws IOException {
    System.out.println("服务启动成功");
    while (true) {
        //如果没有客户端进行请求连接,将阻塞在accept()上
        //accept()成功后返回一个Socket对象,称为clientSocket,后续和客户端进行通信,都是通过clientSocket完成的
        Socket clientSocket = serverSocket.accept();
        //[改进方法] 在这个地方,每次accept成功,都创建一个新的线程,由这个新线程来执行processConnection方法,进行通信
        Thread t = new Thread(()->{
            processConnection(clientSocket);
        });
        t.start();

    }
}

看到这里,有同学可能有一个疑问,在没使用多线程的情况下,多个客户端和服务器建立连接时,明明却提示了已经建立连接成功,这和除了第一个客户端能进行通信,其他客户端都不能通信相矛盾,为什么是这样呢?

因为当客户端new Socket成功的时候,其实在操作系统内核层面,已经建立好连接了(TCP三次握手已经成功),但是应用程序还能接受这个连接

既然能用线程解决这个问题,那么就一定能用线程池解决,并且线程池还能进一步提高效率

例4:将英文翻译为中文(TCP),线程池版——只需要进行小小的改动

public void start() throws IOException {
    System.out.println("服务启动成功");
    //创建一个线程池
    ExecutorService pool = Executors.newCachedThreadPool();
    while (true) {
        Socket clientSocket = serverSocket.accept();
        //让线程池中的线程处理通信
        pool.submit(new Runnable() {
            @Override
            public void run() {
                processConnection(clientSocket);
            }
        });
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12809.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【kubernetes篇】使用Nfs实现kubernetes持久化存储

引言 在kubernetes使用的过程中&#xff0c;有很多数据需要持久化保存。而kubernetes本身不能实现这样的功能&#xff0c;所以需要提供外部存储来实现。nfs网络文件系统&#xff0c;能良好支持pv动态创建等功能&#xff0c;是一个不错的持久化保存方式。今天将这一部分内容作以…

jsx代码如何变成dom

jsx代码如何变成dom一、三个问题考察对jsx的理解二、jsx的本质以及它和js之间是什么关系&#xff1f;2.1 jsx是什么2.2 和js的关系2.3 jsx的本质三、为什么要用jsx&#xff1f;不用会有什么后果四、jsx背后的功能模块是什么&#xff1f;这个功能模块都做了哪些事情&#xff1f;…

DVWA 之 SQL注入(非盲注)

文章目录SQL注入1.判断是否存在注入&#xff0c;注入是字符型还是数字型2.猜解SQL查询语句中的字段数3.确定显示的字段顺序4.获取当前数据库5.获取数据库中的表6.获取表中的字段名7.下载数据SQL注入 步骤&#xff1a; 1.判断是否存在注入&#xff0c;注入是字符型还是数字型 2…

数据库平滑扩容方案剖析

1. 扩容方案剖析 1.1 扩容问题 在项目初期&#xff0c;我们部署了三个数据库A、B、C&#xff0c;此时数据库的规模可以满足我们的业务需求。为了将数据做到平均分配&#xff0c;我们在Service服务层使用uid%3进行取模分片&#xff0c;从而将数据平均分配到三个数据库中。 如…

4-6 最小生成树Prim,Kruskal(贪心)

4.6最小生成树 Prim,Kruskal(贪心) 一、问题描述 设G (V,E)是无向连通带权图&#xff0c;即一个网络。E中每条边(u,v)的权为 c[u][v]。 如果G的子图G’是一棵包含G的所有顶点的树&#xff0c;则称G’为G的生成树。生成树上各边权的总和称为该生成树的耗费。 在G的所有生成树中…

java计算机毕业设计基于安卓Android的校园快药APP-药店管理app

项目介绍 本文介绍了校园快药APP软件开发建设的意义和国内外发展现状,然后详细描述了所开发手机APP的可行性分析,并分析了手机APP所要实现的功能。因为校园快药设施较多,而且人口密集,不能更好的管理校园快药,造成需要时患者不必要的伤亡,所以采用比较方便的、容易便携的手机AP…

[附源码]Python计算机毕业设计Excel操作题自动评分系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

基于PHP+MySQL的企业宣传展示网

随着互联网的发展,企业越来越重视网上宣传渠道了。谢现在各大企业都有了自己的官网,以达到宣传企业或方便客户了解企业的目的。PHP企业宣传展示网分为前台和后台两部分。前台不部分主要是让用户了解和查看及动态等信息,使用的后台部分主要是企业的管理人员对网站的信息进行管理…

股票系统接口是如何进行数据共享的?

股票系统接口系统在量化交易中常见的一种数据挖掘系统&#xff0c;就比如说&#xff0c;如果你想要从别的网站或服务器上获取资源或信息&#xff0c;别人是不会把数据库共享过来的&#xff0c;他只能给你提供一个他们写好的编程方法来获取数据。也就是说通过股票系统接口输入你…

springboot15:junit5的使用

1.测试平台Junit springboot新版使用junit 只需要标注一个注解SpringBootTest然后方法中标注Test即可 以前springboot的使用 比较困难 现在整合使用后 只需要编写测试方法Test写测试的逻辑&#xff0c;整个类具有spring的功能&#xff0c;比如事务&#xff08;测试完成后会自动…

补盲激光雷达「PK」4D成像雷达,车企会作何选择?

关于4D成像雷达和激光雷达的争论&#xff0c;在此之前&#xff0c;两方势力之间还是有些克制。「谁也不是替代谁」&#xff0c;成了各方一致的看法。目标&#xff0c;也很一致&#xff0c;就是补齐摄像头的物理性能缺陷。 比如&#xff0c;与激光雷达相比&#xff0c;4D成像雷…

Python之第十一章 面向对象 --- 基础

目录 1.面向对象编程思想 1.编程思想 2.面向过程编程思想 3.面向对象编程思想 例 面向对象报名案例分析 面向过程与面向对象的区别 2.面向对象专业术语 1.组成 2.对象&#xff08;object&#xff09; 3.类&#xff1a; 1.引入类的原因 2.定义&#xff1a; 3.类的定…

2022HDC见闻与新技术学习体验分享

一、创新照见未来&#xff0c;共建鸿蒙世界&#xff0c;主题演讲笔记 以创新照见未来&#xff0c;共建鸿蒙世界为主题的第四界HDC大会于2022年11月4日在东莞松山湖线上与线下同时开启。本次大会展示了鸿蒙生态的最新成果与发展规划。第一天的主题演讲中&#xff0c;华为发布了解…

06-HTTPS单向认证及Java案例

一、单向认证流程 单向认证流程中&#xff0c;服务器端保存着公钥证书和私钥两个文件&#xff0c;整个握手过程如下&#xff1a; 客户端发起建立HTTPS连接请求&#xff0c;将SSL协议版本的信息发送给服务器端&#xff1b;服务器端将本机的公钥证书&#xff08;server.crt&am…

Windows - WINS Service

WINS SERVICE配置工作任务 安装及配置 WINS 服务; 配置为DCserver 为主WINS服务器。 WINS server - Windows server 更新 1-1 查看计算机名称 1-2 命令查看计算机名称: win+R---->>powerShell---->>命令nbtstat -n 1-3 查

《FFmpeg Basics》中文版-05-裁剪视频

正文 裁剪视频意味着从输入到输出中选择想要的矩形区域而没有余数。 裁剪通常用于调整大小&#xff0c;填充和其他编辑。 裁剪基础知识 较老的FFmpeg版本有cropbottom、cropleft、cropright和croptop选项&#xff0c;但现在已弃用&#xff0c;并使用下表中描述的裁剪操作。 …

微服务分布式开源架构是什么?

微服务分布式开源架构跟单体应用比起来有着较大的优势&#xff0c;可以解决单体系统的不足之处&#xff0c;满足日益增多的业务量需求。那么&#xff0c;微服务分布式开源架构是什么&#xff1f;什么软件服务商的微服务架构比较适合&#xff1f; 一、微服务分布式开源架构是什么…

nmap各种扫描的注意事项

1) nmap -sS 192.168.0.100 TCP的SYN扫描&#xff0c;也称为stealth扫描&#xff0c;扫描时&#xff0c;发送一个SYN包&#xff0c;等待SYN/ACK响应&#xff0c;当能够收到SYN/ACK响应时&#xff0c;就认为该端口是开放的。SYN扫描是一个速度极快而且结果又准的扫描&#xff0…

Linux 进程通信深剖

目录传统艺能&#x1f60e;进程间通信&#x1f914;通信方式&#x1f914;管道&#x1f914;匿名管道&#x1f914;pipe&#x1f914;匿名管道使用&#x1f914;读写规则&#x1f914;管道特点&#x1f914;同步与互斥&#x1f60b;管道生命周期&#x1f60b;流式服务&#x1f…

Nginx反向代理

代理概述 正向代理代理的对象是客户端&#xff0c;反向代理代理的是服务端&#xff0c;Nginx即可以实现正向代理&#xff0c;也可以实现反向代理。 正向代理 反向代理 正向代理案例 理论上Nginx可以支持正向代理上网&#xff0c;但是在实验中&#xff0c;域名访问有问题&am…