从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3

2023-11-13

上一篇我们已经讲了如何搭建一个多线程的服务器模型,可以支持多个客户端同时连接服务器,本篇我们来实现多个客户端,如何实现向服务器注册信息,并实现登录的功能。

想了解更多Linux 编程知识,请关注 公众号【一口Linux】

数据结构

接着上一篇的实例代码继续增加功能。
要实现注册和登录功能,那么我们就必须要让服务器和客户端在交互数据包的时候按照统一的格式收发信令。
信令格式

//C/S通信的结构体
struct protocol{
	int cmd;     //命令
	int state;  //存储命令返回信息
	char name[32]; //用户名
	char data[64]; //数据
};

命令类型:
信令格式中命令定义如下:

/*cmd*/
#define BROADCAST 0X00000001   //广播数据
#define PRIVATE 0X00000002     //私聊
#define REGISTE 0X00000004     //注册账号
#define LOGIN 0X00000008       //登录
#define ONLINEUSER     0X00000010 //显示在线用户
#define LOGOUT     0X00000020    //退出

在线用户信息
服务器需要维护所有用户信息,需要知道用户是否在线,是否注册。

//在线用户 
struct ONLINE{
	int fd;  //-1:该用户下线   >0:该用户已经登录,对应的套接字
	int flage; //-1 该条目没有用户信息  1:该条目有用户注册信息
	char name[32]; //注册的用户名字
	char passwd[32];  //用户名密码
}; 
struct ONLINE online[MAX_USER_NUM];

注册的客户端信息需要存储在服务器,为了简单起见,我们暂时不用数据库存储,只定义一个全局的数组保存客户端信息,并且规定只允许64个客户端登录。

服务器处理结果返回值

/*return code*/
#define OP_OK    0X80000000         //操作成功
#define ONLINEUSER_OK    0X80000001  //显示在线用户,未结束
#define ONLINEUSER_OVER  0X80000002  //显示在线用户,已经发送完毕
#define NAME_EXIST 0X80000003       //注册信息,用户名已经存在
#define NAME_PWD_NMATCH 0X80000004 //登录时,输入的用户名密码不对
#define USER_LOGED 0X80000005     //登录时,提示该用户已经在线
#define USER_NOT_REGIST 0X80000006  //登录时,提示用户没有注册

功能流程图

现在我们根据功能,首先画一个流程图。

注册

在这里插入图片描述由上图所示:

  1. 服务器要先启动,监听客户端的连接;
  2. 客户端启动,首先连接服务器,并显示登陆、注册界面;
  3. 服务器接收到客户端连接后,会创建一个子线程专门用于于客户端的通信;
  4. 选择注册后,提示输入用户名、密码,封装注册信息到结构体变量msg中,并发送该信令给服务器;
  5. 服务器接收到客户端注册信息后,进入注册处理流程;
  6. 注册功能:首先查找该用户名是否存在,数组online[]中注册的位置,flage值为1,否则为-1;
    如果该用户名已经注册,则返回NAME_EXIST 错误信息;
    如果该用户名没有被注册,则找一个空闲位置,将该用户名密码保存到数据库online[]中,并返回注册成功的信令;
  7. 客户端接收到服务器注册处理指令后,会打印提示信息,并显示步骤2的菜单。

登录

在这里插入图片描述

  1. 服务器要先启动,监听客户端的连接;
  2. 客户端启动,首先连接服务器,并显示登陆、注册界面;
  3. 服务器接收到客户端连接后,会创建一个子线程专门用于于客户端的通信;
  4. 选择登陆后,提示输入用户名、密码,封装登陆信息到结构体变量msg中,并发送该信令给服务器;
  5. 服务器接收到客户端注册信息后,进入登陆处理流程;
  6. 登陆功能:首先查找该用户名、密码是否在数组online[]中存在匹配项,找到返回对应的下标,并将于该客户端相连接的套接字保存到对应的条目中,返回登陆成功信息给客户端;
    如果没有找到,则返回-1,并返回0X80000004错误信息给客户端;
  7. 客户端接收到服务器注册处理指令后,会打印提示信息,并设置客户端在线的标记login_f 为1,此时会显示 聊天功能对应的菜单。

