当前位置: 首页 > article >正文

150 Linux 网络编程6 ,从socket 到 epoll整理。listen函数参数再研究

一 . 只能被一个client 链接 socket例子

此例子用于socket 例子,
该例子只能用于一个客户端连接server。
不能用于多个client 连接  server

socket_server_support_one_clientconnect.c


/*
此例子用于socket 例子,
该例子只能用于一个客户端连接server。
不能用于多个client 连接  server*/
#include "wrap.h"
#define SERVER_PORT 8888int main(int argc, const char* argv[]) {int lfd;// 第一步:创建 lfdlfd = Socket(AF_INET, SOCK_STREAM, 0);// 第二步: 给lfd 绑定 IP 和 PORT,这里需要将 port 和IP 从小端转成大端struct sockaddr_in sockaddrin_server;sockaddrin_server.sin_family = AF_INET;sockaddrin_server.sin_port = htons(SERVER_PORT);sockaddrin_server.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd,(struct sockaddr *)&sockaddrin_server,sizeof(sockaddrin_server));//第三步:设定监听上限,这个监听上限的意思是:同时只能有8个客户端和此 server连接,我们这个server只能要一个客户端和我们连接,因此这个值在这里没有具体意义Listen(lfd, 8);// 第四步 :阻塞,并等待客户端连接. accept的第二个参数是传入传出参数,代表的是:成功于服务器连接的客户端的 地址结构struct sockaddr_in sockaddrin_client;socklen_t sockaddrin_clientsocklen_t = sizeof(sockaddrin_client);int  cfd = Accept(lfd, (struct sockaddr *)&sockaddrin_client, &sockaddrin_clientsocklen_t);char clientip[33] = { 0 };const char* clientipresult = inet_ntop(AF_INET, &sockaddrin_client.sin_addr.s_addr, clientip, 32);if (clientipresult == NULL) {printf("inet_ntop error\n");}else {printf("client addr port = %d,addr ip = %s \n", ntohs(sockaddrin_client.sin_port), clientipresult);}printf("client addr port = %d,addr ip = %s \n",ntohs(sockaddrin_client.sin_port), clientip);//只要客户端连接上了, 没有错误,就会走到这一步。//第五步:连接上后,server端就可以循环的 使用read函数 读取客户端发送过来的数据了。//注意的是,read函数默认是阻塞读取的char readbuffer[256] = { 0 };int readbufferlen = 0;while (1) {readbufferlen = Read(cfd, readbuffer, 256);printf("read buffer from client %s \n", readbuffer);for (int i = 0; i < readbufferlen; ++i) {readbuffer[i] = toupper(readbuffer[i]);}Write(cfd, readbuffer, readbufferlen);Write(STDOUT_FILENO, readbuffer, readbufferlen);}
}

wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <netinet/ip.h> 
#include <strings.h>void perr_exit(const char* s);
int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr);
int Bind(int fd, const struct sockaddr* sa, socklen_t salen);
int Connect(int fd, const struct sockaddr* sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void* ptr, size_t nbytes);
ssize_t Write(int fd, const void* ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void* vptr, size_t n);
ssize_t Writen(int fd, const void* vptr, size_t n);
static ssize_t my_read(int fd, char* ptr);
ssize_t Readline(int fd, void* vptr, size_t maxlen);
int tcp4bind(short port, const char* IP);#endif

wrap.c

