网络编程(Java)

news2024/11/19 23:16:31

网络协议通信

IP和端口号

  要想使计算机能够通信,必需为每台计算机指定一个标识号,通过这个标识号指定接受数据的计算机或者发送数据的计算机。一般的,IP地址就是一个计算机的标识号,它可以唯一标识一台计算机。

  IP地址由两部分组成:网络地址和主机地址。在IPv4中,IP地址是32位二进制数字,通常用四个十进制数表示,每个数之间用句点分隔,如192.168.0.1。其中前面的三个数代表网络地址,最后一个数代表主机地址。

  在IPv4中,IP地址按照网络规模的不同可以分为5类,分别是A类、B类、C类、D类和E类。

A类地址:以0开头,第一个字节(即第一段地址)为网络地址,后三个字节(即第二段、第三段和第四段地址)为主机地址。A类地址范围从1.0.0.0到127.255.255.255,可以分配给大型网络。

B类地址:以10开头,前两个字节(即第一段和第二段地址)为网络地址,后两个字节(即第三段和第四段地址)为主机地址。B类地址范围从128.0.0.0到191.255.255.255,可以分配给中等规模的网络。

C类地址:以110开头,前三个字节(即第一段、第二段和第三段地址)为网络地址,最后一个字节(即第四段地址)为主机地址。C类地址范围从192.0.0.0到223.255.255.255,可以分配给小型网络。

D类地址:以1110开头,D类地址用于多点广播,范围从224.0.0.0到239.255.255.255。

E类地址:以1111开头,E类地址保留作实验和研究之用,范围从240.0.0.0到255.255.255.255。

另外还有一个回送地址127.0.0.1,指本机地址,一般用于测试。

  通过IP地址可以连接到指定计算机,但如果需要访问目标计算机某个程序,还需要指定端口号。

  端口号是一种用于标识计算机或设备上应用程序的网络地址的数字。在计算机网络中,每个应用程序都需要一个唯一的端口号来与其他应用程序通信。

常见的端口号包括:

HTTP(超文本传输协议)使用端口号80
HTTPS(加密的HTTP)使用端口号443
FTP(文件传输协议)使用端口号21
SSH(安全外壳协议)使用端口号22
Telnet(远程终端协议)使用端口号23
SMTP(简单邮件传输协议)使用端口号25
DNS(域名系统)使用端口号53
DHCP(动态主机配置协议)使用端口号67和68
POP3(邮局协议版本3)使用端口号110
IMAP(互联网消息访问协议)使用端口号143
端口号通常由16位数字组成,取值范围从0到65535。其中0到1023之间的端口号被保留用于系统级别的服务和应用程序,而1024到65535之间的端口号则可以被普通应用程序使用。

InetAddress

  Java中的一个与IP相关的类,封装了IP地址,提供了一系列与IP地址相关的方法。

常用方法:

 

import java.net.InetAddress;


public class Net {
    public static void main(String[] args) throws Exception {
        //获取本地主机InetAddress对象
        InetAddress localAddr=InetAddress.getLocalHost();
        //通过主机名获取InetAddress对象
        InetAddress remoteAddr=InetAddress.getByName("www.baidu.com");
        System.out.println("本机的IP地址: "+localAddr.getHostAddress());
        System.out.println("远程主机的IP地址: "+remoteAddr.getHostAddress());
        System.out.println("在3秒内是否可到达远程主机: "+remoteAddr.isReachable(3000));
        System.out.println("远程主机的名称: "+remoteAddr.getHostName());


    }
}

 控制台输出:

UDP与TCP 

  

  UDP(用户数据报协议)是互联网协议套件中的传输层协议之一,它是一种无连接的协议,不需要在数据传输前建立连接。UDP在传输数据时不提供可靠性、流量控制和拥塞控制等服务,但传输效率高,开销小,适合于一些对实时性要求高、但对数据可靠性要求不高的应用场景,如在线游戏、音视频传输、DNS查询等。

UDP的数据包称为用户数据报,它的数据包结构比较简单,包含以下几个字段:

源端口号(16位):标识发送方的端口号。

目的端口号(16位):标识接收方的端口号。

长度(16位):标识用户数据报的长度。

校验和(16位):用于检验用户数据报是否传输正确。

数据(可选):要传输的数据,长度可以为0到65535个字节。