代码

chat.h

#ifndef _TCP_CHAT
#define _TCP_CHAT

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
 #include <string.h>
 
#define SERVER_PORT 8888
//在线用户 
struct ONLINE{
	int fd;  //-1   
	int flage; //registed or not
	char name[32];
	char passwd[32];
}; 
#define MAX_USER_NUM 64

//C/S通信的结构体
struct protocol{
	int cmd;
	int state;
	char name[32];
	char data[64];
};
 /*cmd*/
#define BROADCAST 0X00000001
#define PRIVATE 0X00000002
#define REGISTE 0X00000004
#define LOGIN 0X00000008
#define ONLINEUSER     0X00000010
#define LOGOUT     0X00000020

/*return code*/
#define OP_OK    0X80000000
#define ONLINEUSER_OK    0X80000001
#define ONLINEUSER_OVER  0X80000002
#define NAME_EXIST 0X80000003
#define NAME_PWD_NMATCH 0X80000004
#define USER_LOGED 0X80000005
#define USER_NOT_REGIST 0X80000006
#endif

client.c

/*********************************************
           公众号:一口Linux
*********************************************/
#include "chat.h"

int sockfd;
int addrlen;
struct sockaddr_in   server_addr; 

pthread_t pid;

int login_f =  -1;
	
void *func(void *arg)
{
	int len;
	char buf[64]={0};
	
	while(1)
	{
		if(login_f != 1)
		{
			continue;
		}	
	
		len = read(sockfd,buf,sizeof(buf));
		if(len<=0)
		{
			close(sockfd);
			return;
		}
		buf[len]='\0';
		
		printf("%s\n",buf);		
	}	
}
void broadcast(int fd)
{

}
void private(int fd)
{

}
void list_online_user(sockfd)
{

}
int  registe(int fd)
{
	struct protocol msg,msgback;

	msg.cmd = REGISTE;	
	printf("input your name\n");	
	scanf("%s",msg.name);
	printf("input your passwd\n");	
	scanf("%s",msg.data);

	write(sockfd,&msg,sizeof(msg));
	read(sockfd,&msgback,sizeof(msgback));
	if(msgback.state != OP_OK)
	{
		printf("Name had exist,try again!\n");	
		getchar();
		getchar();
		return -1;
	}else{
		printf("Regist success!\n");
		getchar();
		getchar();
		return 0  ;
	}
}
int login(int fd)
{
	struct protocol msg,msgback;

	msg.cmd = LOGIN;	
	printf("input your name\n");	
	scanf("%s",msg.name);
	printf("input your passwd\n");	
	scanf("%s",msg.data);

	write(sockfd,&msg,sizeof(msg));
	read(sockfd,&msgback,sizeof(msgback));
	if(msgback.state != OP_OK)
	{
		printf("Name had exist,try again!\n");
		getchar();
		getchar();
		login_f = -1;
		return NAME_PWD_NMATCH;
	}else{
		printf("Login success!\n");
		getchar();
		getchar();
		login_f = 1;
		return OP_OK  ;
	}
}
int logout(int fd)
{
	close(fd);
	login_f = -1;
}
int main(int argc, char **argv)
{
	int    sel;
	int ret; 
	int min_sel,max_sel;
	int portnumber;
	
	struct protocol msg;
	
	
	if(argc<3)
	{
		printf("cmd: %s ip portnumber\n",argv[0]);
		return;
	}
	//argv2 存放的是端口号 ,读取该端口,转换成整型变量
	if((portnumber=atoi(argv[2]))<0)
	{
		fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);
		exit(1);
	}
	sockfd = socket(PF_INET,SOCK_STREAM,0);	
	if(sockfd<0)
	{
		perror("socket() fail\n");
		return;
	}
	
	server_addr.sin_family =  PF_INET;	
	server_addr.sin_port   =  htons(portnumber);
	server_addr.sin_addr.s_addr   =  inet_addr(argv[1]);
	
	addrlen = sizeof(struct sockaddr_in);
	
	connect(sockfd,(struct sockaddr* )&server_addr,addrlen);
	pthread_create(&pid, NULL,func, NULL);		
	while(1)
	{
		//getchar();
		system("clear");
		if(login_f == -1){
			printf("\t 1 注册\n");
			printf("\t 2 登录\n");
		}else if(login_f == 1){
			printf("\t 3 公聊\n");
			printf("\t 4 私聊\n");
			printf("\t 5 在线列表\n");						
		}	
		printf("\t 0 退出\n");
		
		
		fflush(stdin);
		scanf("%d",&sel);
		if(sel == 0)
		{
			break;
		}
		if(login_f == 1)
		{
			min_sel = 3;
			max_sel = 5;
		}else if(login_f == -1){
			min_sel = 1;
			max_sel = 2;
		}
		
		if(sel<min_sel || sel > max_sel)
		{
			printf("Valid choice ,try again\n");
			continue;
		}
		switch(sel)
		{
			case 1:
				registe(sockfd);
				break;
			case 2:
				ret = login(sockfd);
				break;
			case 3:
				broadcast(sockfd);
				break;
			case 4:
				private(sockfd);
				break;
			case 5:
				list_online_user(sockfd);	
			case 0:
				logout(sockfd);
				break;
			default:
				break;
		}
		if(sel == 0)
		{
			exit(0);
		}
	}
}

