网络编程之TCP

news2024/10/2 8:44:27

hi,大家好,今天为大家带来TCP协议的相关知识

这里写目录标题

  • 认识TCP的相关方法
    • 实现TCP版本的回显服务器
      • 实现多线程版本的TCP回显服务器
      • 实现线程池版本的TCP回显服务器
    • 认识TCP方法

认识TCP的相关方法

实现TCP版本的回显服务器

实现多线程版本的TCP回显服务器

实现线程池版本的TCP回显服务器

认识TCP方法

TCP也有两个核心的类
Socket和SeverSocket
SeverSocket是给服务器用的
Socket的话,客户端可以用,服务器也可以用

先来看看ServerSocket

ServerSocket() 创建未绑定的服务器套接字。
ServerSocket(int port) 创建绑定到指定端口的服务器套接字。

但我们一般在写服务器的时候都会指定服务器端口号
就像饭店,也得有一个固定位置

Socket accept() 侦听要连接到此套接字并接受它。

accept就是接收的意思,客户端向服务器发起连接请求,在内核中进行连接,accept这里是应用程序层面的接受,就是把连接好的连接拿出来让应用程序连起来,这里先简单的认为是连接,后面讲到TCP的三次握手四次招手再具体介绍
ServerSocket是创建TCP服务端的API
下面再来看看Socket

Socket() 创建一个未连接的套接字,并使用系统默认类型的SocketImplort。
Socket(InetAddress address, int port) 创建流套接字并将其连接到指定IP地址的指定端口号。
public Socket(String host,
int port)
throws UnknownHostException,
IOException
创建流套接字并将其连接到指定主机上的指定端口号。

在这里插入图片描述

用于从该套接字读取字节的输入流。
在这里插入图片描述
用于将字节写入此套接字的输出流。
InputStream和OutputStream是字节流,TCP是面对字节流的
InputStream是读数据,也就是从网卡接收
OutputStream是写数据,也就是从网卡发送

方法就认识这么多,下面来写TCP版本的回显程序

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



/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 20:43
 */
public class TCPEchoSever {
    //severSocket就是外场拉客的小哥
    //clientSocket就是内场服务的小姐姐
    //severSocket只有一个,clientSocket会给每个客户端都分配一个

    private ServerSocket serverSocket=null;

    public TCPEchoSever(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            Socket clientSocket=serverSocket.accept();
            processConnection(clientSocket);
        }
    }
    //通过这个方法处理一个连接
    //读取请求
    //根据请求计算响应
    //把响应返回给客户端

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());//得到IP和端口号
        //try()这种写法,括号中允许有多个流对象,用;来分割
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while(true){
                //1.读取请求
                if(!scanner.hasNext()){
                    //读取的流到了结尾(对端关闭)
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),
                            clientSocket.getPort());
                    break;
                }
                //直接使用scanner读取一段字符串
                String request=scanner.next();
                //2.根据请求响应
                String response=process(request);
                //3.把响应写回到客户端,不要忘了响应也要戴上换行
                printWriter.println(response);
                System.out.println(response);
                System.out.printf("[%s:%d] req: %s; resp: %s\n",clientSocket.getInetAddress(),
                        clientSocket.getPort(),request,response);
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return request;
    }

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

}

我们来运行一下程序
先启动服务器
在这里插入图片描述
在这里插入图片描述
看到客户端也启动了,但是输入却没有响应,这是有问题的
为什么客户端输入消息,但是客户端服务器没有任何响应呢
原因就是我们进行TCP的通信媒介是网卡,网卡读取速度比硬盘还要慢,因此为了提高IO效率,我们一般先把数据放到缓冲区上,然后再手动刷新,再到网卡上
在这里插入图片描述
这里的打印,是从网卡上读取数据打印的,但是打印是无效的,因为此时数据在缓冲区,需要刷新一下,也就是使用printWriter的flush方法
同样在服务器的在这里插入图片描述
打印响应也要进行刷新
上代码
服务器

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



/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 20:43
 */
public class TCPEchoSever {
    //severSocket就是外场拉客的小哥
    //clientSocket就是内场服务的小姐姐
    //severSocket只有一个,clientSocket会给每个客户端都分配一个

    private ServerSocket serverSocket=null;

