员工管理系统功能介绍:

1)服务器负责管理所有员工表单(以数据库形式),其他客户端可通过网络连接服务器来查询员工表单。

2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。

3)管理员账号可以查看、修改、添加、删除员工信息,同时具有查询历史记录功能,管理员要负责管理所有的普通用户。

4)普通用户只能查询修改与本人有关的相关信息,其他员工信息不得查看修改。

5)服务器能同时相应多台客户端的请求功能。并发

1 流程图

服务器:

客户端:

2 通信结构体

typedef struct staff_info{

int no; //员工编号

int usertype; //ADMIN 0 USER 1

char name[NAMELEN]; //姓名

char passwd[8]; //密码

int age; // 年龄

char phone[NAMELEN];//电话

char addr[DATALEN]; // 地址

char work[DATALEN]; //职位

char date[DATALEN]; //入职年月

int level; // 等级

double salary ; // 工资

}staff_info_t;

/定义双方通信的结构体信息/

typedef struct {

int msgtype; //请求的消息类型

int usertype; //ADMIN 1 USER 2

char username[NAMELEN]; //姓名

char passwd[8]; //登陆密码

char recvmsg[DATALEN]; //通信的消息

int flags; //标志位

staff_info_t info; //员工信息

}MSG;

3 所需知识点

自动探测

自动换行

【1】TCP通信的编程步骤

1.服务器:

 1)创建套接字

 2)绑定ip和端口号

 3)监听

 4)等待客户端连接

 int main()

 {

//1.创建套接字

int sockfd = socket();

//2.初始化通信结构

struct sockaddr_in addr;

addr.sin_family=AF_INET;

addr.sin_port = port;

addr.sin_addr=addr;

bind(sockfd, &addr);

//3.监听

listen();

//4.连接

while(1)

{

int connfd = accept();

//5.循环数据收发

while(1)

{

recv();

send();

}

}

close(sockfd);

close(connfd);

 }

2.客户端:

 1)创建套接字

 2)连接服务器

 int main()

 {

//1.创建套接字

int sockfd = socket();

//2.初始化通信结构

struct sockaddr_in addr;

addr.sin_family=AF_INET;

addr.sin_port = port;

addr.sin_addr=addr;

//3.连接

connect();

//5.循环数据收发

while(1)

{

send();

recv();

}

 }

【2】服务器模型

1.循环服务器

2.并发服务器

 1)多线程

 2)多进程

 3)IO多路复用:

a. select:

基本思想:

1. 先构造一张有关文件描述符的表(集合、数组); fd_set fd;

2. 将你关心的文件描述符加入到这个表中;FD_SET();

3. 然后调用一个函数。 select / poll

4. 当这些文件描述符中的一个或多个已准备好进行I/O操作的时候

该函数才返回(阻塞)。

5. 判断是哪一个或哪些文件描述符产生了事件(IO操作);

6. 做对应的逻辑处理;

****select函数返回之后,会自动将除了产生事件的文件描述符以外的位全部清空;

程序步骤:

1.把关心的文件描述符放入集合--FD_SET

2.监听集合中的文件描述符--select

3.依次判断哪个文件描述符有数据--FD_ISSET

4.依次处理有数据的文件描述符的数据

伪代码:

fd_set fd;

FD_SET(sockfd);

while(1) {

设置监听读写文件描述符集合(FD_*);

调用select;

select();

如果是监听套接字就绪,说明有新的连接请求

if(sockfd)

{

建立连接();

int connfd = accept();

加入到监听文件描述符集合;

FD_SET(connfd);

}否则说明是一个已经连接过的描述符

else

{

进行操作(send或者recv);

recv();

send();

}

}

select弊端:

1. 一个进程最多只能监听1024个文件描述符 (千级别)

2. select是一种轮询的机制;

3. 涉及到用户态和内核态的数据拷贝;

b. poll

1. 优化文件描述符个数的限制;

2. poll是一种轮询的机制;

3. 涉及到用户态和内核态的数据拷贝;

函数接口:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

参数:

struct pollfd *fds

关心的文件描述符数组struct pollfd fds[N];

nfds:个数

timeout: 超市检测

毫秒级的:如果填1000,1秒

如果-1,阻塞

问题:

我想检测是键盘事件(标准输入 文件描述如为0 ),