server.c

/*********************************************
           公众号:一口Linux
*********************************************/
#include "chat.h"

struct ONLINE online[MAX_USER_NUM];


void del_user_online(int index)
{
	int i;
	char buf[128]={0};

	if(index <0)
	{
		return;
	}
	online[index].fd = -1;
	sprintf(buf,"%s offline\n",online[index].name);
	//通知所有客户端,某个用户下线了
	for(i=0;i<MAX_USER_NUM;i++)
	{
		if(online[i].fd == -1)
		{
			continue;
		}
		write(online[i].fd,buf,strlen(buf));	
	}	
	
	
	return;
}
int add_user(int sockfd,struct protocol*msg)
{
	int i,index = -1;
	char buf[128]={0};
	
	for(i=0;i<64;i++)//添加到在线用户列表
	{
		if(online[i].flage == -1)
		{
			online[i].flage= 1;
			strcpy(online[i].name,msg->name);
			strcpy(online[i].passwd,msg->data);
			printf("regist %s to %d \n",msg->name,i);
			index = i;
			return index;
		}		
	}
	return index;
}
void broadcast(int index,struct protocol*msg)
{

}
int find_dest_user_online(int sockfd,int *index,struct protocol*msg)
{
	int i;
	
	for(i=0;i<MAX_USER_NUM;i++)
	{
	//this pos not use
		if(online[i].flage== -1)
		{
			continue;			
		}
		
		if((strcmp(msg->name,online[i].name)==0)&&(strcmp(msg->data,online[i].passwd)==0))
		{
			if(online[i].fd == -1)
			{
				online[i].fd = sockfd;
				*index = i ;
				return OP_OK;
			}else{
				//user had loged
				printf("%s had login\n",online[i].name);
				return USER_LOGED;
			}
					
		}
	}
	return NAME_PWD_NMATCH;
}
int find_dest_user(char *name)
{
	int i;
	
	for(i=0;i<MAX_USER_NUM;i++)
	{
	
		if(online[i].flage == -1)
		{
			continue;			
		}
		
		if(strcmp(name,online[i].name)==0)
		{
			return i;			
		}
	}
	return -1;
}

void private(int index,struct protocol*msg)
{

}
void list_online_user(int index)
{

}