    public TCPEchoSever(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            Socket clientSocket=serverSocket.accept();
            processConnection(clientSocket);
        }
    }
    //通过这个方法处理一个连接
    //读取请求
    //根据请求计算响应
    //把响应返回给客户端

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());//得到IP和端口号
        //try()这种写法,括号中允许有多个流对象,用;来分割
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while(true){
                //1.读取请求
                if(!scanner.hasNext()){
                    //读取的流到了结尾(对端关闭)
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),
                            clientSocket.getPort());
                    break;
                }
                //直接使用scanner读取一段字符串
                String request=scanner.next();
                //2.根据请求响应
                String response=process(request);
                //3.把响应写回到客户端,不要忘了响应也要戴上换行
                printWriter.println(response);
                printWriter.flush();
                System.out.println(response);
                System.out.printf("[%s:%d] req: %s; resp: %s\n",clientSocket.getInetAddress(),
                        clientSocket.getPort(),request,response);
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return request;
    }

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

}

客户端

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.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 21:16
 */
public class TCPEchoClient {
    private Socket socket=null;

    public TCPEchoClient(String serverIp,int port) throws IOException {
        //这个操作相当于让客户端和服务器建立tcp连接
        //这里的连接连上了,服务器的accept就会返回
        socket=new Socket(serverIp,port);

    }
    public void start(){
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()){
            PrintWriter printWriter=new PrintWriter(outputStream);
            Scanner scannerFromSocket=new Scanner(inputStream);
            while(true){
                //1.从键盘上读取用户输入的内容
                System.out.print("->");
                String request=scanner.next();
                //2.把读取的内容构造成请求,发送给服务器
                //注意,这里的发送,是带有换行的
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器读取响应
                String response=scannerFromSocket.next();
                //4.把响应结果显示到控制台上
                System.out.printf("req: %S; resp: %s\n",request,response );
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) throws IOException {
        TCPEchoClient tcpEchoClient=new TCPEchoClient("127.0.0.1",9090);
        tcpEchoClient.start();

    }

}

运行结果
在这里插入图片描述
在这里插入图片描述
现在就正常了
我们来总结一下TCP通信过程
1.首先要开启服务器,start这里,然后运行到accept这里,阻塞等待
等待客户端的请求
2.客户端启动时,调用Socket方法,和服务器在内核中建立连接,连接成功以后,服务器的accept就返回了
3.服务器这边进入processConnection方法,尝试从客户端读取请求,但是由于此时用户还没有输入,所以读取操作也会阻塞等待
3.客户端这边往下执行时,从控制台读取用户输入,也会阻塞,因为用户可能不会立即输入
4.当用户输入,客户端发请求出去,客户端代码继续执行,到读取服务器响应时,再次阻塞
5.服务器收到客户端的请求,从next这里返回,执行process方法,执行println,把响应写回给客户端

6.客户端这边收到服务器的响应打印到控制台上,同时进入下一次循环,等待用户输入
6.服务器这边回到循环开始的地方,继续尝试获取客户端的请求,然后阻塞等待

对于缓冲区和网卡之间的切换再来说一说
在发数据的时候,必须通过网卡发送,应用程序层面无法直接通过网卡发送数据
接收数据的时候,应用软件无法直接通过网卡接收
那么怎么办呢,在tcp通信中,是存在缓冲区这样的概念的,我们通过缓冲区进行发送和接收
下面来画个图
我们先来画跨主机通信的,那么就需要两个网卡
在这里插入图片描述

传输的数据是需要套接socket的,可以把socket当做一个文件,套接tcp数据报进行传输,就像水是在水管里运输的,水管就是相当于socket,水相当于要传输的数据
send:
客户端发出的数据,要先通过socket进行包装,通过socket对象的getOutputStream方法获取与这个socket相关的outputStream对象,使用write()方法写入到缓冲区,然后将发送缓冲区的数据送到网卡,网卡将数据发到服务器端的接收缓冲区,再发给服务器
receive:
服务器在收到数据的时候,处理完数据,就又通过socket,发送到服务器这边的发送缓冲区,发送缓冲区发给网卡,然后交给客户端这边,客户端通过socket对象的getInputStream方法获取与这个socket相关的inputStream对象,客户端就可以通过read()方法从接收缓冲区读取数据
下图是在同一个主机通信的,就使用一个环回网卡就行!!!

在这里插入图片描述
发送数据和接收数据过程是一样,就不赘述了
现在这个程序是没有问题了,但是在互联网的世界中,我们知道肯定是有很多客户端要访问服务器
那么这个代码这样写是不支持多个客户端同时访问的,我们来看看
在这里插入图片描述
在idea勾选,就可以在idea同时运行很多个客户端
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到,我们在客户端1输入请求,是有响应的,在其他的客户端上输入请求,是没有响应的
这里其实是一个bug.是代码的bug
我们来分析一下
在这里插入图片描述
在这里插入图片描述

当客户端1来的时候,操作系统从内核拿出连接,然后接受连接,调用processConnectino方法,进入processConnecion方法那么只有当客户端1下线其他客户端才能相继连接,我们想要循环处理客户端1的数据,还要循环accept,接受其他的客户端请求,那么我们要咋样解决这个问题呢?
用多线程
在这里插入图片描述
这样写就可以实现一边循环处理原来客户端的请求,还能循环接收其他的客户端进行accept
注意:这里的线程是一个一个创建的,就是串行创建,而在执行的时候是并发的
咋样通俗理解呢
拿售楼来说,一个小哥拉来客户1号,交给一个小姐姐1,进行服务,在小姐姐1服务客户1的时候,这个小哥又拉来一个客户2,再来一个小姐姐2,服务,依次类推,这些客户之间,小姐姐之间是互不影响的,是一起执行的,就是这样理解的了

我们把完整代码给大家
客户端

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



/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 20:43
 */
public class TCPEchoSever {
    //severSocket就是外场拉客的小哥
    //clientSocket就是内场服务的小姐姐
    //severSocket只有一个,clientSocket会给每个客户端都分配一个

