网络编程day5

目录

使用select实现TCP并发服务器

使用poll实现TCP客户端

UDP实现网络聊天室

服务器

ser.h

main.c

func_ser.c

makefile 

客户端

cli.h

main.c

func_cli.c

makfile

 思维导图


使用select实现TCP并发服务器

#include <myhead.h>
int main(int argc, const char *argv[])
{

	//创建套接字
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0){
		perror("socket");
		return -1;
	}

	//设置端口快速重用
	int reuse=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0){
		perror("setsockopt");
		return -1;
	}
	printf("端口快速重用成功\n");


	//绑定
	//填充地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(6666);
	sin.sin_addr.s_addr=inet_addr("192.168.125.13");

	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){
		perror("bind");
		return -1;
	}

	//listen
	listen(sfd,128);

	//接收客户端地址信息
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);

	//创建集合
	fd_set readfds,tempfds;

	//清空集合
	FD_ZERO(&readfds);

	//将要监听的文件描述符加入集合
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);



	int res;                                   //接收select返回值
	char buf[128];                             //
	int maxfd=sfd;
	struct sockaddr_in cin_arr[1024];          //存储客户端地址信息

	while(1){

		//tempfds存储readfds,当事件触发时select
		tempfds=readfds;

		//select函数阻塞监听集合中的函数,直到有事件发生解除阻塞
		res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(0==res){
			printf("time out\n");
			return -1;
		}
		else if(res<0){
			perror("select error");
			return -1;
		}
		//运行到这说明有事件触发
		for(int i=0;i<=maxfd;i++){

			//如果i不在集合中直接遍历下一个
			if(!FD_ISSET(i,&tempfds)){
				continue;
			}

			//触发键盘输入事件
			if(0==i){
				printf("触发键盘输入事件:");
				memset(buf,0,sizeof(buf));
				fgets(buf,sizeof(buf),stdin);
				buf[strlen(buf)-1]='\0';

				printf("%s\n",buf);
			}

			//触发sfd事件
			else if(sfd==i){
				//accept
				int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
				if(newfd<0){
					perror("accept");
					return -1;
				}
				//终端打印客户端连接信息
				printf("[%s %d] newfd=%d accept success\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);

				//将连接的客户端加入集合
				FD_SET(newfd,&readfds);
				cin_arr[newfd]=cin;

				//更新maxfd
				maxfd=maxfd>newfd?maxfd:newfd;
			}

			//其他为客户端发送信息
			else{
				memset(buf,0,sizeof(buf));

				//recv为0说明客户端下线
				if(0==recv(i,buf,sizeof(buf),0)){
					printf("[%s %d]客户端下线\n",inet_ntoa(cin_arr[i].sin_addr),ntohs(cin_arr[i].sin_port));

					//下线需要关闭文件描述
					close(i);
					//客户端下线后需要再集合中函数newfd
					FD_CLR(i,&readfds);

					int j=0;

					//如果移除的为最大的maxfd,则需要更新maxfd
					if(i==maxfd){
						//从maxfd开始往下遍历,找到集合中最大更新maxfd,break
						for(j=maxfd;j>0;j--){
							if(FD_ISSET(j,&readfds)){
								maxfd=j;
								break;
							}
						}
						if(0==j)maxfd=0;
					}
					continue;
				}
				printf("[%s %d]%s\n",inet_ntoa(cin_arr[i].sin_addr),ntohs(cin_arr[i].sin_port),buf);
				strcat(buf,"*-*");
				send(i,buf,sizeof(buf),0);
			}
		}
	}
	close(sfd);
	return 0;
}

使用poll实现TCP客户端