void registe(int sockfd,int *index,struct protocol*msg)
{
	int dest_index;
	char buf[128];
	struct protocol msg_back;

	msg_back.cmd = REGISTE;	
	//找到那个人
	dest_index = find_dest_user(msg->name);

	if(dest_index == -1)
	{	// this user can registe
		*index = add_user(sockfd,msg);
		
		online[*index].flage = 1;
		msg_back.state = OP_OK;
		
		printf("user %s regist success!\n",msg->name);
		write(sockfd,&msg_back,sizeof(msg_back));
		
		return;
	}else{
		msg_back.state = NAME_EXIST;
		printf("user %s exist!\n",msg->name);

		write(sockfd,&msg_back,sizeof(msg_back));
		return;
	}	
}
void login(int sockfd,int *index,struct protocol*msg)
{
	int i;
	int ret;
	char buf[128];
	struct protocol msg_back;

	msg_back.cmd = LOGIN;	
	
	//找到那个人
	ret = find_dest_user_online(sockfd,index,msg);
	
	if(ret != OP_OK)
	{
		msg_back.state = ret;
		strcpy(buf,"there is no this user\n");
		printf("user %s login fail!\n",msg->name);
		
		write(sockfd,&msg_back,sizeof(msg_back));
		return;
	}else{
		msg_back.state = OP_OK;
		strcpy(msg_back.data,"login success\n");
		printf("user %s login success!index =%d \n",msg->name,*index);
		write(online[*index].fd,&msg_back,sizeof(msg_back));
	}
	//通知所有客户端,某个用户上线了
	sprintf(buf,"%s online\n",online[*index].name);
	
	for(i=0;i<MAX_USER_NUM;i++)
	{
		if(online[i].fd != -1)
		{
			write(online[i].fd,buf,strlen(buf));
		}			
	}
	
}
void *func(void *arg)
{
	int sockfd = *((int*)arg);
	char buf[64];
	int len;
	int index = -1;//该用户在在线用户列表的下标
	struct protocol msg;
	
	free(arg);	

	//进入聊天了
	while(1)
	{
		len = read(sockfd,&msg,sizeof(msg));
		if(len<=0)
		{//下线
			printf("%s offline\n",online[index].name);
			//从在线列表中删除
			del_user_online(index);
			close(sockfd);
			return;
		}
		
		switch(msg.cmd)
		{
			case REGISTE:
				registe(sockfd,&index,&msg);
				break;
			case LOGIN:
				login(sockfd,&index,&msg);
				break;
			case BROADCAST:
				broadcast(index,&msg);
				break;
			case PRIVATE:
				private(index,&msg);
				break;
			case ONLINEUSER:
				list_online_user(index);
				break;
			default:
				break;
		}
		
	}	
}

int main(int argc, char **argv)
{
	int lsfd,newfd;
	int addrLen,cliaddrlen;
	struct sockaddr_in   my_addr; 
	struct sockaddr_in   cli_adr;	
	char buf[64]="xuezhiqian fuhele\n";
	pthread_t pid;
	int *arg;
	int i;
	int portnumber;
	
	if(argc<2)
	{
		printf("cmd: %s  portnumber\n",argv[0]);
		return;
	}
/*¶˿ںŲ»¶ԣ¬͋³ö*/
	if((portnumber=atoi(argv[1]))<0)
	{
		fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
		exit(1);
	}	
	lsfd = socket(PF_INET,SOCK_STREAM,0);	
	if(lsfd<0)
	{
		perror("socket() fail\n");
		return;
	}
	bzero(&my_addr,sizeof(struct sockaddr_in));
	my_addr.sin_family =  PF_INET;	
	my_addr.sin_port   =  htons(portnumber);
	my_addr.sin_addr.s_addr   =  htonl(INADDR_ANY);
	addrLen = sizeof(struct sockaddr_in);
	
	if(bind(lsfd,(struct sockaddr* )&my_addr ,addrLen)<0)
	{
		perror("bind() fail\n");
		return;		
	}
	
	listen(lsfd,5);
	cliaddrlen = sizeof(struct sockaddr_in);
	
	for(i=0;i<64;i++)
	{
		online[i].fd = -1;
		online[i].flage= -1;
	}
	while(1)
	{
		newfd = accept(lsfd,(struct sockaddr *)&cli_adr,&cliaddrlen);
		printf("client:ip:%s   port:%d  \n",
			inet_ntoa(cli_adr.sin_addr),cli_adr.sin_port);
				
		arg = malloc(sizeof(int));
		*arg = newfd;//必须搞清楚为什么要申请内存
		
        	pthread_create(&pid,NULL,func, (void*)arg);	
	}
	close(newfd);
	close(lsfd);
}