#include "wrap.h"void perr_exit(const char* s)
{perror(s);exit(-1);
}int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
{int n;again:if ((n = accept(fd, sa, salenptr)) < 0) {if ((errno == ECONNABORTED) || (errno == EINTR))goto again;elseperr_exit("accept error");}return n;
}int Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{int n;if ((n = bind(fd, sa, salen)) < 0)perr_exit("bind error");return n;
}int Connect(int fd, const struct sockaddr* sa, socklen_t salen)
{int n;if ((n = connect(fd, sa, salen)) < 0)perr_exit("connect error");return n;
}int Listen(int fd, int backlog)
{int n;if ((n = listen(fd, backlog)) < 0)perr_exit("listen error");return n;
}int Socket(int family, int type, int protocol)
{int n;if ((n = socket(family, type, protocol)) < 0)perr_exit("socket error");return n;
}ssize_t Read(int fd, void* ptr, size_t nbytes)
{ssize_t n;again:if ((n = read(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}ssize_t Write(int fd, const void* ptr, size_t nbytes)
{ssize_t n;again:if ((n = write(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}int Close(int fd)
{int n;if ((n = close(fd)) == -1)perr_exit("close error");return n;
}/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void* vptr, size_t n)
{size_t  nleft;              //usigned int 剩余未读取的字节数ssize_t nread;              //int 实际读到的字节数char* ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ((nread = read(fd, ptr, nleft)) < 0) {if (errno == EINTR)nread = 0;elsereturn -1;}else if (nread == 0)break;nleft -= nread;ptr += nread;}return n - nleft;
}ssize_t Writen(int fd, const void* vptr, size_t n)
{size_t nleft;ssize_t nwritten;const char* ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ((nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR)nwritten = 0;elsereturn -1;}nleft -= nwritten;ptr += nwritten;}return n;
}static ssize_t my_read(int fd, char* ptr)
{static int read_cnt;static char* read_ptr;static char read_buf[100];if (read_cnt <= 0) {again:if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {if (errno == EINTR)goto again;return -1;}else if (read_cnt == 0)return 0;read_ptr = read_buf;}read_cnt--;*ptr = *read_ptr++;return 1;
}ssize_t Readline(int fd, void* vptr, size_t maxlen)
{ssize_t n, rc;char    c, * ptr;ptr = vptr;for (n = 1; n < maxlen; n++) {if ((rc = my_read(fd, &c)) == 1) {*ptr++ = c;if (c == '\n')break;}else if (rc == 0) {*ptr = 0;return n - 1;}elsereturn -1;}*ptr = 0;return n;
}int tcp4bind(short port, const char* IP)
{struct sockaddr_in serv_addr;int lfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&serv_addr, sizeof(serv_addr));if (IP == NULL) {//如果这样使用 0.0.0.0,任意ip将可以连接serv_addr.sin_addr.s_addr = INADDR_ANY;}else {if (inet_pton(AF_INET, IP, &serv_addr.sin_addr.s_addr) <= 0) {perror(IP);//转换失败exit(1);}}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(port);//端口复用代码,在bind之前int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));Bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));return lfd;
}

编译命令

gcc socket_server_support_one_clientconnect.c wrap.c -o socket_server_support_one_clientconnect.out
这里使用的是 gcc build, 如果使用g++,则会有build error,因为g++的语法检查,要比 gcc 严格一些。
error 信息如下g++ socket_server_support_one_clientconnect.c wrap.c -o socket_server_support_one_clientconnect.out
wrap.c: In function ‘ssize_t Readn(int, void*, size_t)’:
wrap.c:111:8: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]ptr = vptr;^~~~
wrap.c: In function ‘ssize_t Writen(int, const void*, size_t)’:
wrap.c:136:8: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]ptr = vptr;^~~~
wrap.c: In function ‘ssize_t Readline(int, void*, size_t)’:
wrap.c:180:8: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]ptr = vptr;

二 . 可以被多个 client 链接 socket 例子,使用 父子进程完成。

2.1 添加 将 SIGCHLD 信号屏蔽

    //信号屏蔽是指进程主动阻止某些信号的递达,直到屏蔽解除,被屏蔽的信号在屏蔽期间仍然会产生,但不会被处理,直到屏蔽解除后才会被处理,信号屏蔽通常用于保护临界区代码,防止信号处理程序与普通代码同时执行导致的数据不一致问题。
 

            sigset_t set;
            sigemptyset(&set);
            sigaddset(&set, SIGCHLD);
            sigprocmask(SIG_BLOCK, &set, NULL);

2.2 端口复用

        server IP 和 port可以复用

        setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 

2.3 父进程完成的任务有:

        2.3.1.负责监听lfd功能.因此先要关闭 cfd

        2.3.2 父进程还需要回收子进程,以避免子进程完成后变成僵尸进程

                sigaction 在windows 上使用vs2019 编写linux代码,即使添加了#include <signal.h>,也无法识别,原因未知,但是在 linux环境下 build 是可以pass 的。

                            struct sigaction act;
                            act.sa_handler = catchchild;
                            sigemptyset(&act.sa_mask);
                            act.sa_flags = 0;
                            sigaction(SIGCHLD, &act, NULL);

        2.3.3 屏蔽解除 sigprocmask(SIG_UNBLOCK, &set, NULL);

2.4 子进程完成的任务有:

        2.4.1 子进程,负责 cfd 和 client的交换数据发送信息功能。因此先要关闭 lfd

                close(lfd);

        2.4.2 连接上后,循环的 使用read函数 读取客户端发送过来的数据了。注意的是,read函数默认是阻塞读取的
 

            char readbuffer[256] = { 0 };
            int readbufferlen = 0;

            while (1) {
                readbufferlen = Read(cfd, readbuffer, 256);
                printf("read buffer from client %s \n", readbuffer);
                for (int i = 0; i < readbufferlen; ++i) {
                    readbuffer[i] = toupper(readbuffer[i]);
                }
                Write(cfd, readbuffer, readbufferlen);
                Write(STDOUT_FILENO, readbuffer, readbufferlen);
            }

2.5 完整代码:

socket_server_support_more_clientconnect_use_fork.c


/*
此例子用于socket 例子,
该例子只能用于多个客户端连接server。基于 父子进程 实现
父进程 用于 lfd ,
子进程 用于 cfd.测试的问题1: listen(lfd,num) 监听的上限数量问题。*/
#include "wrap.h"
#define SERVER_PORT 8888void catchchild(int single) {pid_t pid;int status;while (1) {pid = waitpid(-1, &status, WNOHANG);if (pid <=0 ) {break;}else if (pid > 0) {printf("child pid = %\d exit \n",pid);if (WIFEXITED(status)) {//WIFEXITED(status)为真,说明是子线程是正常结束的。。使用WEXITSTATUS(status)  ---  获取进程退出状态 (exit的参数)printf("child normal die ,die information : %d \n", WEXITSTATUS(status));}if (WIFSIGNALED(status)) {//WIFSIGNALED(status)为真,说明子线程异常终止。。使用WTERMSIG(status) --- 取得使进程终止的那个信号的编号printf("child not normal die ,die information : %d \n", WTERMSIG(status));}}}
}int main(int argc, const char* argv[]) {//第零步:将 SIGCHLD 信号屏蔽,这样做的原因是,有可能当父进程还没有 注册 完成 SIGCHID 的时候,子进程已经执行完毕了,因此在main 函数的最前面,将信号屏蔽了//信号屏蔽是指进程主动阻止某些信号的递达,直到屏蔽解除,被屏蔽的信号在屏蔽期间仍然会产生,但不会被处理,直到屏蔽解除后才会被处理,信号屏蔽通常用于保护临界区代码,防止信号处理程序与普通代码同时执行导致的数据不一致问题。sigset_t set;sigemptyset(&set);sigaddset(&set, SIGCHLD);sigprocmask(SIG_BLOCK, &set, NULL);int lfd;// 第一步:创建 lfdlfd = Socket(AF_INET, SOCK_STREAM, 0);// 第一步 让 server IP 和 port可以复用。int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 第二步: 给lfd 绑定 IP 和 PORT,这里需要将 port 和IP 从小端转成大端struct sockaddr_in sockaddrin_server;sockaddrin_server.sin_family = AF_INET;sockaddrin_server.sin_port = htons(SERVER_PORT);sockaddrin_server.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd, (struct sockaddr*)&sockaddrin_server, sizeof(sockaddrin_server));//第三步:设定监听上限,这个监听上限的意思是:同时只能有2个客户端和此 server连接,我们这个server只能要2个客户端和我们连接,测试如果有3个的客户端连接的情况下,server端发生的现象 和 client端发生的现象,因此还需要写一个客户端Listen(lfd, 2);// 第四步 :accept 阻塞监听客户端连接,并 fork出子进程。// 4.1 阻塞,并等待客户端连接. accept的第二个参数是传入传出参数,代表的是:成功于服务器连接的客户端的 地址结构struct sockaddr_in sockaddrin_client;socklen_t sockaddrin_clientsocklen_t = sizeof(sockaddrin_client);pid_t pid;while (1) {int  cfd = Accept(lfd, (struct sockaddr*)&sockaddrin_client, &sockaddrin_clientsocklen_t);char clientip[33] = { 0 };const char* clientipresult = inet_ntop(AF_INET, &sockaddrin_client.sin_addr.s_addr, clientip, 32);if (clientipresult == NULL) {printf("inet_ntop error\n");}else {printf("client addr port = %d,addr ip = %s \n", ntohs(sockaddrin_client.sin_port), clientipresult);}pid = fork();if (pid == -1) {//fork 函数的 error 处理perr_exit("fork error");}else if (pid > 0) {//4.1 父进程,负责监听lfd功能.因此先要关闭 cfdclose(cfd);//4.2 父进程还需要回收子进程,以避免子进程完成后变成僵尸进程。// 那么如何回收呢? 如果是 阻塞回收,那么while(1)的循环在父进程这里就卡在这里了// 如果是 不阻塞忙轮询 回收呢?也不行,怎么忙轮询呢?// 因此这里只能用信号捕捉函数 ,捕捉 SIGCHID 信号//struct sigaction {//	void     (*sa_handler)(int);//	void     (*sa_sigaction)(int, siginfo_t*, void*);//	sigset_t   sa_mask;//	int        sa_flags;//	void     (*sa_restorer)(void);//};//int sigaction(int signum, const struct sigaction* act,struct sigaction* oldact);struct sigaction act;act.sa_handler = catchchild;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, NULL);//4.3 屏蔽解除sigprocmask(SIG_UNBLOCK, &set, NULL);}else if (pid == 0 ) {//4.4 子进程,负责 cfd 和 client的交换数据发送信息功能。因此先要关闭 lfdclose(lfd);//4.5 连接上后,循环的 使用read函数 读取客户端发送过来的数据了。注意的是,read函数默认是阻塞读取的char readbuffer[256] = { 0 };int readbufferlen = 0;while (1) {readbufferlen = Read(cfd, readbuffer, 256);printf("read buffer from client %s \n", readbuffer);for (int i = 0; i < readbufferlen; ++i) {readbuffer[i] = toupper(readbuffer[i]);}Write(cfd, readbuffer, readbufferlen);Write(STDOUT_FILENO, readbuffer, readbufferlen);}}}
}