#include <myhead.h>
//使用poll实现TCP客户端
int main(int argc, const char *argv[])
{
	//创建套接字
	int cfd=socket(AF_INET,SOCK_STREAM,0);
	if(cfd<0){
		perror("socket");
		return -1;
	}

	//绑定非必须
	
	//填充服务器地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(6666);
	sin.sin_addr.s_addr=inet_addr("192.168.125.13");

	//创建集合
	struct pollfd pollfds[2];

	//监测0号文件描述符的读事件
	pollfds[0].fd=0;
	pollfds[0].events=POLLIN;

	//监测cfd的读事件
	pollfds[1].fd=cfd;
	pollfds[1].events=POLLIN;

	//连接服务器
	if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0){
		perror("connect");
		return -1;
	}

	int res;                   //接收poll函数的返回值
	char buf[128];
	while(1){
		//使用poll函数监测集合文件描述的事件
		res=poll(pollfds,2,-1);
		if(0==res){
			printf("time out\n");
			return -1;

		}
		else if(res<0){
			perror("poll error");
			return -1;
		}

		//运行到这说明有事件触发
		if(pollfds[0].revents==POLLIN){

			//从终端获取输入
			memset(buf,0,sizeof(buf));
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]='\0';
			printf("触发键盘输入:%s\n",buf);

			//发送给服务器
			send(cfd,buf,sizeof(buf),0);
		}
		if(pollfds[1].revents=POLLIN){
			memset(buf,0,sizeof(buf));

			//接收服务器信息
			recv(cfd,buf,sizeof(buf),0);
			printf("收到服务器信息%s\n",buf);
		}
	}

	//关闭文件描述符
	close(cfd);
	return 0;
}

UDP实现网络聊天室

服务器

ser.h

#ifndef __SER_H__
#define __SER_H__
#include <myhead.h>

#define ERR_MSG(msg) do{fprintf(stderr,"__%d__",__LINE__);\
						perror(msg);\
						}while(0)
#define IP "192.168.125.13"
#define PORT 6666

//通信结构体
typedef struct
{
    int  type;                 //用户状态:定义1为登录、2为聊天,3为客户端下线,4为系统信息
    char name[128];            //用户名
    char msg[128];             //消息
}user_t;

//线程传参结构体
typedef struct
{
	sqlite3 *db;
	int sfd;
}th_t;

//线程调用函数传参
typedef struct
{
	th_t th;
	user_t user;
}temp_t;

//在数据库中创建表
int create_sheet(sqlite3 *db);

//在数据库中插入表
int insert_sheet(sqlite3 *db,char *name,struct sockaddr_in cin);

//在数据库中查找
int search(sqlite3 *db,char *name,void *arg);

//查找回调函数
int select_callback(void *arg,int columns,char **column_text,char **colum_name);

//删除表中记录
int del_sheet(sqlite3 *db,char *name);

//删除表
int del_sheet_a(sqlite3 *db);

//服务发送系统信息线程
void *task(void *arg);

#endif

main.c

#include "ser.h"
//UDP实现网络聊天室
//UDP服务器