还是鼠标事件(文件描述符是/dev/input/mouse1);

1. 创建一个结构体数组

struct pollfd fds[2];

2. 将你关心的文件描述符加入到结构体成员中

struct pollfd {

int   fd;         // 关心的文件描述符;

short events;     // 关心的事件,读

short revents;    // 如果产生事件,则会自动填充该成员的值

};

// 键盘

fds[0].fd = 0;

fds[0].events = POLLIN;

//鼠标

fds[1].fd = mouse1_fd;

fds[1].events = POLLIN;

3. 调用poll函数

如果返回表示有事件产生;

poll(fds,2,1000)

4. 判断具体是哪个文件描述符产生了事件

if(fds[0].revents == POLLIN)

{

....

}

c. epoll

1. 没有文件描述符的限制

2. 异步IO,当有事件产生,文件描述符主动调用callback

3. 不用数据拷贝;

3个功能函数:

#include <sys/epoll.h>

int epoll_create(int size);//创建红黑树根节点

//成功时返回epoll文件描述符,失败时返回-1

//控制epoll属性

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epfd:epoll_create函数的返回句柄。

op:表示动作类型。有三个宏 来表示:

EPOLL_CTL_ADD:注册新的fd到epfd中

EPOLL_CTL_MOD:修改已注册fd的监听事件

EPOLL_CTL_DEL:从epfd中删除一个fd

FD:需要监听的fd。

event:告诉内核需要监听什么事件

EPOLLIN:表示对应文件描述符可读

EPOLLOUT:可写

EPOLLPRI:有紧急数据可读;

EPOLLERR:错误;

EPOLLHUP:被挂断;

EPOLLET:触发方式,电平触发;

ET模式:表示状态的变化;

//成功时返回0,失败时返回-1

//等待事件到来

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

功能:等待事件的产生,类似于select嗲用

epfd:句柄;

events:用来从内核得到事件的集合;

maxevents:表示每次能处理事件最大个数;

timeout:超时时间,毫秒,0立即返回,-1阻塞

//成功时返回发生事件的文件描述数,失败时返回-1

伪代码:

1.定义epoll事件,创建epoll的fd

int epfd,epct,i;

struct epoll_event event;       //定义epoll 事件

struct epoll_event events[20];  //定义epoll 事件集合

epfd = epoll_create(1); // 创建epoll 的fd

2.填充事件

event.data.fd = serverFd;           //填充事件的fd

event.events = EPOLLIN | EPOLLET;   //填充 事件类型

epoll_ctl(epfd,EPOLL_CTL_ADD,serverFd,&event);  //把serverFd(监听FD)注册到epfd中

3.监听事件

while(1){

epct = epoll_wait(epfd,events,20,-1); // 等待事件到来,阻塞模式

for(i=0;i<epct;i++){  //根据epoll返回的值来查询事件

if(events[i].data.fd == serverFd){ // 如果事件的fd是监听fd,调用accept处理

clientFd = accept();

//添加clientfd描述符

epoll_ctl(epfd,EPOLL_CTL_ADD,clientFd,&event);

}else {

//如果不是serverFd,应是client数据事件,调用读数据

read();

}

}

}

【3】数据库函数接口

 1.int   sqlite3_open(char  *path,   sqlite3 **db);

功能:打开sqlite数据库

参数:

path: 数据库文件路径

db: 指向sqlite句柄的指针

返回值:成功返回0,失败返回错误码(非零值)

 2.int   sqlite3_close(sqlite3 *db);

功能:关闭sqlite数据库

返回值:成功返回0,失败返回错误码

 3.int sqlite3_exec(sqlite3 *db, const  char  *sql,

sqlite3_callback callback, void *,  char **errmsg);

功能:执行SQL语句

参数:

db:数据库句柄

sql:SQL语句 ("create table stu .....;")

callback:回调函数

void * arg:

当使用查询命令的时候,callback和arg才有意义;

select .....

errmsg:错误信息指针的地址

char *errmsg;

&errmsg;

返回值:成功返回0,失败返回错误码

 int callback(void *para, int f_num, char **f_value, char **f_name);

功能:每找到一条记录自动执行一次回调函数

参数:

para:   传递给回调函数的参数

f_num:  记录中包含的字段数目(id name score)