    private ServerSocket serverSocket=null;

    public TCPEchoSever(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            Socket clientSocket=serverSocket.accept();
            Thread thread=new Thread(()->{
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });


        }
    }
    //通过这个方法处理一个连接
    //读取请求
    //根据请求计算响应
    //把响应返回给客户端

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());//得到IP和端口号
        //try()这种写法,括号中允许有多个流对象,用;来分割
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while(true){
                //1.读取请求
                if(!scanner.hasNext()){
                    //读取的流到了结尾(对端关闭)
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),
                            clientSocket.getPort());
                    break;
                }
                //直接使用scanner读取一段字符串
                String request=scanner.next();
                //2.根据请求响应
                String response=process(request);
                //3.把响应写回到客户端,不要忘了响应也要戴上换行
                printWriter.println(response);
                printWriter.flush();
                System.out.println(response);
                System.out.printf("[%s:%d] req: %s; resp: %s\n",clientSocket.getInetAddress(),
                        clientSocket.getPort(),request,response);
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return request;
    }

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

}

服务器

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

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 21:16
 */
public class TCPEchoClient {
    private Socket socket=null;

    public TCPEchoClient(String serverIp,int port) throws IOException {
        //这个操作相当于让客户端和服务器建立tcp连接
        //这里的连接连上了,服务器的accept就会返回
        socket=new Socket(serverIp,port);

    }
    public void start(){
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()){
            PrintWriter printWriter=new PrintWriter(outputStream);
            Scanner scannerFromSocket=new Scanner(inputStream);
            while(true){
                //1.从键盘上读取用户输入的内容
                System.out.print("->");
                String request=scanner.next();
                //2.把读取的内容构造成请求,发送给服务器
                //注意,这里的发送,是带有换行的
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器读取响应
                String response=scannerFromSocket.next();
                //4.把响应结果显示到控制台上
                System.out.printf("req: %S; resp: %s\n",request,response );
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) throws IOException {
        TCPEchoClient tcpEchoClient=new TCPEchoClient("127.0.0.1",9090);
        tcpEchoClient.start();

    }

}

线程频繁的创建和销毁是耗费资源的,我们升级代码,采用线程池,避免线程销毁,用完放到线程池里面,更加高效
在这里插入图片描述
看看完整代码
客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 20:43
 */
public class TCPEchoSever {
    //severSocket就是外场拉客的小哥
    //clientSocket就是内场服务的小姐姐
    //severSocket只有一个,clientSocket会给每个客户端都分配一个

    private ServerSocket serverSocket=null;

