Linux网络套接字
Socket 编程 UDP
本章将函数介绍和代码编写实战一起使用。
IPv4 的 socket 网络编程,sockaddr_in 中的成员 struct in_addr.sin_addr 表示 32 位 的 IP 地址
但是我们通常用点分十进制的字符串表示 IP 地址,以下函数可以在字符串表示和in_addr 表示之间转换;
字符串转 in_addr 的函数:
#include <arpa/inet.h>
int inet_aton(const char:*strptr,struct inaddr *addrptr);
int_addr_t inet_addr(const char *strptr);
int inet_pton(int family,const char *strptr,void *addrptr);
in_addr 转字符串的函数:
char *inet_ntoa(struct in addrinaddr);
const char *inet_ntop(int family,const void *addrptr, char *strptr,size t len);
查看OS所有UDP和进程信息:
netstat -naup
这个函数是创建一个套接字:
int socket(int domain, int type,int protocol);
第一个参数是套接字的域,就是确定是ipv4还是ipv6等待。
第二个是套接字的数据流类型。
第三个参数是协议类型。
返回值是:返回成功返回一个文件操作符,失败返回-1。
其实socket也就相当于创建了一个文件。

这个函数是绑定套接字:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
第一个参数是网络文件描述符
第二个参数是用哪一种套接字(让绑定过来的套接字实现哪一种功能)

将指定内存全部初始化为0的函数:
void bzero(void *s, size_t n);
第一个参数是传地址
第二个参数是缓冲区的大小

in_addr_t inet_addr(const char *cp);
让字符串转换成网络ip风格的四字节

接收信息函数:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
第二个参数为接收容器
第三个参数为信息长度
第四个参数为设置阻塞与非阻塞
第六个参数为套接字种类的长度

发送信息函数:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
参数和上一个函数差不多,只有最后一个参数是不需要取地址的

首先有一个代码的预备工作,实现一个日志附带文件打印功能的代码
//log.hpp
#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:std::cout << logtxt << std::endl;break;case Onefile:printOneFile(LogFile, logtxt);break;case Classfile:printClassFile(level, logtxt);break;default:break;}}void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug/Warning/Fatal"printOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};
Log log;
模拟服务器
#include "udpserver.hpp"
#pragma once
#include <memory>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;extern Log log;//声明变量log
enum{SOCKET_ERR = 1,//套接字创建失败BIND_ERR
};uint16_t defaultport = 8080;//默认端口
//绑定端口号的时候要注意,很多端口都是被应用层协议固定使用[0,1023]这个区间:http:80 https:443等等
//建议使用1024以上,但也要注意,比如mysql:3306
string defaultip = "0.0.0.0";//默认ip,bind为0就是任意ip地址都可以进到服务器来const int size = 1024;class UdpServer
{
public:UdpServer(const uint16_t &port = defaultport, const string &ip = defaultip):sockfd_(0),port_(port),ip_(ip),isrunning_(false){}void Init(){//1.创建udp socketsockfd_ = socket(AF_INET,SOCK_DGRAM,0);if(sockfd_ < 0){log(Fatal,"socket create error, socket:%d",sockfd_);exit(SOCKET_ERR);}log(Info,"socket create success, socket:%d",sockfd_);//2.bind socketstruct sockaddr_in local;bzero(&local,sizeof(local));local.sin_family = AF_INET;//设置自己为IPV4local.sin_port = htons(port_);//因为端口号需要给对方发送,所以必须要保证我的端口号是网络字节序列local.sin_addr.s_addr = inet_addr(ip_.c_str());//1.将string->uint32_t 2.必须是网络序列//sin_addr里面还有一个成员,s_addr才是真实的本体 //local.sin_addr.s_addr=INADDR_ANY;也是绑定任意IP地址的方法int n = bind(sockfd_,(const struct sockaddr *)&local,sizeof(local));if(n < 0){log(Fatal, "bind error, error: %d, err string:%s",errno, strerror(errno));exit(BIND_ERR);}log(Info,"bind success, errno: %d, err string: %s",errno,strerror(errno));}void Run(){isrunning_ = true;char inbuffer[size];while(isrunning_){struct sockaddr_in client;socklen_t len = sizeof(client); ssize_t n = recvfrom(sockfd_,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&client,&len);if(n < 0){log(Warning,"recvfrom error,errno: %d,err string:%s",errno,strerror(errno));continue;}string info = inbuffer;string echo_string = "server echo#" + info;sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(struct sockaddr*)&client,len);}}~UdpServer(){if(sockfd_ > 0) close(sockfd_); }
private:int sockfd_;//网络文件描述符string ip_;//服务器iP地址uint16_t port_;//服务器进程的端口号bool isrunning_;//服务器是否在运行
};
#include "log.hpp"
#include "udpserver.hpp"void Usage(string proc)
{cout << "\n\rUsage:" << proc << "port[1024+]\n" << endl;
}
int main(int argc,char* argv[])
{if(argc != 2){Usage(argv[0]);exit(0);}uint16_t port = stoi(argv[1]);unique_ptr<UdpServer> svr(new UdpServer(port));svr->Init();svr->Run();return 0;
}
客户端
#pragma once
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
using namespace std;void Usage(string proc)
{cout << "\n\rUsage:" << proc << "port[1024+]\n" << endl;
}
int main(int argc,char* argv[])
{if(argc != 3){Usage(argv[0]);exit(0);}string serverip = argv[1];uint16_t serverport = stoi(argv[2]);struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());socklen_t len = sizeof(server);int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){cout << "socket error" << endl;exit(1);}//客户端需要绑定,但是不需要显示绑定,由OS自己选择//为了防止进程端口出现冲突//OS什么时候给我绑定的呢?是在首次发送数据的时候string message;char buffer[1024];while(true){cout << "Please Enter@ ";getline(cin,message);//1.数据2.发给谁sendto(sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,len);struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s = recvfrom(sockfd,buffer,1023,0,(struct sockaddr*)&temp,&len);if(s > 0){buffer[s] = 0;cout << buffer <<endl;}}close(sockfd);return 0;
}
Socket 编程 TCP
测试服务器工具,指定服务器远程登陆:
telnet 127.0.0.1 端口号
127.0.0.1表示本地环回。
第一个函数也是将字符串的ip转换成网络四字节的ip。