相当于有多少列;

f_value:包含每个字段值的指针数组

f_name:包含每个字段名称的指针数组

返回值:成功返回0,失败返回-1

 4.int  sqlite3_get_table(sqlite3 *db, const  char  *sql,

char ***resultp,  int *nrow,  int *ncolumn, char **errmsg);

功能:执行SQL操作

参数:

db:数据库句柄

sql:SQL语句

resultp:用来指向sql执行结果的指针;实际上就是“指针数组指针”;

nrow:满足条件的记录的数目,实际上就是有多少行数据;

ncolumn:每条记录包含的字段数目,实际上就是有多少个字段(多少列);

errmsg:错误信息指针的地址

返回值:成功返回0,失败返回错误码

练习:创建数据库stu.db,包含name、id、score字段,实现对数据库的增删改查。

【4】员工管理系统

1.通信结构体的定义(5min)

2.服务器负责处理操作

客户端不能直接操作数据库

common.h

#ifndef _COMMON_H_
#define _COMMON_H_#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <pthread.h>#define STAFF_DATABASE     "staff_manage_system.db"#define USER_LOGIN       0x00000000  // login    登陆    0x00000001
#define USER_MODIFY     0x00000001  // user-modification  修改
#define USER_QUERY      0x00000002  // user-query   查询#define ADMIN_LOGIN   0x10000000  // login    登陆    0x00000001
#define ADMIN_MODIFY    0x10000001 // admin_modification
#define ADMIN_ADDUSER   0x10000002 // admin_adduser
#define ADMIN_DELUSER   0x10000004 // admin_deluser
#define ADMIN_QUERY     0x10000008  //hitory_query
#define ADMIN_HISTORY   0x10000010  //hitory_query#define QUIT          0x11111111#define ADMIN 0   //管理员
#define USER  1 //用户#define NAMELEN 16
#define DATALEN 128/*员工基本信息*/
typedef struct staff_info{int  no;          //员工编号int  usertype;    //ADMIN 1   USER 2   char name[NAMELEN];    //姓名char passwd[8];     //密码int  age;           // 年龄char phone[NAMELEN];//电话char addr[DATALEN]; // 地址char work[DATALEN]; //职位char date[DATALEN];   //入职年月int level;            // 等级double salary ;        // 工资}staff_info_t;/*定义双方通信的结构体信息*/
typedef struct {int  msgtype;     //请求的消息类型int  usertype;    //ADMIN 1  USER 2     char username[NAMELEN];  //姓名char passwd[8];          //登陆密码char recvmsg[DATALEN];   //通信的消息int  flags;      //标志位staff_info_t info;      //员工信息
}MSG;#endif

Makefile

all:gcc server.c -o server -lpthread -lsqlite3gcc client.c -o clientclean:rm server client

 client.c

#include "common.h"/***************************************函数名:do_query*参   数:消息结构体*功   能:登陆****************************************/
void do_admin_query(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:admin_modification*参   数:消息结构体*功   能:管理员修改****************************************/
void do_admin_modification(int sockfd,MSG *msg)//管理员修改
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:admin_adduser*参   数:消息结构体*功   能:管理员创建用户****************************************/
void do_admin_adduser(int sockfd,MSG *msg)//管理员添加用户
{       printf("------------%s-----------%d.\n",__func__,__LINE__);
}/***************************************函数名:admin_deluser*参   数:消息结构体*功   能:管理员删除用户****************************************/
void do_admin_deluser(int sockfd,MSG *msg)//管理员删除用户
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:do_history*参   数:消息结构体*功   能:查看历史记录****************************************/
void do_admin_history (int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:admin_menu*参   数:套接字、消息结构体*功   能:管理员菜单****************************************/
void admin_menu(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);
}/***************************************函数名:do_query*参   数:消息结构体*功   能:登陆****************************************/
void do_user_query(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:do_modification*参   数:消息结构体*功   能:修改****************************************/
void do_user_modification(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}/***************************************函数名:user_menu*参   数:消息结构体*功   能:管理员菜单****************************************/
void user_menu(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int admin_or_user_login(int sockfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);//输入用户名和密码memset(msg->username, 0, NAMELEN);printf("请输入用户名:");scanf("%s",msg->username);getchar();memset(msg->passwd, 0, DATALEN);printf("请输入密码(6位)");scanf("%s",msg->passwd);getchar();//发送登陆请求send(sockfd, msg, sizeof(MSG), 0);//接受服务器响应recv(sockfd, msg, sizeof(MSG), 0);printf("msg->recvmsg :%s\n",msg->recvmsg);//判断是否登陆成功if(strncmp(msg->recvmsg, "OK", 2) == 0){if(msg->usertype == ADMIN){printf("亲爱的管理员,欢迎您登陆员工管理系统!\n");admin_menu(sockfd,msg);}else if(msg->usertype == USER){printf("亲爱的用户,欢迎您登陆员工管理系统!\n");user_menu(sockfd,msg);}}else{printf("登陆失败!%s\n", msg->recvmsg);return -1;}return 0;
}/*************************************************函数名:do_login*参   数:套接字、消息结构体*返回值:是否登陆成功*功   能:登陆*************************************************/
int do_login(int sockfd)
{   int n;MSG msg;while(1){printf("*************************************************************\n");printf("********  1:管理员模式    2:普通用户模式    3:退出********\n");printf("*************************************************************\n");printf("请输入您的选择(数字)>>");scanf("%d",&n);getchar();switch(n){case 1:msg.msgtype  = ADMIN_LOGIN;msg.usertype = ADMIN;break;case 2:msg.msgtype =  USER_LOGIN;msg.usertype = USER;break;case 3:msg.msgtype = QUIT;if(send(sockfd, &msg, sizeof(MSG), 0)<0){perror("do_login send");return -1;}close(sockfd);exit(0);default:printf("您的输入有误,请重新输入\n"); }admin_or_user_login(sockfd,&msg);}}int main(int argc, const char *argv[])
{//socket->填充->绑定->监听->等待连接->数据交互->关闭 //创建网络通信的套接字//填充网络结构体//连接服务器if(connect() == -1){perror("connect failed.\n");exit(-1);}do_login(sockfd);close(sockfd);return 0;
}

 server.c

#include "common.h"sqlite3 *db;  //仅服务器使用int process_user_or_admin_login_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);//封装sql命令,表中查询用户名和密码-存在-登录成功-发送响应-失败-发送失败响应 char sql[DATALEN] = {0};char *errmsg;char **result;int nrow,ncolumn;msg->info.usertype =  msg->usertype;strcpy(msg->info.name,msg->username);strcpy(msg->info.passwd,msg->passwd);printf("usrtype: %#x-----usrname: %s---passwd: %s.\n",msg->info.usertype,msg->info.name,msg->info.passwd);sprintf(sql,"select * from usrinfo where usertype=%d and name='%s' and passwd='%s';",msg->info.usertype,msg->info.name,msg->info.passwd);if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg) != SQLITE_OK){printf("---****----%s.\n",errmsg);       }else{//printf("----nrow-----%d,ncolumn-----%d.\n",nrow,ncolumn);     if(nrow == 0){strcpy(msg->recvmsg,"name or passwd failed.\n");send(acceptfd,msg,sizeof(MSG),0);}else{strcpy(msg->recvmsg,"OK");send(acceptfd,msg,sizeof(MSG),0);}}return 0;
}int process_user_modify_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_user_query_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_admin_modify_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_admin_adduser_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_admin_deluser_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_admin_query_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_admin_history_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_client_quit_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);}int process_client_request(int acceptfd,MSG *msg)
{printf("------------%s-----------%d.\n",__func__,__LINE__);switch (msg->msgtype){case USER_LOGIN:case ADMIN_LOGIN:process_user_or_admin_login_request(acceptfd,msg);break;case USER_MODIFY:process_user_modify_request(acceptfd,msg);break;case USER_QUERY:process_user_query_request(acceptfd,msg);break;case ADMIN_MODIFY:process_admin_modify_request(acceptfd,msg);break;case ADMIN_ADDUSER:process_admin_adduser_request(acceptfd,msg);break;case ADMIN_DELUSER:process_admin_deluser_request(acceptfd,msg);break;case ADMIN_QUERY:process_admin_query_request(acceptfd,msg);break;case ADMIN_HISTORY:process_admin_history_request(acceptfd,msg);break;case QUIT:process_client_quit_request(acceptfd,msg);break;default:break;}}int main(int argc, const char *argv[])
{//判断命令行参数  //打开数据库if(sqlite3_open() != SQLITE_OK){printf("%s.\n",sqlite3_errmsg(db));}else{printf("the database open success.\n");}//执行数据库操作if(sqlite3_exec()!= SQLITE_OK){printf("%s.\n",errmsg);}else{printf("create usrinfo table success.\n");}//socket->填充->绑定->监听->等待连接->数据交互->关闭//创建网络通信的套接字sockfd = socket();if(sockfd == -1){perror("socket failed.\n");exit(-1);}//填充网络结构体  //绑定网络套接字和网络结构体if(bind() == -1){printf("bind failed.\n");exit(-1);}//监听套接字,将主动套接字转化为被动套接字if(listen() == -1){printf("listen failed.\n");exit(-1);}//通过select实现并发while(1){retval =select();//判断是否是集合里关注的事件if(判断是连接请求){//数据交互 acceptfd = accept();if(acceptfd == -1){printf("acceptfd failed.\n");exit(-1);}                  }else{recvbytes = recv();if(recvbytes == -1){printf("recv failed.\n");continue;}else if(recvbytes == 0){printf("peer shutdown.\n");close(i);FD_CLR(i, &readfds);  //删除集合中的i}else{process_client_request(i,&msg);}}}close(sockfd);return 0;
}