截图

客户端1注册

用户名:yikoulinux
密 码: qqqq
客户端log
在这里插入图片描述服务器log
在这里插入图片描述

客户端2注册

用户名:yikoupeng
密 码: qqqq
服务器/客户端log在这里插入图片描述

客户端1登录

登录log

在这里插入图片描述按下回车,客户端会隐藏登录、注册的菜单,并显示公聊、私聊、在线列表的菜单。如下图所示:

在这里插入图片描述

客户端2登录

登录log

在这里插入图片描述
备注:

  1. 本篇只介绍登陆注册功能的实现;
  2. 因为本文只讨论功能的实现,对于很多异常出错的操作并没有全部完善;
  3. 在线用户的信息应该保存到数据库中【比如sqlite】,本篇为了便于读者理解,暂时用数组替代;
  4. 注册登录没有实现密码的二次校验和隐式输入。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3 的相关文章

  • Scrapy FakeUserAgentError:获取浏览器时发生错误

    我使用 Scrapy FakeUserAgent 并在我的 Linux 服务器上不断收到此错误 Traceback most recent call last File usr local lib64 python2 7 site pack
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • 将数组传递给函数名称冲突

    Specs GNU bash 版本 3 1 17 无法升级 Premise 我一直在摆弄数组 我想知道是否有任何方法可以让函数的本地变量与所述函数外部的数组同名 Example 在下面的示例中 我将尝试显示该问题 Working bin b
  • 怎样才能使 Windows 成为一个开箱即用的 POSIX 兼容操作系统?

    这个问题的动机是我的一个牵强的梦想 即 nix 平台上可用的许多优秀软件可以轻松移植到 Windows 微软最近对开源和开放性采取了不同的方法 所以我真的很想知道如果微软有这样的倾向 这样的事情会有多可行 我很好奇的一些更具体的事情是 是否
  • gethostbyname() 或 getnameinfo() 如何在后台工作?

    How gethostbyname or getnameinfo 在后台工作 include
  • 构建 makefile 依赖/继承树

    如果我解释得不好或者问了一些明显的问题 我很抱歉 但我是 Linux 内核的新手 而且有点深入 我们有一个嵌入式 Linux 系统 它附带一个 文档非常糟糕的 SDK 其中包含数百个文件夹stuff 大多数文件夹包含rules make m
  • 为什么在 Linux 上字符串文字的内存地址与其他字符串文字的内存地址如此不同?

    我注意到字符串文字在内存中的地址与其他常量和变量 Linux 操作系统 非常不同 它们有许多前导零 未打印 Example const char h Hi int i 1 printf p n void h printf p n void
  • Inotify linux 监视子目录

    是否可以以这种模式监视目录 storage data usernames Download gt storage data Download 我需要监视每个用户的下载文件夹中是否进行了更改 也许我需要创建所有路径的列表 将其放入数组中 并在
  • 在Linux中断上下文中运行用户线程

    我正在编写一些定制的应用程序 并允许更改 Linux 内核中的中断处理程序代码 我有一个用户线程正在等待中断发生 如果发生中断 那么我要做的第一件事就是执行该用户线程 有什么办法让它发挥作用吗 Thanks 创建一个字符设备 这就是内核所做
  • C 程序从连接到系统的 USB 设备读取数据

    我正在尝试从连接到系统 USB 端口的 USB 设备 例如随身碟 获取数据 在这里 我可以打开设备文件并读取一些随机原始数据 但我想获取像 minicom teraterm 这样的数据 请让我知道我可以使用哪些方法和库来成功完成此操作以及如
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst
  • Linux shell 脚本中的 while 循环超时

    这工作正常 无限循环 while TRUE do printf done 我在尝试着timeout this while loop与timeout命令 所有这些都不起作用 timeout 5 while TRUE do printf don
  • 没有可用的符号表信息

    我正在测试第三方的库 它崩溃了 当我想查看崩溃的原因时 我的 gdb 告诉我没有可用的调试符号 Program received signal SIGSEGV Segmentation fault Switching to Thread 0
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • diff 文件仅比较每行的前 n 个字符

    我有2个文件 我们将它们称为 md5s1 txt 和 md5s2 txt 两者都包含a的输出 find type f print0 xargs 0 md5sum sort gt md5s txt 不同目录下的命令 许多文件被重命名 但内容保
  • 如何更改 Ubuntu 14.04 上的 php-cli 版本?

    我是 Linux 新手 在篡改时破坏了一些 php 设置 如果我执行一个包含以下内容的 php 脚本 phpinfo 它显示 php 版本为 5 6 但通过命令行 如果我运行php v它返回 7 0 版本 我想让两个版本匹配 我怎样才能修复
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte
  • Godaddy 托管上的 CakePHP 控制台

    我一直在努力让我的 CakePHP 网站在 Godaddy 网格托管 帐户上运行 我的蛋糕应用程序设置是从帐户的子目录托管的 并且可以通过子域访问 我必须调整我的 htaccess 文件才能使其正常工作 现在我需要让 CakePHP 控制台
  • 在Linux上编译C# + WPF以便在Windows上运行

    我有一个 C 应用程序 其中某些部分是使用 WPF 编写的 Mono 不支持 可以在 Linux 上编译这个应用程序吗 最终 该应用程序将在 Windows 上运行 但它是更大框架的一部分 并且我们的整个构建过程在 Linux 上运行 因此