2.6 编译命令

gcc wrap.c socket_server_support_more_clientconnect_use_fork.c -o socket_server_support_more_clientconnect_use_fork.out

*****关于 listen 第二个参数的 问题研究

在代码中,设定的listen(lfd,2); 那么这个参数2刚开始的自己的想法是:最多有两个客户端连接上server,但是实际测试中,用了5客户端连接,都没有问题,这说明啥呢?说明自己对 listen的第二个参数理解是不对的。
 

listen(lfd,2); 这个listen的第二个参数是啥意思呢?赋值多少比较合理呢?

我们先来看 listen参数的说明:

       The backlog argument defines the maximum length to which the  queue  of
       pending  connections  for  sockfd  may  grow.   If a connection request
       arrives when the queue is full, the client may receive an error with an
       indication  of  ECONNREFUSED  or,  if  the underlying protocol supports
       retransmission, the request may be ignored so that a later reattempt at
       connection succeeds.

  backlog :就是你设置的参数值

中文翻译就是:

backlog 参数定义了待处理连接队列的最大长度,sockfd 可能会增长。如果连接请求在队列已满时到达,客户端可能会收到带有 ECONNREFUSED 指示的错误,或者如果底层协议支持重传,该请求可能会被忽略,以便稍后重新尝试连接成功。