以下为员工管理系统带调试信息的打印记录:管理员登陆:客户端的打印信息服务器端的打印信息普通员工登陆:客户端的打印信息服务器端的打印信息@@@@@@@@@@@@@@@@@@@@@@管理员登陆--客户端的测试记录:@@@@@@@@@@@@@@@@@@@@@@linux@ubuntu:/mnt/hgfs/KernelSource/staff_manage_select/stage4-user$ ./client
sockfd :3.
*************************************************************
********  1:管理员模式    2:普通用户模式    3:退出********
*************************************************************
请输入您的选择(数字)>>1
------------admin_or_user_login-----------489.
请输入用户名:admin
请输入密码(6位)admin
msg->recvmsg :OK
亲爱的管理员,欢迎您登陆员工管理系统!*************************************************************
* 1:查询  2:修改 3:添加用户  4:删除用户  5:查询历史记录*
* 6:退出                                                   *
*************************************************************
请输入您的选择(数字)>>1
------------do_admin_query-----------35.
*************************************************************
******* 1:按人名查找      2:查找所有   3:退出  *******
*************************************************************
请输入您的选择(数字)>>1
请输入您要查找的用户名:xiaohui
工号  用户类型     姓名 密码  年龄  电话  地址  职位  入职年月    等级   工资
======================================================================================
1004,    1,    xiaohui,    1,    31,    1888x,    henan,    gagagaga,    9012.10.11,    1,    1.0;.
*************************************************************
******* 1:按人名查找      2:查找所有   3:退出  *******
*************************************************************
请输入您的选择(数字)>>2
工号  用户类型     姓名 密码  年龄  电话  地址  职位  入职年月    等级   工资
======================================================================================
1001,    0,    admin,    admin,    18,    110,    华清远见创客学院,    嵌入式物联网方向讲师,    xxx,    5,    1.0;.
======================================================================================
1003,    1,    fengjunhui,    1,    30,    18888888888,    henan,    gaga,    2015.10.23,    1,    10.0;.
======================================================================================
1002,    1,    lisi,    1,    20,    119,    华清远见创客学院=北京,    ooo,    2019.11.11,    1,    50.0;.
======================================================================================
1004,    1,    xiaohui,    1,    31,    1888x,    henan,    gagagaga,    9012.10.11,    1,    1.0;.
*************************************************************
******* 1:按人名查找      2:查找所有   3:退出  *******
*************************************************************
请输入您的选择(数字)>>3*************************************************************
* 1:查询  2:修改 3:添加用户  4:删除用户  5:查询历史记录*
* 6:退出                                                   *
*************************************************************
请输入您的选择(数字)>>2
------------do_admin_modification-----------100.
请输入您要修改只认的工号:1002
*******************请输入要修改的选项********************
******  1:姓名   2:年龄   3:家庭住址   4:电话  ******
******  5:职位    6:工资  7:入职年月   8:评级  ******
******  9:密码  10:退出                 *******
*************************************************************
请输入您的选择(数字)>>2
请输入年龄:30
数据库修改成功!修改结束.