int main(int argc, const char *argv[])
{

	int sfd;                       //socket文件描述符
	//1.打开套接字
	sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd<0){
		ERR_MSG("socket");
		return -1;
	}
	
	//填充服务器IP和端口号
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);
	//2.绑定
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0){
		ERR_MSG("bind");
		return -1;
	}	
	printf("bind success\n");
	//接收客户端地址信息
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);
	

	//创建数据库
	sqlite3 *db;                   //数据库指针

	//指向数据库的指针,数据库操作的句柄
	if(sqlite3_open("./chat.db",&db)!=0){
		fprintf(stderr,"__%d__sqlite3_open error",__LINE__);
		return -1;
	}
	//分支线程传参
	th_t th;
	th.db=db;
	th.sfd=sfd;

	//创建分支线程,用于服务器给客户端发送系统信息
	pthread_t tid;
	if(pthread_create(&tid,NULL,task,&th)){
		fprintf(stderr,"__%d__pthread_create error\n",__LINE__);
		return -1;
	}
	//每次重启服务器后清空数据库表
	del_sheet_a(db);

	//创建表
	create_sheet(db);

	//search函数传参
	temp_t temp;
	temp.th.sfd=sfd;

	user_t user;                   //消息结构体变量

	int res;     //登录时用户名重复标志
	while(1){
		bzero(&user.msg,sizeof(user.msg));
		//接收时需要知道发送方
		recvfrom(sfd,&user,sizeof(user),0,(struct sockaddr*)&cin,&addrlen);
		//用户登录时把用户名,IP,PORT存入数据库中
		//登录时用户名不可以和数据库中用户名重复
		if(1==user.type){
			do{
				res=insert_sheet(db,user.name,cin);
				sendto(sfd,&res,sizeof(res),0,(struct sockaddr *)&cin,addrlen);
				if(res!=0){
					recvfrom(sfd,&user,sizeof(user),0,(struct sockaddr*)&cin,&addrlen);
				}
			}while(res);
			//转发给在线的其他用户该用户登录成功
			temp.user=user;
			search(db,user.name,&temp);	
			//在服务器打印该客户登录成功
			printf("[%s %d] user:%s 登录成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),user.name);
		}
		//用户聊天时服务器转发客户端消息
		else if(2==user.type){
			//转发客户端消息 
			temp.user=user;
			search(db,user.name,&temp);
			//在服务器打印用户聊天成功
			printf("[%s %d] user:%s chat成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),user.name);
		}
		else if(3==user.type){
			//用户下线删除用户在数据库中信息
			del_sheet(db,user.name);
			//给其他用户发送该客户下线信息
			temp.user=user;
			search(db,user.name,&temp);
			//服务器打印该用户下线
			printf("[%s %d] user:%s offline\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),user.name);
		}
	}
	//5.关闭套接字
	close(sfd);
	return 0;
}

func_ser.c

#include "ser.h"
//服务器发送系统信息线程
void *task(void *arg){
	while(1){
		th_t th=*((th_t*)arg);
		user_t system1;                                 //系统消息结构体变量
		memset(system1.msg,0,sizeof(system1.msg));
		system1.type=4;                                 //发送系统信息状态码为4
		fgets(system1.msg,sizeof(system1.msg),stdin);   //从终端获取发送的消息
		system1.msg[strlen(system1.msg)-1]='\0';

		//调用search传参
		temp_t temp;
		temp.th=th;
		temp.user=system1;

		search(th.db,"",&temp);                                  //调用search函数查找在线的全部用户
	}
}


//创建表
int create_sheet(sqlite3 *db){
	//sql语句,并将用户名设置为主键,重复插入则报错 
	char sql[128]="create table if not exists user (name char primary key,\
				                                    IP char,PORT short);";
	//errmsg
	char *errmsg=NULL;
	//使用sqlite3_exec函数调用sqlite3语句创建表格
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
		fprintf(stderr,"__%d__%s\n",__LINE__,errmsg);
		return -1;
	}
	return 0;
}

//在表中插入数据
int insert_sheet(sqlite3 *db,char *name,struct sockaddr_in cin){
	//sql语句
	char sql[128]="";
	//把格式串转换成字符串,数据库插入语句
	sprintf(sql,"insert into user values (\"%s\",\"%s\",%d)",name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
	char *errmsg=NULL;
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
		fprintf(stderr,"__%d__%s\n",__LINE__,errmsg);
		return -1;
	}
	return 0;
}

//删除表中的数据
int del_sheet(sqlite3 *db,char *name){
	//sql语句
	char sql[128]="";
	//将格式串转化为字符串,数据库删除语句
	sprintf(sql,"delete from user where name=\"%s\";",name);
	char *errmsg;
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
		fprintf(stderr,"__%d__%s\n",__LINE__,errmsg);
		return -1;
	}
	return 0;
}
//删除表
int del_sheet_a(sqlite3 *db){
	//将格式串转化为字符串,数据库删除
	char sql[128]="delete from user";
	char *errmsg;
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
		fprintf(stderr,"__%d__%s",__LINE__,errmsg);
		return -1;
	}
}
//查找表中的名字不为name的成员
int search(sqlite3 *db,char *name,void *arg){

	//给回调函数传参
	temp_t temp=*(temp_t *)arg;

	char sql[128]="";
	//数据库查找语句
	sprintf(sql,"select * from user where name != \"%s\";",name);
//  错误信息
	char *errmsg;
	if(sqlite3_exec(db,sql,select_callback,&temp,&errmsg)!=SQLITE_OK){
		fprintf(stderr,"__%d__%s\n",__LINE__,errmsg);
		return -1;
	}

}

//search回调函数(sfd,user)
int select_callback(void *arg,int columns,char **column_text,char **colum_name){
	
//	printf("columns=%d\n",columns);
	//存放从数据库中查找出的ip和端口号的临时变量
	temp_t temp=*((temp_t *)arg);
	
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);
	//将查找出的数据填充
	cin.sin_family=AF_INET;
	cin.sin_port=htons(atoi(*(column_text+2)));
	cin.sin_addr.s_addr=inet_addr(*(column_text+1));

//	printf("port=%#x\n",cin.sin_port);
//	printf("port=%#x\n",cin.sin_addr.s_addr);

//	printf("column_text=%s colum_text=%s\n",*(column_text+1),*(column_text+2));

	if(sendto(temp.th.sfd,&(temp.user),sizeof(temp.user),0,(struct sockaddr*)&cin,addrlen)<0){
		ERR_MSG("sendto");
		return -1;
	}
	return 0;
}

makefile 