    public TCPEchoSever(int port) throws IOException {
        serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println("服务器启动!");
        while(true){

            Socket clientSocket=serverSocket.accept();

                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            processConnection(clientSocket);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });
                   



        }
    }
    //通过这个方法处理一个连接
    //读取请求
    //根据请求计算响应
    //把响应返回给客户端

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线\n",clientSocket.getInetAddress().toString(),
                clientSocket.getPort());//得到IP和端口号
        //try()这种写法,括号中允许有多个流对象,用;来分割
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()) {
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while(true){
                //1.读取请求
                if(!scanner.hasNext()){
                    //读取的流到了结尾(对端关闭)
                    System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),
                            clientSocket.getPort());
                    break;
                }
                //直接使用scanner读取一段字符串
                String request=scanner.next();
                //2.根据请求响应
                String response=process(request);
                //3.把响应写回到客户端,不要忘了响应也要戴上换行
                printWriter.println(response);
                printWriter.flush();
                System.out.println(response);
                System.out.printf("[%s:%d] req: %s; resp: %s\n",clientSocket.getInetAddress(),
                        clientSocket.getPort(),request,response);
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return request;
    }

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

}

服务器

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.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: WHY
 * Date: 2023-04-07
 * Time: 21:16
 */
public class TCPEchoClient {
    private Socket socket=null;