23.2.28 Staffing System相关推荐

  1. (28)System Verilog进程间同步(事件event)

    (28)System Verilog进程间同步(事件event) 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog进程间同步(事件eve ...

  2. (28)System Verilog设计UART发送

    (28)System Verilog设计UART发送 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog设计UART发送 1.UART发送 ...

  3. 【离散数学】 SEU - 24 - 2021/05/28 - Algebraic System

    Discrete Mathematical Structures (6th Edition) 2021/05/28 - Algebraic System Algebraic System Binary ...

  4. 寒假集训总结 (1.23~1.28) [第一梯队]

    Day 1. 分治算法入门 一.分治法概述 分治法的设计思想 对于一个规模为 n n n的问题:若该问题可以容易地解决(比如说规模 n n n较小)则直接解决,否则将其分解为 k k k个规模较小的子 ...

  5. 论文调研——23.2.28

    文章目录 Diffusion Models: A Comprehensive Survey of Methods and Applications ADVERSARIAL TRAINING METHO ...

  6. JavaEE基础第9章Java常用类

    第9章Java常用类 字面量的定义方式都是存在常量池中的,常量池中不会存储多个一样的字符串,在定义一个字符串的时候会先去常量池中找有没有存在的,有就将地址传过去,没有就新建. String字符串 概念 ...

  7. LintCode 28. 搜索二维矩阵

    import org.junit.Test;import java.util.Arrays;public class SearchMatrix {/*** @param matrix: matrix, ...

  8. 【DockerCE】Docker-CE 20.10.23正式版发布

    官网地址(For RHEL/CentOS 7.9): https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ 20.10. ...

  9. 23年2月CCF会议截稿8条-SACMAT2023/UAI2023/Euro-Par2023/ASAP2023/ICCCN2023/MobHoc2023/ICCBR2023/PETS2023

    点击文末公众号卡片,找对地方,轻松参会 会议简称 截稿时间 通知时间 录用率 官网 SACMAT2023 23.2.17 23.4.12 21年28.6% https://sacmat2023.fbk ...

最新文章

  1. 安装 SQL Server 2008 R2 的硬件和软件要求(转)
  2. Nginx负载均衡和反向代理
  3. Android中四种补间动画的使用示例(附代码下载)
  4. llinux环境变量查看和修改
  5. 漂亮实用的loading(加载)封装
  6. const常类型说明
  7. IBM FileNet Content Java API 简介
  8. LEWITT莱维特STREAM4x5、DGT260声卡安装调试教程
  9. Scrapy框架以及scrapy-redis实现分布式爬虫
  10. RGB888颜色码与十六位(RGB565)颜色码的转换
  11. Java集成建行龙支付接口(详细)
  12. 怎么把图片的边缘弄圆_如何PS制做出边缘清晰或虚化的圆角照片
  13. 及c语言实现 pdf,词法分析及其C语言实现.PDF
  14. 10个重要的算法C语言实现源代码:拉格朗日,牛顿插值,高斯,龙贝格,牛顿迭代,牛顿-科特斯,雅克比,秦九昭,幂法,高斯塞德尔
  15. 使用Linux搭建软路由
  16. 成功解决 -- flink.shaded.guava18.NumberFormatException: Not a version
  17. jQuery+PHP+Ajax动态数字统计展示实例
  18. java ext.dirs_关于-Djava.ext.dirs使用及JAVA 命令参数详解System.setProperty
  19. python os.path模块
  20. 盘点HR日常工作数据计算大全

热门文章

  1. Tensorflow使用Char-CNN实现中文文本分类(1)
  2. 如何在地址栏加上网站的标志、LOGO图片
  3. 服务器.esp文件,ESP32 Arduino教程:通过软接入点(soft AP)实现HTTP服务器-esp文件
  4. 演绎真实世界?看人性在游戏中的养成之路
  5. day32-跳跃游戏股票售买
  6. 2023 年 3 月 GameFi 月度报告
  7. 喝不完的饮料(C语言解析)
  8. 以ear结尾的单词(ChatGPT4写作)
  9. Linux设备检测外部网络NAT类型
  10. “蝉原则”与CSS3随机多背景随机圆角等效果