这两个博客说的很仔细:

https://zhuanlan.zhihu.com/p/634606981

listen()函数的第二个参数详解_listen函数的第二个参数-CSDN博客

整理核心:所以,backlog 目前的真正含义就是:

(1)在linux 2.2 内核之前,backlog是指半连接队列(syns_queue)的长度。

(2)在linux2.2及之后,backlog是指已经完全建立连接,但是还没有被应用层accept之前,socket所处全连接队列(accetp_queue)的长度。

全连接队列是什么?

全连接队列存储3次握手成功并已建立的连接,将其称为全连接队列,也可称为接收队列(Accept队列),本文中的描述将称为Accept队列或全连接队列。如下红框中所示,全连已成功建立三次握手,当前的TCP状态为ESTABLISHED,但是服务端还未Accept的队列。

要核心学习这,实际上要学习linux 内核的整体课程才能有深入的了解,这里只是对这个知识点比较迷惑,记录一下。

三. 可以被多个 client 链接 socket 例子,使用 子线程完成

socket_server_support_more_clientconnect_use_pthread.c

/*
使用线程完成 socket 并发服务器
主线程socket,bind ,listen,
在循环中,accept得到 cfd ,并创建 pthread,在pthread函数中 */#include "wrap.h"
#include <pthread.h>typedef struct c_info
{int cfd;struct sockaddr_in cliaddr;}CINFO;void* client_fun(void* arg);int main(int argc, char* argv[]) {//当 pthread_attr_t 是全局变量的时候,可以直接使用静态方式初始化,目的是 设置pthread的属性为 分离pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);short port = 8888;int lfd = tcp4bind(port, NULL);//创建套接字 绑定 Listen(lfd, 128);struct sockaddr_in cliaddr;socklen_t len = sizeof(cliaddr);CINFO* info;while (1){int cfd = Accept(lfd, (struct sockaddr*)&cliaddr, &len);char ip[16] = "";pthread_t pthid;//将accpet后的 cfd 做为参数传递到 子线程。info = malloc(sizeof(CINFO));info->cfd = cfd;info->cliaddr = cliaddr;//在前面已经将 attr 设置为分离态了,因此不存在 主线程回收的问题pthread_create(&pthid, &attr, client_fun, info);}return 0;}//子线程启动调用函数
void* client_fun(void* arg)
{CINFO* info = (CINFO*)arg;char ip[16] = "";printf("new client ip=%s port=%d\n", inet_ntop(AF_INET, &(info->cliaddr.sin_addr.s_addr), ip, 16),ntohs(info->cliaddr.sin_port));while (1){char buf[1024] = "";int count = 0;count = read(info->cfd, buf, sizeof(buf));if (count < 0){perror("");break;}else if (count == 0){printf("client close\n");break;}else{printf("%s\n", buf);write(info->cfd, buf, count);}}close(info->cfd);//记得最后要释放info,避免内存泄漏free(info);
}

编译命令

gcc wrap.c socket_server_support_more_clientconnect_use_pthread.c -lpthread -o socket_server_support_more_clientconnect_use_pthread.out

四. select 模型

五 poll 模型

六 epoll 模型

相关文章:

150 Linux 网络编程6 ,从socket 到 epoll整理。listen函数参数再研究

一 . 只能被一个client 链接 socket例子 此例子用于socket 例子&#xff0c; 该例子只能用于一个客户端连接server。 不能用于多个client 连接 server socket_server_support_one_clientconnect.c /* 此例子用于socket 例子&#xff0c; 该例子只能用于一个客户端连接server。…...

centos7 配置国内镜像源安装 docker

使用国内镜像源&#xff1a;由于 Docker 的官方源在国内访问可能不稳定&#xff0c;你可以使用国内的镜像源&#xff0c;如阿里云的镜像源。手动创建 /etc/yum.repos.d/docker-ce.repo 文件&#xff0c;并添加以下内容&#xff1a; [docker-ce-stable] nameDocker CE Stable -…...

周末总结(2024/01/25)

工作 人际关系核心实践&#xff1a; 要学会随时回应别人的善意&#xff0c;执行时间控制在5分钟以内 坚持每天早会打招呼 遇到接不住的话题时拉低自己&#xff0c;抬高别人(无阴阳气息) 朋友圈点赞控制在5min以内&#xff0c;职场社交不要放在5min以外 职场的人际关系在面对利…...

【go语言】map 和 list

一、map map 是一种无序的键值对的集合。 无序 &#xff1a;map[key]键值对&#xff1a;key - value map 最重要的一点是通过 key 来快速检索数据&#xff0c;key 类似于索引&#xff0c;指向数据的值。map 是一种集合&#xff0c;所以我们可以像迭代数组和切片那样迭代他。…...

PCIe 个人理解专栏——【2】LTSSM(Link Training and Status State Machine)

前言&#xff1a; 链路训练和状况状态机LTSSM&#xff08;Link Training and Status State Machine&#xff09;是整个链路训练和运行中状态的状态转换逻辑关系图&#xff0c;总共有11个状态。 正文&#xff1a; 包括检测&#xff08;Detect&#xff09;&#xff0c;轮询&…...

《DiffIR:用于图像修复的高效扩散模型》学习笔记

paper&#xff1a;2303.09472 GitHub&#xff1a;GitHub - Zj-BinXia/DiffIR: This project is the official implementation of Diffir: Efficient diffusion model for image restoration, ICCV2023 目录 摘要 1、介绍 2、相关工作 2.1 图像恢复&#xff08;Image Rest…...

Vue3 30天精进之旅:Day01 - 初识Vue.js的奇妙世界

引言 在前端开发领域&#xff0c;Vue.js是一款极具人气的JavaScript框架。它以其简单易用、灵活高效的特性&#xff0c;吸引了大量开发者。本文是“Vue 3之30天系列学习”的第一篇博客&#xff0c;旨在帮助大家快速了解Vue.js的基本概念和核心特性&#xff0c;为后续的深入学习…...

[笔记] 极狐GitLab实例 : 手动备份步骤总结

官方备份文档 : 备份和恢复极狐GitLab 一. 要求 为了能够进行备份和恢复&#xff0c;请确保您系统已安装 Rsync。 如果您安装了极狐GitLab&#xff1a; 如果您使用 Omnibus 软件包&#xff0c;则无需额外操作。如果您使用源代码安装&#xff0c;您需要确定是否安装了 rsync。…...

将本地项目上传到 GitLab/GitHub

以下是将本地项目上传到 GitLab 的完整步骤&#xff0c;从创建仓库到推送代码的详细流程&#xff1a; 1. 在 GitLab 上创建新项目 登录 GitLab&#xff0c;点击 New project。选择 Create blank project。填写项目信息&#xff1a; Project name: 项目名称&#xff08;如 my-p…...

switch组件的功能与用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了PageView这个Widget,本章回中将介绍Switch Widget.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的Switch是指左右滑动的开关&#xff0c;常用来表示某项设置是打开还是关闭。Fl…...

mac 电脑上安装adb命令

在Mac下配置android adb命令环境&#xff0c;配置方式如下&#xff1a; 1、下载并安装IDE &#xff08;android studio&#xff09; Android Studio官网下载链接 详细的安装连接请参考 Mac 安装Android studio 2、配置环境 在安装完成之后&#xff0c;将android的adb工具所在…...

Couchbase UI: Dashboard

以下是 Couchbase UI Dashboard 页面详细介绍&#xff0c;包括页面布局和功能说明&#xff0c;帮助你更好地理解和使用。 1. 首页&#xff08;Overview&#xff09; 功能&#xff1a;提供集群的整体健康状态和性能摘要 集群状态 节点健康状况&#xff1a;绿色&#xff08;正…...

[极客大挑战 2019]Knife1

题目 蚁剑直接连接密码是Syc 拿下flag flag{1d373584-fc74-4a2c-a6d4-3691314be4ab}...

第17篇:python进阶:详解数据分析与处理

第17篇&#xff1a;数据分析与处理 内容简介 本篇文章将深入探讨数据分析与处理在Python中的应用。您将学习如何使用pandas库进行数据清洗与分析&#xff0c;掌握matplotlib和seaborn库进行数据可视化&#xff0c;以及处理大型数据集的技巧。通过丰富的代码示例和实战案例&am…...

【Maui】提示消息的扩展

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;3.1 消息扩展库3.2 消息提示框使用3.3 错误消息提示使用3.4 问题选择框使用 四、项目展示 前言 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架&#xff0c;用于使用 C# 和 XAML 创建本机移…...

消息队列篇--通信协议扩展篇--二进制编码(ASCII,UTF-8,UTF-16,Unicode等)

1、ASCII&#xff08;American Standard Code for Information Interchange&#xff09; 范围&#xff1a;0 到 127&#xff08;共 128 个字符&#xff09;描述&#xff1a;ASCII 是一种早期的字符编码标准&#xff0c;主要用于表示英文字母、数字和一些常见的符号。每个字符占…...

CentOS 7 搭建lsyncd实现文件实时同步 —— 筑梦之路

在 CentOS 7 上搭建 lsyncd&#xff08;Live Syncing Daemon&#xff09;以实现文件的实时同步&#xff0c;可以按照以下步骤进行操作。lsyncd 是一个基于 inotify 的轻量级实时同步工具&#xff0c;支持本地和远程同步。以下是详细的安装和配置步骤&#xff1a; 1. 系统准备 …...

【2025最新计算机毕业设计】基于SSM房屋租赁平台【提供源码+答辩PPT+文档+项目部署】(高质量源码,可定制,提供文档,免费部署到本地)

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...

(开源)基于Django+Yolov8+Tensorflow的智能鸟类识别平台

1 项目简介&#xff08;开源地址在文章结尾&#xff09; 系统旨在为了帮助鸟类爱好者、学者、动物保护协会等群体更好的了解和保护鸟类动物。用户群体可以通过平台采集野外鸟类的保护动物照片和视频&#xff0c;甄别分类、实况分析鸟类保护动物&#xff0c;与全世界各地的用户&…...

【转帖】eclipse-24-09版本后,怎么还原原来版本的搜索功能

【1】原贴地址&#xff1a;eclipse - 怎么还原原来版本的搜索功能_eclipse打开类型搜索类功能失效-CSDN博客 https://blog.csdn.net/sinat_32238399/article/details/145113105 【2】原文如下&#xff1a; 更新eclipse-24-09版本后之后&#xff0c;新的搜索功能&#xff08;CT…...

【自定义函数】编码-查询-匹配

目录 自定义编码匹配编码匹配改进 sheet来源汇总来源汇总改进 END 自定义编码匹配 在wps vb环境写一个新的excel函数名为编码匹配&#xff0c;第一个参数指定待匹配文本所在单元格&#xff08;相对引用&#xff09;&#xff0c;第二个参数指定关键词区域&#xff08;绝对引用&…...

16 分布式session和无状态的会话

在我们传统的应用中session存储在服务端&#xff0c;减少服务端的查询压力。如果以集群的方式部署&#xff0c;用户登录的session存储在该次登录的服务器节点上&#xff0c;如果下次访问服务端的请求落到其他节点上就需要重新生成session&#xff0c;这样用户需要频繁的登录。 …...

git基础指令大全

版本控制 git管理文件夹 进入要管理的文件夹 — 进入 初始化&#xff08;提名&#xff09; git init 管理文件夹 生成版本 .git ---- git在管理文件夹时&#xff0c;版本控制的信息 生成版本 git status 检测当前文件夹下的文件状态 (检测&#xff0c;检测之后就要管理了…...

Android实训九 数据存储和访问

实训9 数据存储和访问 一、【实训目的】 1、 SharedPreferences存储数据; 2、 借助Java的I/O体系实现文件的存储&#xff0c; 3、使用Android内置的轻量级数据库SQLite存储数据; 二、【实训内容】 1、实现下图所示的界面&#xff0c;实现以下功能&#xff1a; 1&#xff…...

[STM32 标准库]定时器输出PWM配置流程 PWM模式解析

前言&#xff1a; 本文内容基本来自江协&#xff0c;整理起来方便日后开发使用。MCU&#xff1a;STM32F103C8T6。 一、配置流程 1、开启GPIO&#xff0c;TIM的时钟 /*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟RCC_APB2PeriphClockC…...

如何跨互联网adb连接到远程手机-蓝牙电话集中维护

如何跨互联网adb连接到远程手机-蓝牙电话集中维护 --ADB连接专题 一、前言 随便找一个手机&#xff0c;安装一个App并简单设置一下&#xff0c;就可以跨互联网的ADB连接到这个手机&#xff0c;从而远程操控这个手机做各种操作。你敢相信吗&#xff1f;而这正是本篇想要描述的…...

【6】YOLOv8 训练自己的分割数据集

YOLOv8 训练自己的分割数据集:详细指南 引言 YOLOv8作为目标检测领域的佼佼者,其在实例分割任务上也表现出色。本文将详细介绍如何使用YOLOv8训练自己的分割数据集,从数据集准备、模型训练、评估到部署,全方位地进行阐述。 一、数据集准备 数据收集: 图像/视频来源: 与目…...

将 OneLake 数据索引到 Elasticsearch - 第二部分

作者&#xff1a;来自 Elastic Gustavo Llermaly 及 Jeffrey Rengifo 本文分为两部分&#xff0c;第二部分介绍如何使用自定义连接器将 OneLake 数据索引并搜索到 Elastic 中。 在本文中&#xff0c;我们将利用第 1 部分中学到的知识来创建 OneLake 自定义 Elasticsearch 连接器…...

Android Studio:视图绑定的岁月变迁(2/100)

一、博文导读 本文是基于Android Studio真实项目&#xff0c;通过解析源码了解真实应用场景&#xff0c;写文的视角和读者是同步的&#xff0c;想到看到写到&#xff0c;没有上帝视角。 前期回顾&#xff0c;本文是第二期。 private Unbinder mUnbinder; 只是声明了一个 接口…...

私有包上传maven私有仓库nexus-2.9.2

一、上传 二、获取相应文件 三、最后修改自己的pom文件...