UDP在传输数据时,不保证数据的可靠性和完整性,因此需要应用层自行处理这些问题。如果需要在UDP上实现可靠数据传输,需要在应用层上进行相应的处理,比如增加重传机制、数据校验和等。

  TCP(Transmission Control Protocol,传输控制协议)是一种基于连接的、可靠的、面向流的传输层协议,它提供了端到端的数据传输服务。TCP协议是因特网协议族中最常用的协议之一,它保证了数据传输的可靠性,确保数据从源到目的地的正确性和完整性。

TCP协议的特点包括:

基于连接:通信前需要建立连接,通信结束后需要释放连接,保证数据的可靠性。

可靠性:通过序列号和确认号机制,确保数据传输的正确性和完整性,可靠地传输数据。

面向流:数据在传输过程中被看作是一个连续的字节流,而不是分散的数据包。

全双工:通信双方可以同时发送和接收数据。

拥塞控制:通过拥塞控制机制,保证网络的稳定性和可靠性。

数据段首部:TCP协议在每个数据段的首部添加了序列号、确认号、窗口大小等控制信息,以保证数据的可靠性和完整性。

TCP协议的应用广泛,例如网页浏览、电子邮件、文件传输、远程登录等。

三次握手:

UDP通信 

  UDP是面向无连接的协议,通信时不需要发送端和接受端不需要建立连接。UDP通信过程,就像货运公司在两个码头间发送货物,在码头发送和接受货物需要使用集装箱来装载货物。UDP通信同样需要,发送和接收数据需要被集装箱”打包“,Java提供了DatagramPacket类,运输货物只有“集装箱”不够还需要“码头”。为此Java还提供了DatagramSocket类。

DatagramPacket 

构造方法与常用方法

DatagramSocket 

构造方法与常用方法

UDP网络程序 

  实现UDP需要创建一个发送端程序和接收端程序。运行时,必须先让接收端程序先运行,才能避免发送端找不到接收端而造成数据丢失问题。

建立接收端:



import java.net.DatagramPacket;
import java.net.DatagramSocket;

//接收端
public class receiver {
    public static void main(String[] args)throws Exception {
        byte[]buf=new byte[1024];//创建字节数组,用于接受数据
        //定义DatagramSocket对象,设置监听端口号
        DatagramSocket ds=new DatagramSocket(9949);
        //设置一个DatagramPacket对象用于接受数据
        DatagramPacket dp=new DatagramPacket(buf, buf.length);
        System.out.println("等待接受数据..");
        ds.receive(dp);//等待接受数据,没有数据则会都市
        //调用DatagramPacket方法获得接收到的信息
        //包括数据内容,长度,发送IP地址和端口号
        String  str=new String(dp.getData(),0,dp.getLength())+" From "+dp.getAddress().getHostAddress()+" : "+dp.getPort();
        System.out.println(str);
        ds.close();//释放资源


    }
}

运行后控制台:

编写发送端:

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

//发送端
public class sender {
    public static void main(String[] args) throws Exception{
        //创建一个Socket对象
        DatagramSocket ds=new DatagramSocket(8848);
        String data="UDP数据包";//要发送的数据
        byte[]arr=data.getBytes();//把定义字符串变为字节数组
        //创建一个要发送的数据包,包括要发送的数据数据长度,接收端IP地址以及端口号
        DatagramPacket dp=new DatagramPacket(arr,arr.length, InetAddress.getByName("localhost"),9949);
        System.out.println("发送信息..");
        ds.send(dp);//发送数据
        ds.close();
        
        
        
    }
}

 再运行发送端:

发送端控制台:

接收端控制台:

(注意:设置端口号时如果发送端口号已被占用,只需关掉端口号或者新建一个没有使用的端口号即可) 