EXE=char_ser
OBJECTS=$(patsubst %.c,%.o,$(wildcard *.c))
CC=gcc
CFLAGS+=-c
CFLAGS+=-o

all:$(EXE)

$(EXE):$(OBJECTS)
	$(CC)  $^ -pthread -lsqlite3 -o $@

%.o:%.c
	$(CC)  $(CFLAGS)  $@  $^

clean:
	rm $(OBJECTS)  $(EXE)

客户端

cli.h

#ifndef __CLI_H__
#define __CLI_H__

#include <myhead.h>
//UDP实现网络聊天室
//UDP客户端
#define IP "192.168.125.13"    //服务器IP地址
#define PORT 6666              //服务器端口号

#define ERR_MSG(msg) do{fprintf(stderr,"__%d__",__LINE__);\
						perror(msg);\
						}while(0)
typedef struct
{
	int  type;                 //用户状态:定义1为登录、2为聊天,3为客户端下线,4为系统消息
	char name[128];            //用户名
	char msg[128];             //消息
}user_t;

//线程传参
typedef struct
{
	int cfd;
	struct sockaddr_in serin;
	socklen_t addrlen;
	user_t user;
}temp_t;

void *task(void *arg);         //读线程


#endif

main.c

#include "cli.h"

int main(int argc, const char *argv[])
{
	int cfd;                       //客户端套接字文件描述符
	//1.打开套接字
	cfd=socket(AF_INET,SOCK_DGRAM,0);
	if(cfd<0){
		ERR_MSG("socket");
		return -1;
	}
	//2.绑定非必须
	//
	struct sockaddr_in serin;      //服务器地址信息结构体
	//填充服务器结构体
	serin.sin_family=AF_INET;              
	serin.sin_port=htons(PORT);
	serin.sin_addr.s_addr=inet_addr(IP);
	socklen_t addrlen=sizeof(serin);

	//线程传参
	temp_t temp;
	temp.cfd=cfd;
	temp.serin=serin;
	temp.addrlen=addrlen;
	
	//用户登录
	//给服务器发送用户名,知道输入的用户名不与数据库中重名
	int res;
	user_t user;                   //消息结构体变量 
	do{
		//从终端获取用户名
		printf("\033[1;33;10m请输入用户名\033[0m>>");
		memset(user.name,0,sizeof(user.name));
		fgets(user.name,sizeof(user.name),stdin);
		user.name[strlen(user.name)-1]='\0';
		user.type=1;                     //设置为登录状态
		//给服务器传用户名
		if(sendto(cfd,&user,sizeof(user),0,(struct sockaddr*)&serin,sizeof(serin))<0){
			ERR_MSG("sendto");
			return -1;
		}
		//接收服务查询结果
		recvfrom(cfd,&res,sizeof(res),0,(struct sockaddr*)&serin,&addrlen);
		if(res!=0){
			printf("\033[10;31;10m用户名重复\n\033[0m");
		}
	}while(res);

	temp.user=user;
	//创建分支线程运行接收数据
	pthread_t tid;
	if(pthread_create(&tid,NULL,task,&temp)!=0){
		fprintf(stderr,"pthread_create error\n");
		return -1;
	}
	//登录成功设置为聊天状态
	user.type=2;

	//3发送
	while(1){
		bzero(user.msg,sizeof(user.msg));
		//从终端输入要发送的消息
		printf("\033[1;32;10m%s:\033[0m",user.name);
		fgets(user.msg,sizeof(user.msg),stdin);
		user.msg[strlen(user.msg)-1]='\0';
		//给服务器发送数据,如果为quit,设定为下线状态
		if(0==strcmp(user.msg,"quit")){
			user.type=3;
		}
		//给服务器发送信息
		sendto(cfd,&user,sizeof(user),0,(struct sockaddr*)&serin,sizeof(serin));
		//如果为下线状态则退出客户端
		if(3==user.type){
			close(cfd);
			exit(EXIT_SUCCESS);
		}
	}
	pthread_join(tid,NULL);
	return 0;
}

func_cli.c

#include "cli.h"