    public TCPEchoClient(String serverIp,int port) throws IOException {
        //这个操作相当于让客户端和服务器建立tcp连接
        //这里的连接连上了,服务器的accept就会返回
        socket=new Socket(serverIp,port);

    }
    public void start(){
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()){
            PrintWriter printWriter=new PrintWriter(outputStream);
            Scanner scannerFromSocket=new Scanner(inputStream);
            while(true){
                //1.从键盘上读取用户输入的内容
                System.out.print("->");
                String request=scanner.next();
                //2.把读取的内容构造成请求,发送给服务器
                //注意,这里的发送,是带有换行的
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器读取响应
                String response=scannerFromSocket.next();
                //4.把响应结果显示到控制台上
                System.out.printf("req: %S; resp: %s\n",request,response );
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) throws IOException {
        TCPEchoClient tcpEchoClient=new TCPEchoClient("127.0.0.1",9090);
        tcpEchoClient.start();

    }

}

补充:

短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以 多次收发数据

在这里插入图片描述
这就是这期的所有内容了,我们下期再见,886!🌸🌸🌸

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

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

相关文章

尚硅谷大数据技术Hadoop教程-笔记06【Hadoop-生产调优手册】

视频地址:尚硅谷大数据Hadoop教程(Hadoop 3.x安装搭建到集群调优) 尚硅谷大数据技术Hadoop教程-笔记01【大数据概论】尚硅谷大数据技术Hadoop教程-笔记02【Hadoop-入门】尚硅谷大数据技术Hadoop教程-笔记03【Hadoop-HDFS】尚硅谷大数据技术Ha…

轻松管理和保障容器应用程序:Docker Swarm安全之道

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 文章目录 一、 介绍Docker Swarm 安全1. 什么是Docker Swarm2. 为什么要使用Docker Swarm3. Docker Swarm的安全特性 二…

sql语法:详解DDL

Mysql版本:8.0.26 可视化客户端:sql yog 目录 一、DDL是什么?二、和数据库相关的DDL2.1 创建数据库2.2 删除数据库2.3 查看所有的数据库,当前用户登录后,可以看到哪些数据库2.4 查看某个数据库的详细定义2.5 修改数据库…

你一定能看懂的数据库事务和事务特性实现原理

一。概念 事务 是数据库执行原子操作的基本单位。一个事务中的多个修改,则要么全部成功执行,要么全部不执行。 关于事务的 MYSQL 官网的解释 Transactions are atomic units of work that can be *committed* or *rolled back*. When a transaction ma…

PyTorch 深度学习实战 | DIEN 模拟兴趣演化的序列网络

01、实例:DIEN 模拟兴趣演化的序列网络 深度兴趣演化网络(Deep Interest Evolution Network,DIEN)是阿里巴巴团队在2018年推出的另一力作,比DIN 多了一个Evolution,即演化的概念。 在DIEN 模型结构上比DIN 复杂许多,但大家丝毫不用担心,我们将DIEN 拆解开来详细地说…

Unity+jenkins自动化打包(1)

一 安装Jenkins https://www.jenkins.io/download/ 官网 1) 使用 brew 安装 2) 安装完成后一般都会遇到问题 我用的是jenkins-lts 稳定版 解决办法 删除掉对应的文件夹 1 rm -rf /usr/local/Homebrew/Library/Taps/homebrew/homebrew-services 2…

内网穿透实现在外远程SQL Server数据库 - Windows环境

目录 前言 1. 本地安装配置SQL Server 2. 将本地sqlserver服务暴露至公网 2.1 本地安装cpolar内网穿透 2.2 创建隧道 3. 公网远程连接sqlserver 3.1 使用命令行远程连接sqlserver, 3.2 使用图形界面远程连接sqlserver 3.3 使用SSMS图形界面远程连接sqlserver 4. 配置…

【服务器】威联通NAS文件共享 - 搭建SFTP服务并内网穿透实现在外远程访问

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 前言 1. 威联通NAS启用SFTP 2. 测试局域网访问 3. 内网穿透 3.1 威联通安装cpolar内网穿透 3.2 创建隧道 3.3 测试公网远程访问 4. 配置固定公网TCP端口地址 4.1 保留一个固定TCP…

AI绘图设计师Stable Diffusion成为生产力工具(六):制作一张庆祝五一劳动节的海报

S:AI能取代设计师么? I :至少在设计行业,目前AI扮演的主要角色还是超级工具,要顶替?除非甲方对设计效果无所畏惧~~ 预先学习: 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。…

Spring《二》bean的实例化与生命周期

🍎道阻且长,行则将至。🍓 上一篇:Spring《一》快速入门 下一篇:Spring《三》DI依赖注入 目录 一、bean实例化🍍1.构造方法 ***2.静态工厂 *使用工厂创建对象实例化bean 3.实例工厂 ***使用示例工厂创建对象…

深度学习必备书籍——《Python深度学习 基于Pytorch》

作为一名机器学习|深度学习的博主,想和大家分享几本深度学习的书籍,让大家更快的入手深度学习,成为AI达人!今天给大家介绍的是:《Python深度学习 基于Pytorch》 文章目录 一、背景二、内容简介三、新版特色四、作者介绍…

3.26学习周报

文章目录 前言文献阅读摘要简介方法结果讨论结论 时间序列预测学习1.基础知识1.1什么是时间序列?1.2时间序列的基本任务?2.时间序列预测算法汇总LSTM学习 总结 前言 本周阅读文献《Simulate the forecast capacity of a complicated water quality mode…

【SpringBoot】| 邮箱发送验证码,你会了吗?

目录 🦁 题外话🦁 提前准备2.1 配置邮箱第三方登录2.1.1 点击设置——账户2.1.2 开启POP3/SMTP服务 2.2 添加依赖2.3 yaml配置 🦁 进入主题🦁 测试使用🦁 尾声3.1 安利一个生成验证码的工具类3.1.1 添加依赖3.1.2 编写…

Qt音视频开发32-qmedia内核回调拿图片数据

一、前言 使用qmediaplayer来打开视频并播放,默认首选会采用QVideoWidget控件来展示,优点是不用自己来绘制,一切交给了QVideoWidget控件,这样可以做到极低的CPU占用,缺点也明显,就是无法拿到每一帧的图片,很多时候我们还需要主动拿到每一帧的图片来运算做人工智能,通过…

hive之left semi join(左半连接)使用方法

目录 一、建表数据准备 二、语法 三、left semi join例子 四、left semi join、join、left join的区别 1、left semi join 2、left join 3、join 结语 一、建表数据准备 参考hive之full outer join(全连接)使用方法_IMezZ的博客-CSDN博客目录介…

【Bard】谷歌的人工智能工具—Bard初体验

文章目录 一、Bard介绍二、Bard体验1、加入Bard的候补名单2、登入Bard篇3、使用Bard篇(1)提供三种预选方式✨(2)创作生成各类文案(3)无生成图画能力(4)支持语音转文本输入✨&#xf…

AI绘图设计师Stable Diffusion成为生产力工具(五):放大并修复老照片、马赛克照片、身份证件照

S:你安装stable diffusion就是为了看小姐姐么? I :当然不是,当然是为了公司的发展谋出路~~ 预先学习: 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。运行使用时问题《Windows使用Stable Diffusion时…

MySQL安装和配置(保姆级别和全网最详细教程)

前言 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系…

OPNET Modeler 例程——ALOHA和CSMA的性能对比

文章目录 概述一、创建 ALOHA 协议模型二、创建 CSMA 协议模型三、创建收信机进程和节点模型四、创建总线型链路模型五、创建网络模型六、查看仿真结果总结 概述 本例程以以太网为例论述总线型网络的建模方法,对数据链路层的 MAC 技术进行建模分析,并进…

【多线程】常见的锁策略

✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 ✨每日一语:老当益壮,宁移白首之心;穷且益坚,不坠青云之志。 目 录 🏳️一. 乐观锁 vs 悲观锁🏴二. 普通的互…