随机推荐

  • ubuntu安装NERDTree,Taglist和WinManager

    在ubuntu中要用vim进行开发的话 这三个插件组合在一起 给你一种顺滑的感受 NERDTree NERDTree的安装 nerdtree可以显示当前项目的文件结构 安装方法如下 执行以下命令即可 1 创建文件夹 mkdir vim 如果
  • 线性代数的本质(五)——矩阵的运算

    文章目录 矩阵的运算 矩阵的转置 方阵的运算 初等矩阵 分块矩阵 逆矩阵 矩阵的秩 广义逆矩阵 矩阵的运算 矩阵的转置 转置 矩阵 A A A的行列互换得到的矩阵称为 A A A 的转置 transpose 记作
  • 【满分】【华为OD机试真题2023B卷 JAVA&JS】最佳植树距离

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 最佳植树距离 知识点二分查找 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 按照环保公司要求 小明需要在沙化严重的地区进行植树防沙工作 初步目标是种植一条直线的树带
  • git报错:error: RPC failed; curl 18 transfer closed with outstanding read data remaining

    今天和朋友聊天 推荐了个项目给我看看 在克隆的过程中发现太大拉不下来 报错如下 error RPC failed curl 18 transfer closed with outstanding read data remaining 远程
  • 黄金矿工(Java)

    先来一张效果图 图片资源 https pan baidu com s 1weCGFLQlzOTvDRY18bizrg pwd ivjt 提取码 ivjt 该项目一共12个类 均处于同一目录 首先是基类 其余用来表示物体的类都继承它 impo
  • Tensorflow 1.13训练模型.pb文件转换成Tensorflowlite可以使用的.tflite文件过程记录

    Tensorflow 1 13训练模型 pb文件转换成Tensorflowlite可以使用的 tflite文件过程记录 前言 之前一直通过1 13版本的TensorflowGpu训练模型 使用范围局限在电脑端 例如opencv调用模型等等
  • unity游戏开发-socket网络通信

    本篇主要是分享基于unity的客户端socket网络通信方案 关于服务器的c socekt搭建放在了这里 基于C 的Tcp服务端通信 其中关于socekt粘包断包的处理放在这里分享了 C socket粘包断包处理 目录 整体设计 TcpCl
  • Spring Security Oauth2 认证(获取token/刷新token)流程(password模式)

    1 本文介绍的认证流程范围 本文主要对从用户发起获取token的请求 oauth token 到请求结束返回token中间经过的几个关键点进行说明 2 认证会用到的相关请求 注 所有请求均为post请求 获取access token请求 o
  • BUUCTF WEB刷题记录

    第一题 刚打开的页面 看源码 发现source php 访问source php 我们要用file参数带出flag 但是有白名单限制 第一个和第二个判断是对file本身的值进行判断 第三个和第四个是对 前面的file值进行判断 所以我们可以
  • jeecg-boot字典翻译改造(支持实体类详情查询自动翻译)

    找到字典切面类 DictAspect 改造方法 parseDictText 支持自动生成的列表接口 单个实体类查询翻译 代码如下 private void parseDictText Object result if result inst
  • 2023 最新版IntelliJ IDEA 2023.1创建Java Web前(vue3)后端(spring-boot3)分离 项目详细步骤(图文详解)

    文章目录 接上篇 项目构建所需的相关工具 Java IDEA maven NodeJS Vue Visual Studio Code 后端项目创建详细步骤 1 开始创建新项目 2 输入项目名称 选择项目存储位置 项目管理工具 Maven 选
  • Hibernate lazy load.

    HIBERNATE的持久化对象加载策略 延迟加载 也就是用到的时候才去加载 这样可以提高一些性能 Hibernate的lazy loading 采用了一个HibernateSession来管理session 它的逻辑是每进行一次数据库操作
  • unpkg 与 npm 的基本介绍

    目录 定义 特点 原理 使用 npm安装流程 npm install npm update registry 区别 总结 定义 UNPKG是一个基于npm registry 的静态资源 CDN 服务 它可以快速获取和使用任何JavaScri
  • springmvc中操作json,配置FastJson

    目前网络上传递数据大部分都是json和xml 但是xml使用的很少了 这里主要介绍json 一般来说json常用的场景是提供外部接口 请求内使用request域就足够了 springmvc对于json的支持 上图 1 请求json方式分析
  • 搭建AI智能语音外呼系统

    随着人工智能技术的发展 近半年来涌现了大量基于人工智能的呼叫中心业务服务商和集成商 仅电销机器人这一个方向就至少有近百家公司正在推广运营 包括百度 讯飞 智齿 硅基 百应 箭鱼 容联等 商务上的需求非常强烈 整个市场都飞快地热闹起来 一套可
  • Redis优化秒杀系统

    Redis优化秒杀系统 使用背景 普通的基于mss框架的系统在并发量不是很高的情况下 对redis的需求不是很高 redis在系统中的角色相当于一个对象缓存器 在高并发的系统中 比如秒杀系统 在某一刻对数据库中的一条数据可能是成千上万的用户
  • 前端页面生成PDF方案之puppetter

    1 新建一个文件夹 例如 test 2 新建一个js文件 例如test js 3 进入test文件夹 在该目录下运行命令行 并执行下面命令 npm init 4 运行命令安装 npm i puppetter 5 编辑test js cons
  • 常量池、运行时常量池、字符串值基本概念区分

    常量池 Constant Pool 常量池数据编译期被确定 是Class文件中的一部分 存储了类 方法 接口等中的常量 当然也包括字符串常量 字符串池 字符串常量池 String Pool String Constant Pool 是常量池
  • 微信公众平台开发笔记4(关注回复自定义消息)

    基于WXJava开发 最终目的 实现关注回复自定义消息 一条文本 一条图片 点击菜单发送视频或音频 音乐可以发送但是不能正常播放 猜测是填写的地址有问题 音频上传时需要先在接口测试平台多媒体文件上传接口上传缩略图 jpeg 新建WxMess
  • 从0实现基于Linux socket聊天室-实现聊天室的登录、注册功能-3

    上一篇我们已经讲了如何搭建一个多线程的服务器模型 可以支持多个客户端同时连接服务器 本篇我们来实现多个客户端 如何实现向服务器注册信息 并实现登录的功能 想了解更多Linux 编程知识 请关注 公众号 一口Linux 数据结构 接着上一篇的