多线程UDP网络程序

  当接收端程序处于阻塞状态,运行发送端程序,接收端就会收到发送端发送端数据而结束阻塞状态,完成程序运行。实际上,发送端可以无限发送数据,接收端也可以一直接受数据,例如,聊天程序发送端可以一直发送消息,接收端也可以一直接受消息,发送端和客户端都是多线程的。

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class threads_udp_demo {
    public static void main(String[] args) {
        new receice().start();
        new send().start();

    }
}
class receice extends Thread {
    @Override
    public void run() {
        try {
            //创建端口
            DatagramSocket socket = new DatagramSocket(6666);
            //创建数据包
            DatagramPacket packet = new DatagramPacket(new byte[1024],1024);
            while (true) {
                socket.receive(packet);//接受数据
                byte[]arr=packet.getData();
                int len=packet.getLength();
                String ip=packet.getAddress().getHostAddress();
                System.out.println(ip+" : "+new String(arr,0,len)+" 端口: "+packet.getPort());
            }

        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class send extends Thread {
    @Override
    public void run() {
        try {
            //创建端口
            DatagramSocket socket = new DatagramSocket(9999);
            Scanner sc=new Scanner(System.in);
            while (true){
                String data=sc.nextLine();
                if("quit".equals(data)){
                    break;
                }
                DatagramPacket packet = new DatagramPacket(data.getBytes(),data.getBytes().length,
                        InetAddress.getByName("localhost"),6666);
                socket.send(packet);
            }
            socket.close();


        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

 模拟微信聊天

(1)通过上述任务描述可知此任务是使用多线程与UDP通信相关知识实现的。要实现聊天窗口界面。首先需要定义一个实现聊天功能的类,类中需要定义访问聊天的输出语句,从而获取输入的发送端端口号、接收端端口号以及实现发送和接收功能的方法。

import java.util.Scanner;

public class Room {
    public static void main(String[] args) {
        System.out.println("欢迎使用聊天功能!");
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入您的账号:");
        int sendPort=sc.nextInt();
        System.out.println("请输入您要发送的账号:");
        int receivePort=sc.nextInt();
        System.out.println("系统启动..");
        //发送操作
        new Thread(new SendTask(sendPort),"发送端").start();

        //接受操作
        new Thread(new ReceiveTask(receivePort), "接收端").start();

    }
}


(2)实现发送数据的功能。该功能通过一个实现了Runnable接口的类实现,类中需要定义获取发送数据的端口号,并在实现run()的方法中,编写发送数据的方法。

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class SendTask implements Runnable{
    private int sendPort;//发送数据端口号
    //构造方法


    public SendTask(int sendPort) {
        this.sendPort = sendPort;
    }

    @Override
    public void run() {
        try {
            //创建端口对象
            DatagramSocket ds=new DatagramSocket();
            //输入发送数据
            Scanner sc=new Scanner(System.in);
            while (true){
                String data=sc.nextLine();
                byte[]buf=data.getBytes();
                DatagramPacket dp=new DatagramPacket(buf,buf.length,
                        InetAddress.getByName("127.0.0.255"),sendPort);
                //发送数据
                ds.send(dp);


            }

        }catch (Exception e) {
            e.printStackTrace();

        }

    }
}


(3)实现接收数据的功能。该功能通过一个实现了Runnable接口的类实现,类中需要定义获取接收数据的端口号,并在实现run()的方法中,编写显示接收到的数据的方法。

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveTask implements Runnable{
    private int receivePort;

    public ReceiveTask(int receivePort) {
        this.receivePort = receivePort;
    }

    @Override
    public void run() {
       try {
           //创建端口
           DatagramSocket ds=new DatagramSocket(receivePort);
           //创建packet
           byte[]buf=new byte[1024];
           DatagramPacket dp=new DatagramPacket(buf, buf.length);
           while (true){
               ds.receive(dp);
               //显示接收到数据
               String str=new String(dp.getData(),0,dp.getLength());
               System.out.println("收到 "+dp.getAddress().getHostAddress()+"" +
                       "发送的数据 : "+str);
           }

       }catch (Exception e) {
           e.printStackTrace();
       }

    }
}


(4)创建完所有的类与方法后,运行两次程序,同时开启两个窗口来实现聊天功能。

TCP通信

   TCP通信两端都需要创建Scoket对象,严格区分客户端和服务端,通信时,必须先由客户端连接服务器端才能实现通信,服务器端不能主动连接客户端,而且服务器端必须事先启动,等待客户端的连接。

  Java提供两个用于实现TCP程序的类,ServerSocket,用于标识服务器端;Socket,用于标识客户端。

  通信时,首先创建服务器对象,然后等待客户端连接;然后创建客户端对象,开启服务,客户端对象向服务器端发起连接请求,服务器端响应后,两者才能建立连接,开始通信。

ServerSocket

构造方法和常用方法:

 

 ServerSocket对象负责监听某台计算机的某个端口号,创建对象后,继续调用该对象的accept方法,接受来自客户端的请求。执行accept方法后,服务器程序发生阻塞,直到客户端发出连接请求,accept才会返回一个Socket对象用于与客户端实现通信,程序才能继续向下执行。

Socket

构造方法和常用方法:

 

 

 

 

 

 简易TCP网络程序

首先实现服务端:

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

public class Server {
    public static void main(String[] args)throws Exception {
        new TCPServer().listen();
    }


}
class TCPServer{
    private static final int PORT=7788;//定义端口号
    public void listen()throws Exception {//定义一个listen方法抛出异常
        ServerSocket ss=new ServerSocket(PORT);
        //调用accept方法接受数据
        Socket client=ss.accept();
        OutputStream os=client.getOutputStream();//获取客户端输出流
        System.out.println("开始与客户端交互数据..");
        //当客户端连接到服务器,向客户端输出数据
        os.write(("数据已传输").getBytes());
        Thread.sleep(5000);//模拟其他功能占用时间
        System.out.println("结束与客户端交互数据");
        os.close();
        client.close();

    }
}

 accept方法只有接收到了客户端访问才会停止阻塞。

客户端:

import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;

public class Client {
    public static void main(String[] args)throws Exception {
        new TCPClient().connect();

    }
}
class TCPClient {
    private static final int PORT=7788;//服务器端口号
    public void connect()throws Exception {
        //创建一个Socket连接指定计算机的端口号
        Socket client=new Socket(InetAddress.getLocalHost(),PORT);
        InputStream is=client.getInputStream();//得到服务器数据流
        byte[]buf=new byte[1024];
        int len=is.read(buf);//数据读取到缓冲区
        System.out.println("服务器端发送端数据: ");
        System.out.println(new String(buf,0,len));
        client.close();//关闭Socket对象,释放资源
    }
}

先运行服务器端,在运行客户端,查看控制台输出:


 

多线程TCP程序 

在日常需求中,经常会有多个客户端访问一个服务端,服务端应给每个客户端都开启对应Socket建立专线通信。

对上述Server代码进行修改:

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

public class Server {
    public static void main(String[] args)throws Exception {
        new TCPServer().listen();
    }


}
class TCPServer{
    private static final int PORT=7788;//定义端口号
    public void listen()throws Exception {//定义一个listen方法抛出异常
        ServerSocket ss=new ServerSocket(PORT);
        //不断接受客户端请求
        while (true){
            //调用accept方法接受数据
            Socket client=ss.accept();
            new Thread(){

                @Override
                public void run() {
                    OutputStream os;
                    try {
                        os=client.getOutputStream();//获取客户端输出流
                        System.out.println("开始与客户端交互数据..");
                        //当客户端连接到服务器,向客户端输出数据
                        os.write(("数据已传输").getBytes());
                        Thread.sleep(5000);//模拟其他功能占用时间
                        System.out.println("结束与客户端交互数据");

                    }catch (Exception e) {
                        e.printStackTrace();
                    }


                };
            }.start();

        }



    }
}

 运行,不断使用客户端,查看控制台输出:

 反转字符串

编写一个小程序。实现客户端向服务器传递一个字符串(键盘录入) ,服务器(多线程)将字符串反转后写回,客户端再次接读取到的是反转后的字符串。要求使用多线程与TCP通信相关知识实现。

 

 

(1)根据任务描述可以知道该程序用TCP通信技术实现,所以第一条就是定义客户端,键盘录入数据定义Scanner来实现,然后创建客户端指定IP地址和端口号,之后获取输出流,与输入流,最后将字符串写到服务器并将反转后的结果读出来打印在控制台。

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class Client {
       public static void main(String[] args) throws UnknownHostException,
                                                        IOException {
                 //创建键盘录如对象
        		Scanner sc = new Scanner(System.in);
                 //创建客户端,指定ip地址和端口号
        		Socket socket = new Socket("127.0.0.1", 8848);
        		BufferedReader br = new BufferedReader(new
                         InputStreamReader(socket.getInputStream()));	//获取输入流
                 //获取输出流
        		PrintStream ps = new PrintStream(socket.getOutputStream());
                  //将字符串写到服务器去
              ps.println(sc.nextLine());
         		System.out.println(br.readLine()); //将反转后的结果读出来
         		socket.close();
         	}
 }

(2)实现服务端的代码编写,首先创建服务端绑定客户端的端口号,并用Server的accept()方法接受客户端的请求。

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

public class Server {
    public static void main(String[] args)throws IOException {
        ServerSocket ss = new ServerSocket(8848);
        System.out.println("服务器启动,绑定8848端口.."); //不断接受客户端请求
        while (true) {
            //调用accept方法接受数据
            final Socket socket = ss.accept();
            new Thread() {

                @Override
                public void run() {
                    try {
                        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流
                        PrintStream ps = new PrintStream(socket.getOutputStream());
                        String line = br.readLine();
                        line = new StringBuilder(line).reverse().toString();
                        ps.println(line);//写回
                        socket.close();

                    } catch (IOException e) {
                        e.printStackTrace();
                    }


                }
            }.start();

        }
    }
}

(3)服务端定义run()方法实现之后获取输入输出流,将客户端发送过来的数据读取出来并采用链式编程的思想将字符串反转后返回到客户端。

查看控制台数据:

 

 文件上传

编写一个客户端向服务端上传文件的程序,要求使用TCP通信的的知识,完成将本地机器输入的路径下的文件上传到D盘中名称为upload的文件夹中。并把客户端的IP地址加上count标识作为上传后文件的文件名,即IP(count)的形式。其中,count随着文件的增多而增大,例如127.0.0.(1).jpg、127.0.0.(2).jpg。

(1)根据任务描述中使用TCP通信的知识实现文件上传功能可知,要实现此功能,需要定义一个服务器接收文件的程序和 一个客户端上传文件的程序。

(2)首先要编写服务器端程序来接收文件。服务器端需要使用ServerSocket对象的accept()方法接收客户端的请求,由于一个服务器可能对于多个客户端,所以当客户端与服务器端简历连接后,服务器需要单独开启一个新的线程来处理与客户端的交互,这时需要在服务器端编写开启新线程的方法。在新线程的方法中,需要获取客户端的端口号,并且使用输入输出流来传输文件到指定的目录中。

package tcp_demo;

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

public class FileServer {
    public static void main(String[] args) throws Exception {
        //创建ServerSocket对象
        ServerSocket serverSocket = new ServerSocket(10001);
        while (true) {
            // 调用accept()方法接收客户端请求,得到Socket对象
            Socket s = serverSocket.accept();
            // 每当和客户端建立Socket连接后,单独开启一个线程处理和客户端的交互
            new Thread(new ServerThread(s)).start();
        }
    }
}

class ServerThread implements Runnable {
	// 持有一个Socket类型的属性
	private Socket socket;

	// 构造方法中把Socket对象作为实参传入
	public ServerThread(Socket socket) {
		this.socket = socket;
	}

	public void run() {
		// 获取客户端的IP地址
		String ip = socket.getInetAddress().getHostAddress();
		// 上传图片个数
		int count = 1;
		try {
			InputStream in = socket.getInputStream();
			// 创建上传图片目录的File对象
			File parentFile = new File("D:\\upload\\");
			// 如果不存在,就创建这个目录
			if (!parentFile.exists()) {
				parentFile.mkdir();
			}
			// 把客户端的IP地址作为上传文件的文件名
			File file = new File(parentFile, ip + "(" + count +
					").jpg");
			while (file.exists()) {
				// 如果文件名存在,则把count++
				file = new File(parentFile, ip + "(" + (count++) +
						").jpg");
			}
			// 创建FileOutputStream对象
			FileOutputStream fos = new FileOutputStream(file);
			// 定义一个字节数组
			byte[] buf = new byte[1024];
			// 定义一个int类型的变量len,初始值为0
			int len = 0;
			// 循环读取数据
			while ((len = in.read(buf)) != -1) {
				fos.write(buf, 0, len);
			}
			// 获取服务端的输出流
			OutputStream out = socket.getOutputStream();
			// 上传成功后向客户端写出“上传成功”
			out.write("上传成功".getBytes());
			// 关闭输出流对象
			fos.close();
			// 关闭Socket对象
			socket.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

(3)编写客户端的功能代码,客户端功能的实现,因为是用户自己输入上传文件。所以要定义键盘录入。录入后需要使用Socket类来创建客户对象,并通过输入输出流来定义指定的文件。

package tcp_demo;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class FileClient {
    public static void main(String[] args)throws Exception {
        // 创建客户端Socket
        Socket socket = new Socket("127.0.0.1", 10001);
        // 获取Socket的输出流对象
        OutputStream out = socket.getOutputStream();
        // 创建FileInputStream对象
        System.out.println("请输入你要上传文件的路径:");
        Scanner sc =new Scanner(System.in);
        String upload = sc.nextLine();
        if(!upload.isEmpty()){
            FileInputStream fis = new FileInputStream(upload);
            // 定义一个字节数组
            byte[] buf = new byte[1024];
            // 定义一个int类型的变量len
            int len;
            // 循环读取数据
            while ((len = fis.read(buf)) != -1) {
                out.write(buf, 0, len);
            }
            // 关闭客户端输出流
            socket.shutdownOutput();
            // 获取Socket的输入流对象
            InputStream in = socket.getInputStream();
            // 定义一个字节数组
            byte[] bufMsg = new byte[1024];
            // 接收服务端的信息
            int num = in.read(bufMsg);
            String Msg = new String(bufMsg, 0, num);
            System.out.println(Msg);		// 关键输入流对象
            fis.close();
            // 关闭Socket对象
            socket.close();
        }else {
            System.out.println("请输入文件路径后再上传 !");
        }
    }

    }

(4)最后我们启动程序,先启动服务端程序,再运行客户端程序来测试上传的结果。

 

 

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

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

相关文章

AUTOSAR 自适应平台

总目录链接>> AutoSAR入门和实战系列总目录 文章目录AUTOSAR 自适应平台动机标准自适应平台基础基本功能通信安全保障自适应平台服务DemonstratorDemonstrator实现路线图本系列文章由两部分组成:第一部分讨论了AUTOSAR 经典平台,该平台旨在基于微…

Linux下的进程地址空间

Linux下的进程地址空间程序地址空间回顾从代码结果推结论引入进程地址空间页表为什么要有进程地址空间重新理解进程地址空间程序地址空间回顾 我们在初学C/C的时候,我们会经常看见老师们画这样的内存布局图: 可是这真的是内存吗? 如果不是它…

【设计模式】 模板方法模式介绍及C代码实现

【设计模式】 模板方法模式介绍及C代码实现 背景 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任…

2023年1月综合预订类APP用户洞察——旅游市场复苏明显,三年需求春节集中释放

2023年1月,随着国家对新型冠状病毒感染实施“乙类乙管”,不再对入境人员和货物等采取检疫传染病管理措施,并且取消入境后全员核酸检测和集中隔离,横亘在旅游者与旅游目的地之间的隔阂从此彻底消失。2023年1月恰逢春节假期&#xf…

SQL零基础入门学习(十一)

SQL零基础入门学习(十) SQL NOT NULL 约束 NOT NULL 约束强制列不接受 NULL 值。 NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。 下面的 SQL 强制 “ID” 列、 “LastName” …

Mac OSX下使用VMware Fusion 配置静态IP 图文教程指南

目录一. 前言二. Mac OSX下使用VMware Fusion 配置静态IP2.1 了解静态IP如何划分基础知识2.2 Centos7 安装操作系统时图形界面配置静态IP2.3 Centos7安装操作系统后修改动态IP为静态IP三参考文献一. 前言 Mac OSX 下使用VMware Fusion 创建的虚拟机,默认是通过DHCP…

雷达实战之射频前端配置说明

在无线通信领域,射频系统主要分为射频前端,以及基带。从发射通路来看,基带完成语音等原始信息通过AD转化等手段转化成基带信号,然后经过调制生成包含跟多有效信息,且适合信道传输的信号,最后通过射频前端将信号发射出去…

msys2+minGW方案编译ffmpeg的最佳实践

一、Win10 64bit编译环境的建立1)从http://www.msys2.org/下载 msys2-x86_64-xxx.exe2) 安装msys2到默认路径 C:\msys64\3) 运行MSYS2 w644)执行 pacman -Syu 更新系统当出现提示时,选择y5) 当窗口关闭时,重…

九龙证券|美股创年内最大周跌幅!美联储官员密集发声!波音重挫近5%

当地时刻2月24日,美股三大指数收盘明显跌落。道指跌1.02%,标普500指数跌1.05%,纳指跌1.69%。 大型科技股普跌,微软、亚马逊跌超2%。波音大跌4.8%,居道指跌幅榜首位,公司因机身部件有问题再次暂停向用户交付…

zabbix4.0-动作-邮件告警

目录 1、创建动作Actions 动作触发流程 创建一个动作 2、配置 Media types 媒介类型,添加一个发件邮箱来发送告警邮件 3、配置 Users Media,添加一个收件邮箱来接收告警邮件 4、更改一个触发器表达式来触发动作Action,最终发送告警邮…

【数据库】MongoDB数据库详解

目录 一,数据库管理系统 1, 什么是数据库 2,什么是数据库管理系统 二, NoSQL 是什么 1,NoSQL 简介 2,NoSQL数据库 3,NoSQL 与 RDBMS 对比 三,MongoDB简介 1, MongoDB 是什…

Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够了

前言 本文罗列了了python零基础入门到精通的详细教程,内容均以知识目录的形式展开。 第一章:python基础之markdown Typora软件下载Typora基本使用Typora补充说明编程与编程语言计算机的本质计算机五大组成部分计算机三大核心硬件操作系统 第二章&…

【LeetCode】剑指 Offer 15. 二进制中1的个数 p100 -- Java Version

题目链接:https://leetcode.cn/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/?favoritexb9nqhhg 1. 题目介绍(15. 二进制中1的个数) 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回…

Systemverilog覆盖率的合并和计算方式

在systemverilog中,对于一个covergroup来说,可能会有多个instance,我们可能需要对这些instance覆盖率进行操作。 只保存covergroup type的覆盖率,不需要保存instance-specified的覆盖率coverage type和instance-specified的覆盖率…

SVM支持向量机理解_KKT条件_拉格朗日对偶_SMO算法

目录 一、支持向量机基本型(线性可分) 1.1 问题描述 1.2 参考资料 二、KKT条件 2.1 KKT条件的几个部分 2.1.1 原始条件 2.1.2 梯度条件 2.1.3 松弛互补条件 2.2 参考资料 三、对偶形式 四、SMO算法 五、线性不可分情形 六、核函数 一、支持…

TimeWheel时间轮算法原理及实现(附源码)

时间轮算法原理及实现前言1.时间轮核心2.简单定时器3.任务队列4.优化任务队列5.简单时间轮6.多层时间轮前言 在各种业务场景中,我们总是会需要一些定时进行一些操作,这些操作可能是需要在指定的某个时间点操作,也可能是每过一个固定的时间间隔后进行操作,这就要求我们需要有一个…

【蓝桥OJ—C语言】高斯日记、马虎的算式、第39级台阶

文章目录高斯日记马虎的算式第39级台阶总结高斯日记 题目: 大数学家高斯有个好习惯:无论如何都要记日记。 他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210。 后来人们知道&am…

You Only Need 90K Parameters to Adapt Light 论文阅读笔记

这是BMVC2022的论文,提出了一个轻量化的局部全局双支路的低光照图像质量增强网络,有监督。 思路是先用encoder f(⋅)f(\cdot)f(⋅)转到raw-RGB域,再用decoder gt(⋅)g_t(\cdot)gt​(⋅)模拟ISP过程转到sRGB域。虽然文章好像没有明确指出&…

【蓝牙mesh】Network协议层介绍

【蓝牙mesh】Network协议层介绍 Network层简介 上一章节我们讲解了蓝牙Mesh中Lower层的功能和数据格式。 Lower层的数据往下传输就到了网络层(Network Layer)。网络层定义了收到Lower层的数据后,如何对其进行判断、封装、加密、认证&#xf…

学习(mianshi)必备-ClickHouse高性能查询/写入和常见注意事项(五)

目录 一、ClickHouse高性能查询原因-稀疏索引 二、ClickHouse高性能写入-LSM-Tree存储结构 什么是LSM-Tree 三、ClickHouse的常见注意事项和异常问题排查 一、ClickHouse高性能查询原因-稀疏索引 密集索引: 在密集索引中,数据库中的每个键值都有一个索引记录&…