因为TCP是面向连接的,服务器比较被动,一直处于等待链接到来的状态,所以用监听的方式查看是否有客户端到来。
这个函数是将套接字设置监听状态:
int listen(int sockfd, int backlog);
第二个参数等后面TCP协议在进行解释

接收消息函数,并获知哪个客户端连接上了自己:
int accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags);
这里返回值也是一个套接字,那么我们第一个参数也是套接字,有什么区别呢?
我们输入的套接字就相当于饭店外面的接待员,并不参与真正的服务当中,返回值的套接字才是真正的服务员,服务被接待过的客人。
也就是说,第一个参数的套接字仅仅是帮助我们获取新连接的工具人。

通过指定的套接字发送连接。
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

这个客户端与服务器的程序还是要用到上面log的代码:
服务器
#pragma once
#include "log.hpp"
#include <memory>
#include <sys/socket.h>
#include <cstdlib>
#include <cstdlib>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;
extern Log log;
const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const int backlog = 10;
enum
{UsageError = 1,SocketError,BindError,ListenError
};
class TcpServer;
class ThreadData
{
public:ThreadData(int fd, const string &ip, const uint16_t &p, TcpServer *t): sockfd(fd), clientip(ip), clientport(p), tsvr(t){}
public:int sockfd;string clientip;uint16_t clientport;TcpServer *tsvr;
};
class TcpServer
{
public:TcpServer(const uint16_t &port,const string &ip = defaultip):listensock_(defaultfd),port_(port),ip_(ip){}void InitServer(){listensock_ = socket(AF_INET,SOCK_STREAM,0);if(listensock_ < 0){log(Fatal,"create socket,errno: %d,errstring: %s",errno,strerror(errno));exit(SocketError);}log(Info,"create socket success, sockfd:%d",listensock_);struct sockaddr_in local;memset(&local,0,sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_);inet_aton(ip_.c_str(),&(local.sin_addr));if(bind(listensock_,(struct sockaddr*)&local,sizeof(local)) < 0){log(Fatal,"bind error, errno: %d, errstring:%s",errno,strerror(errno));exit(BindError);}if(listen(listensock_,backlog)<0){log(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));exit(ListenError);}log(Info, "listen socket success, listensock_: %d", listensock_);}static void *Routine(void *args){pthread_detach(pthread_self());//分离状态不用让主线程去等待,互不影响ThreadData *td = static_cast<ThreadData *>(args);td->tsvr->Service(td->sockfd, td->clientip, td->clientport);delete td;return nullptr;}void Start(){log(Info, "tcpServer is running....");for(;;){//1.获取新连接struct sockaddr_in client;socklen_t len = sizeof(client);int sockfd = accept(listensock_,(struct sockaddr*)&client,&len);if(sockfd < 0){log(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //获取一个失败不必推出,再次进行下一个获取即可continue;}uint16_t clientport = ntohs(client.sin_port);char clientip[32];inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));//2. 根据新连接来进行通信log(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, clientip, clientport);//单进程版本,无法让多个客户端进行连接/*Service(sockfd, clientip,clientport);close(sockfd);*///多进程版,让子进程去处理客户端,父进程继续向下执行。创建多个进程就能连接多个客户端/*pid_t id = fork();if(id == 0){//childclose(listensock_);//这个是父进程用的fd,防止误操作if(fork() > 0) exit(0);//因为是阻塞等待,所以让子进程再创建子进程去处理客户端Service(sockfd, clientip, clientport); //孙子进程来处理客户端,system 领养close(sockfd);exit(0);}close(sockfd);//这里必须关闭,因为sockfd已经交给子进程处理了,父进程不需要在管理了,不然父进程的文件描述符会越用越少// fatherpid_t rid = waitpid(id, nullptr, 0);(void)rid;*///多线程版ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);pthread_t tid;pthread_create(&tid, nullptr, Routine, td);}}void Service(int sockfd,const string& clientip,const uint16_t &clientport)//因为是面向字节流的,所以用read和write对网络文件进行读写即可{char buffer[4096];while (true){ssize_t n = read(sockfd, buffer, sizeof(buffer));if (n > 0){buffer[n] = 0;cout << "client say# " << buffer << endl;string echo_string = "tcpserver echo# ";echo_string += buffer;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n == 0)//客户端退出,就会关闭套接字{log(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);break;}else{log(Warning, "read error, sockfd: %d, client ip: %s, client port: %d", sockfd, clientip.c_str(), clientport);break;}}}~TcpServer(){}
private:int listensock_;string ip_;uint16_t port_;
};
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
using namespace std;
void Usage(const string &proc)
{cout << "\n\rUsage: " << proc << " serverip serverport\n"<< endl;
}
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}string serverip = argv[1];uint16_t serverport = stoi(argv[2]);//TCP方式的客户端bind实在什么时候呢?//是在connect的时候OS自动绑定struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);inet_pton(AF_INET, serverip.c_str(), &(server.sin_addr));int sockfd = 0;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){cerr << "socket error" << endl;return 1;}int n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){cerr << "connect error..., reconnect: "<< endl;}while(true){string message;cout << "Please Enter# ";getline(cin, message);int n = write(sockfd, message.c_str(), message.size());if (n < 0){cerr << "write error..." << endl;}char inbuffer[4096];n = read(sockfd, inbuffer, sizeof(inbuffer));if (n > 0){inbuffer[n] = 0;cout << inbuffer << endl;}}close(sockfd);return 0;
}
客户端
#include "tcpserver.hpp"
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[1024+]\n" << std::endl;
}
int main(int argc, char *argv[])
{if(argc != 2){Usage(argv[0]);exit(UsageError);}uint16_t port = std::stoi(argv[1]);std::unique_ptr<TcpServer> tcp_svr(new TcpServer(port));tcp_svr->InitServer();tcp_svr->Start();return 0;
}
守护进程
两个人在使用一个服务器,那么服务器就会生成两个“会话”(session),会话里面包含了命令行解释器(bash),和多个进程。