//读取数据
void *task(void *arg){
	//主线程传参
	temp_t temp=*((temp_t*)arg);

	//接收服务器信息临时变量
	user_t user1;
	while(1){
		memset(&user1,0,sizeof(user1));
		//接收服务器信息
		recvfrom(temp.cfd,&user1,sizeof(user1),0,(struct sockaddr*)&(temp.serin),&(temp.addrlen));
		if(1==user1.type){
			//用户登录接收用户登录信息
			printf("\033[128D             \033[1;33;10muser:%s online\n\033[0m",user1.name);
			//		printf("请输入>>");
		}
		else if(2==user1.type){
			//用户聊天接收聊天信息
			printf("\033[128D             \033[1;33;10m%s:%s\n\033[0m",user1.name,user1.msg);
		}
		else if(3==user1.type){
			//用户下线信息
			printf("\033[128D             \033[1;33;10muesr:%s offline\n\033[0m",user1.name);
		}
		else if(4==user1.type){
			//系统信息
			printf("\033[128D      \033[1;31;10mSYSTEM:%s\n\033[0m",user1.msg);

		}
		//读取完后刷新出最后一行用户名
		printf("\033[1;32;10m%s:\033[0m",temp.user.name);
		fflush(stdout);
	}
}

makfile

EXE=char_cli
OBJECTS=$(patsubst %.c,%.o,$(wildcard *.c))
CC=gcc
CFLAGS+=-c
CFLAGS+=-o

all:$(EXE)

$(EXE):$(OBJECTS)
	$(CC)  $^ -pthread -o $@

%.o:%.c
	$(CC)  $(CFLAGS)  $@  $^

clean:
	rm $(OBJECTS)  $(EXE)

 

 思维导图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Create AI大会|人人皆可成为开发者,探索人工智能新趋势

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度渗透到我们生活的方方面面。2024年4月16日&#xff0c;备受瞩目的Create 2024百度AI开发者大会在深圳国际会展中心&#xff08;宝安&#xff09;盛大开幕。大会以“创造未来”为主题…

47.基于SpringBoot + Vue实现的前后端分离-校园外卖服务系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的校园外卖服务系统设计与实现管理工作…

人才测评的方法有哪些?

人才测评是企业在筛选人才的时候必然会使用的策略&#xff0c;为了节省企业HR在招聘时的成本&#xff0c;又极大提高了人才和岗位的匹配度&#xff0c;从企业发展和员工个人发展来看&#xff0c;起到了双赢的作用&#xff0c;在线人才测评是现代企业招聘&#xff0c;人才选拔&a…

力扣哈哈哈哈

public class MyStack {int top;Queue<Integer> q1;Queue<Integer> q2;public MyStack() {q1new LinkedList<Integer>();q2new LinkedList<Integer>();}public void push(int x) {q2.offer(x);//offer是入队方法while (!q1.isEmpty()){q2.offer(q1.pol…

如何通过Postgres的日志进行故障排查?

文章目录 一、配置日志记录二、查看和分析日志三、使用日志进行故障排查的示例四、总结 在进行数据库管理和维护时&#xff0c;日志分析是一项至关重要的技能。PostgreSQL的日志记录功能可以帮助我们追踪数据库的运行状态&#xff0c;定位问题&#xff0c;以及优化性能。下面&a…

51单片机入门_江协科技_33~34_OB记录的自学笔记_LED呼吸灯与PWM直流马达调速

33. 直流电机驱动(PWM) 33.1. 直流电机介绍 •直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 •直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&…

如何规划数据中台

1. 数据中台是一套解决方案 数据中台是一套可持续“让企业数据用起来”的机制&#xff0c;是一套解决方案&#xff0c;不仅是一个平台。让数据更加灵活地支撑前端业务&#xff0c;通过持续沉淀企业数据复用能力形成数据从采集、治理、开发到数据服务的一整套数据使用的机制。 …

SpringBoot 监控 SQL 运行情况(实战教程)

1 基本概念 2 添加依赖 3 配置相关属性 4 sql监控 5 慢sql记录 6 spring 监控 7 去 Ad&#xff08;广告&#xff09; 8 获取 Druid 的监控数据 1 基本概念 Druid是Java语言中最好的数据库连接池。 虽然HikariCP的速度稍快&#xff0c;但是&#xff0c;Druid能够提供强…

【考研高数】学习笔记分享

派大星说数学&#xff08;导学部分&#xff09; 关于做题 测试 答疑阶段 直播 群内 高中基础知识导学 一、数与式 述了课程学习和因式分解、分式拆解等知识点。学生应了解课程内容&#xff0c;带着疑问听课&#xff0c;不要抄笔记&#xff0c;导学课和基础课都有测验&…

mac安装nvm详细教程

0. 前提 清除电脑上原有的node (没有装过的可以忽略)1、首先查看电脑上是否安装的有node,查看node版本node -v2、如果有node就彻底删除nodesudo rm -rf /usr/local/{bin/{node,npm},lib/node_modules/npm,lib/node,share/man/*/node.*}2、保证自己的电脑上有安装git,不然下载n…

鼠标悬停显示三个下拉列表按钮

鼠标悬停显示三个下拉列表按钮 代码部分&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width,initial-scale1,minimum-scale1,maximum-scale1,user-scala…

京东AI数字人“采销东哥”首秀观看量破2000万;天工 SkyMusic 音乐大模型开放公测

&#x1f989; AI新闻 &#x1f680; 京东AI数字人“采销东哥”首秀观看量破2000万 摘要&#xff1a;京东AI数字人“采销东哥”由京东云言犀打造&#xff0c;在其直播首秀中亮相并迅速吸引超2000万观看量。尽管“采销东哥”的外形和口音与创始人刘强东相似&#xff0c;但其直…

SSL Pinning之双向认证

双向认证处理流程 概述获取证书逆向app 获取证书的KeyStore的 key通过jadx 反编译 app 获取证书&#xff1a;frida hook 证书转换命令行转换portecle 工具使用 charles 配置 p12 格式证书 概述 本篇只介绍怎么解决ssl pinning&#xff0c; 不讲ssl/tls 原理。 为了解决ssl pinn…

运动想象 (MI) 分类学习系列 (8) :IFNet

运动想象分类学习系列:IFNet 0. 引言1. 主要贡献2. 提出的方法2.1 交互式频率卷积神经网络2.1.1 光谱空间特征表示2.1.2 跨频交互2.1.3 分类&#xff08;一个池化分类层&#xff09; 2.2 重复试验增强 3. 实验3.1 基线比较3.2 消融实验3.2.1 数据增强消融3.2.2 条带分割消融3.2…

✅技术社区--布隆过滤器在项目中怎么用的?不用可以吗?

使用 布隆过滤器 一般就是用于快速判断某个元素是否在集合中出现了&#xff0c;可以用于解决 缓存穿透 的问题&#xff0c;布隆过滤器提供 一组哈希函数 h1, h2, ..., hk &#xff0c;对需要存储的数据使用哈希函数计算得到 k 个哈希值&#xff0c;将 BitMap 中这 k 个位置都设…

面试stm32基础知识

1.ISP 第一步进入bootloader模式&#xff1a;先置BOOT0为高&#xff0c;BOOT1为低&#xff0c;再复位单片机进入bootloader模式&#xff0c;之后通过上位机下载程序&#xff1b; 第二步配置启动代码的地方&#xff1a;代码下载完毕后&#xff0c;置BOOT0为低&#xff0c;BOOT1…

中兴F7607P自启动程序,关闭JAVA插件

本文目的&#xff1a;关闭光猫内自动运行的JAVA插件&#xff0c;并实现开机自动调用用户的程序启动 移动定制版F7607P不带LXC容器&#xff0c;取而代之的是JAVA虚拟机&#xff0c;内置多个插件&#xff0c;包括名为CMCCDPI的插件&#xff0c;用途可以从名字上窥见。机器rootfs分…

Windows系统下查看C语言文件反汇编

一、配置编译器环境变量 1.下载mingw64 MinGW 的全称是&#xff1a;Minimalist GNU on Windows &#xff0c;MinGW 就是 GCC 的 Windows 版本 。 MinGW-w64 与 MinGW 的区别在于 MinGW 只能编译生成32位可执行程序&#xff0c;而 MinGW-w64 则可以编译生成 64位 或 32位 可执行…

FinalShell 远程连接 Linux(Ubuntu)系统

Linux 系列教程&#xff1a; VMware 安装配置 Ubuntu&#xff08;最新版、超详细&#xff09;FinalShell 远程连接 Linux&#xff08;Ubuntu&#xff09;系统Ubuntu 系统安装 VS Code 并配置 C 环境 ➡️➡️➡️提出一个问题&#xff1a;为什么使用 FinalShell 连接&#xff0…

字符串拆分优化算法

字符串拆分优化算法 问题背景算法设计思路伪代码实现C语言代码实现 详细解释结论 在面对字符串拆分问题时&#xff0c;我们的目标是找到一种最优的拆分顺序&#xff0c;以使得总的拆分代价最小。这个问题可以通过动态规划算法来解决。在本文中&#xff0c;我们将详细介绍这个问…