眼下,两个bash都是前台进程,其他的都是后台进程,并且一个会话当中只能有一个前台进程。
无论前台还是后台进程都可以向显示器进行打印,但是能用键盘的只有前台。(比如说将bash变成后台,另一个进程变成前台进程,Ctrl+C就能让这个进程停止,然后将bash换回到前台)——谁拥有键盘文件谁就是前台。
如何将进程后台运行呢?
只需要在启动可执行文件的时候加上一个&即可。
如果想让进程变成前台需要
fg+任务号
用jobs指令来查看后台任务号。
如果某一个前台进程被暂停之后放到后台了,想让这个后台继续运行:
bg+任务号
进程间的关系

这里的PGID是进程组的ID,SID是会话的ID。
会话也是要被OS组织管理的。
第一个进程PID和PGID是一样的,说明这个进程自成一组。
剩下三个PGID一样说明他们三个是一组。(一般来说,第一个进程是组长)
组长是组内中PID和PGID相同的进程。
平时所有任务其实都是进程组在完成!
也就是说,前台进程和后台进程其实并不正确,应该叫做前台任务和后台任务!
那么SID的ID是谁呢?
其实就是bash。
如果客户端退出了呢?

TTY全变成了?也就是说跟终端无关了。
TPGID变成了1。
并且退出的客户端的进程全都被OS给领养了。
也就是说这些进程收到了客户端登录和退出的影响。
如果不想让这些进程受到客户端的影响,那么这就叫守护进程化。(也叫精灵进程)
注销
windowsOS党总有一个操作叫做注销,注销就是将整个会话给关闭。
当重新登录的时候就相当于重新创建一个会话。
守护进程
如何进行守护进程化呢?
那就是让一个会话当中的某个进程脱离当前会话,自成一个会话,上一个会话进行销毁也就和这个进程无关了。
函数接口
#include <unistd.h>
pid_t setsid(void);
谁调用这个函数谁就被设置成为守护进程,成功返回一个新的pid,失败返回-1.

但是这个函数不会让这个进程成为新会话的组长。
可是新的会话只有这个进程,那怎么办呢?只要不让这个进程是第一个进程就好了。
if(fork()>0) exit(0);
srtsid();
所以守护进程的本质也是孤儿进程。
如果程序生成一个守护进程(以服务器举例),分为以下几个步骤:
1.忽略部分异常信号
2.将自己变成独立会话
3.更改当前调用进程的工作目录
4.标准输入输出错误不要在打印到屏幕上,重定向到/dev/null(也可以放在一个文件里形成文件的日志)
这样就能让一个服务器在后台持久运行了。
注意:守护进程命名习惯是后面以d为结尾。
让进程和以上效果相同的函数:
第一个参数是设置为0是将工作目录设置为根目录,否则就是当前目录,
第二个参数是设置为0是将标准输入输出错误重定向到/dev/null。

TCP简单的特性
三次握手与四次挥手
TCP会三次握手来进行链接的建立:

通过四次挥手进行释放:

注意:TCP是全双工的。(可以互相通信)
那么为什么不会相互收到影响呢?

因为在两个客户端当中,双方网络文件的上层都有自己的两种缓冲区,下层也是,所以不会冲突。(双方资源是隔离的)
也就是说我们上面用的read和write都是在对网络上下的两个缓冲区之间进行拷贝。
但TCP是面向字节流的,我们如何保证都上来的是一个完整的报文?
在用read和write的时候,TCP会有一个传输控制协议!
什么时候发,发多少,出错了如何解决?
也就是说write写的时候,其实从自己的缓冲区发送到网络的缓冲区就直接返回了,我们并不知道到底有没有发送到对方手里,因为这是TCP决定的。(其实就是给了OS,因为TCP也是在OS当中实现的,也就是TCP网络模块)
同理,read也是一样的。
所以这就需要协议定制,序列化和反序列化。
相关文章:
Linux网络套接字
Socket 编程 UDP 本章将函数介绍和代码编写实战一起使用。 IPv4 的 socket 网络编程,sockaddr_in 中的成员 struct in_addr.sin_addr 表示 32 位 的 IP 地址 但是我们通常用点分十进制的字符串表示 IP 地址,以下函数可以在字符串表示和in_addr 表示之间转换; 字符串转 in_addr…...
看爬山虎学本领 软爬机器人来创新 各种场景能适应
*本文只做阅读笔记分享* 一、灵感来源:向植物取经 大家好!今天来聊一款超酷的软爬机器人,它的灵感来自会攀爬的植物——爬山虎。 大家都知道,爬墙高手爬山虎能在各种复杂墙面轻松生长攀爬,可现有的攀爬机器人在复杂…...
1-Docker安装
1.准备环境 1.第一步:创建以自己的姓名全拼的用户名 [roothadoop ~]# useradd qiwenyong [roothadoop ~]# passwd qiwenyong Changing password for user qiwenyong. New password: BAD PASSWORD: The password is shorter than 7 characters Retype new passwor…...
WPS JS宏编程教程(从基础到进阶)-- 第三部分:JS宏编程语言开发基础
第三部分:JS宏编程语言开发基础 @[TOC](第三部分:JS宏编程语言开发基础)**第三部分:JS宏编程语言开发基础**1. 变量与数据类型**变量声明:三种方式****示例代码****数据类型判断****实战:动态处理单元格类型**2. 运算符全解析**算术运算符****易错点:字符串拼接 vs 数值相…...
BT-Basic函数之首字母T
BT-Basic函数之首字母T 文章目录 BT-Basic函数之首字母Ttabtesttest conttest monitortest on boardstest scanworkstest shortstesthead cleanuptesthead configurationtesthead istesthead power on/offtesthead statustestjet print level istestordertestplan generationth…...
经典算法 约数之和
原题目链接 问题描述 假设现在有两个自然数 A 和 B,设 S 为 A^B 的所有约数之和。 请你计算:S mod 9901 的值。 输入格式 在一行中输入两个用空格隔开的整数 A 和 B。 输出格式 输出一个整数,表示 S mod 9901 的值。 数据范围 0 ≤ A, …...
Flinksql--订单宽表
参考: https://chbxw.blog.csdn.net/article/details/115078261 (datastream 实现) 一、ODS 模拟订单表及订单明细表 CREATE TABLE orders (order_id STRING,user_id STRING,order_time TIMESTAMP(3),-- 定义事件时间及 Watermark(允许5秒乱序&#x…...
C# 窗体应用(.FET Framework ) 打开文件操作
一、 打开文件或文件夹加载数据 1. 定义一个列表用来接收路径 public List<string> paths new List<string>();2. 打开文件选择一个文件并将文件放入列表中 OpenFileDialog open new OpenFileDialog(); // 过滤 open.Filter "(*.jpg;*.jpge;*.bmp;*.png…...
极客天成NVFile:无缓存直击存储性能天花板,重新定义AI时代并行存储新范式
在AI算力需求呈指数级爆发的今天,存储系统正面临一场前所未有的范式革命。传统存储架构中复杂的缓存机制、冗余的数据路径、僵化的扩展能力,已成为制约千卡GPU集群算力释放的重要因素。极客天成NVFile并行文件存储系统以全栈并行化架构设计和无缓存直通数…...
Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解
N皇后问题要求在NN的棋盘上放置N个皇后,使得她们无法互相攻击。本文提供递归和循环迭代两种解法,并通过图示解释核心逻辑。 一、算法核心思想 使用回溯法逐行放置皇后,通过冲突检测保证每行、每列、对角线上只有一个皇后。发现无效路径时回退…...
【代码艺廊】pyside6桌面应用范例:homemade-toolset
在研发测试日常工作中,通常会遇到很多琐碎的事情,占用我们工作的时间和精力,从而导致我们不能把大部分的注意力放在主要的工作上面。为了解决这个问题,除了加人之外,我们通常会开发一些日常用的效率工具,比…...
LeetCode 3047 求交集区域内的最大正方形面积
探寻矩形交集中的最大正方形面积 在算法与数据结构的探索之路上,二维平面几何问题一直占据着独特的地位,它们不仅考验我们的空间思维能力,还要求我们能够巧妙地运用算法逻辑。今天,我们将深入剖析一道极具代表性的二维平面几何算…...
谷歌开源单个 GPU 可运行的Gemma 3 模型,27B 超越 671B 参数的 DeepSeek
自从 DeepSeek 把训练成本打下来之后,各个模型厂家现在不再堆参数进行模型的能力对比。而是转向了训练成本优化方面,且还要保证模型能力不减反增的效果。包括使用较少的模型参数,降低 GPU 使用数量,降低模型内存占用等等技术手段。…...
C++_类和对象(下)
【本节目标】 再谈构造函数Static成员友元内部类匿名对象拷贝对象时的一些编译器优化再次理解封装 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 class Date { public:Date(in…...
《Java实战:素数检测算法优化全解析——从暴力枚举到筛法进阶》
文章目录 摘要一、需求分析二、基础实现代码与问题原始代码(暴力枚举法)问题分析 三、优化版代码与解析优化1:平方根范围剪枝优化2:偶数快速跳过完整优化代码 四、性能对比五、高阶优化:埃拉托斯特尼筛法算法思想代码实…...
基于Python+Flask的服装零售商城APP方案,用到了DeepSeek AI、个性化推荐和AR虚拟试衣功能
首先创建项目结构: fashion_store/ ├── backend/ │ ├── app/ │ │ ├── __init__.py │ │ ├── models/ │ │ ├── routes/ │ │ ├── services/ │ │ └── utils/ │ ├── config.py │ ├── requirements.t…...
二,<FastApi>FastApi的两个核心组件
FastAPI的两个核心组件Pydantic和Starlette。 Starlette 负责Web部分(Asyncio),Starlette Starlette是一个轻量级的ASGI框架/工具包,非常适合在Python构建异步Web服务。 它已经准备好生产,并为您提供以下内容: 轻巧的低复杂性HTTP Web框架。W…...
Docker设置代理
目录 前言创建代理文件重载守护进程并重启Docker检查代理验证 前言 拉取flowable/flowable-ui失败,用DaoCloud源也没拉下来,不知道是不是没同步。索性想用代理拉镜像。在此记录一下。 创建代理文件 创建docker代理配置 sudo mkdir -p /etc/systemd/s…...
一键自动备份:数据安全的双重保障
随着数字化时代的到来,数据已成为企业和个人不可或缺的核心资产。在享受数据带来的便捷与高效的同时,数据丢失的风险也随之增加。因此,备份文件的重要性不言而喻。本文将深入探讨备份文件的重要性,并介绍两种实用的自动备份方法&a…...
HeidiSQL:多数据库管理工具
HeidiSQL 是一款广受欢迎的免费开源数据库管理工具,专为数据库管理员及开发者设计。无论您是刚接触数据库领域的新手,还是需要同时处理多种数据库系统的专业开发者,该工具都能凭借其直观的界面和强大的功能,助您轻松完成数据管理任…...
医药档案区块链系统
1. 医生用户模块 目标用户:医护人员 核心功能: 检索档案:通过关键词或筛选条件快速定位患者健康档案。请求授权:向个人用户发起档案访问权限申请,需经对方确认。查看档案…...
【Python学习】列表/元组等容器的常用内置函数详解
文章目录 map使用示例: filter示例:注意事项: sortedsorted() 与 list.sort() 的区别: any示例: all示例: any 与 all 的对比zip示例:常见用途: enumerate示例:常见用途&…...
蓝桥云客--浓缩咖啡液
4.浓缩咖啡液【算法赛】 - 蓝桥云课 问题描述 蓝桥杯备赛选手小蓝最近刷题刷到犯困,决定靠咖啡续命。他手上有 N 种浓缩咖啡液,浓度分别是 A1%, A2%, …, AN%,每种存货都是无限的。为了提神又不炸脑,小蓝需要按比例混合这…...
SQLark(百灵连接):一款面向信创应用开发者的数据库开发和管理工具
SQLark(百灵连接)是一款面向信创应用开发者的数据库开发和管理工具,用于快速查询、创建和管理不同类型的数据库系统。 目前可以支持达梦数据库、Oracle 以及 MySQL。 SQL 智能编辑器 基于语法语义解析实现代码补全能力,为你提供…...
计算机视觉——为什么 mAP 是目标检测的黄金标准
概述 在目标检测领域,有一个指标被广泛认为是衡量模型性能的“黄金标准”,它就是 mAP(Mean Average Precision,平均精确率均值)。如果你曾经接触过目标检测模型(如 YOLO、Faster R-CNN 或 SSD)…...
Frame Of Reference压缩算法
文章目录 1_概述2_算法基本步骤3_过程优化4_优势以及局限5_模拟实现6_总结 1_概述 Frame of Reference(FoR)压缩算法 是一种用于压缩数值数据的算法,特别是在处理大规模数据集时,利用数据的局部性和重复性来减少存储和传输的开销…...
1.0 软件测试全流程解析:从计划到总结的完整指南
软件测试全流程解析:从计划到总结的完整指南 摘要 本文档详细介绍了软件测试的完整流程,包括测试计划、测试设计、测试执行、测试报告和测试总结等主要阶段。每个阶段都从目标、主要工作、输出物和注意事项等方面进行了详细说明。通过本文档࿰…...
嵌入式AI简介
嵌入式AI是一种将人工智能算法部署在终端设备中运行的技术,使智能硬件能够在本地实时完成感知、交互和决策功能,无需依赖云端计算。以下是其核心要点: 一、核心特点 1. 本地化处理:数据在设备端直接处理,无需联网&a…...
esp32cam 开发板搭载ov3660摄像头在arduino中调用kimi进行图像识别
首先呢,最近搞一个项目,需要一个摄像头拍摄图片 就买了个ov3660开发板,用的esp32S芯片 淘宝商家给的教程是arduino的,所以先用arduino跑起来 arduino配置esp32-cam开发环境 - 简书1、安装arduino https://www.arduino.cc/en/Main/Software?setlang=cn 2、配置esp32 打开…...
二十种中药果实识别分类系统,Python/resnet18/pytorch
二十种中药果实识别分类系统,Python/resnet18/pytorch 基于pytorch训练, resnet18网络,可用于训练其他分类问题,也可自己重新训练 20类中药材具体包括:(1) 补骨脂,(2) 草豆蔻,(3) 川楝子,(4) 地肤子&…...
