电子商务网站开发教程房地产销售策划方案
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:22
当前位置: 首页 > news >正文
电子商务网站开发教程,房地产销售策划方案,域名更新自动转跳,网站设计目录 1. Redis 异步方式1.1 同步连接优点缺点示例#xff1a;访问 Redis#xff0c;并对 counter 实现自增1000次#xff0c;统计用时 1.2 异步连接优点缺点1.2.1 Redis 驱动1.2.2 示例第1步#xff1a;实现 Reactor第2步#xff1a;实现 Redis 适配器第3步#xff1a;实… 目录 1. Redis 异步方式1.1 同步连接优点缺点示例访问 Redis并对 counter 实现自增1000次统计用时 1.2 异步连接优点缺点1.2.1 Redis 驱动1.2.2 示例第1步实现 Reactor第2步实现 Redis 适配器第3步实现主体代码 参考 1. Redis 异步方式
Redis 提供了两种主要的连接方式同步连接和异步连接。选择合适的连接方式可以显著影响应用的性能和响应能力。
1.1 同步连接
同步连接是指客户端与 Redis 服务器之间的一种简单的请求-响应模式。当使用同步连接时客户端发送一个命令给 Redis 服务器并在收到服务器响应之后才能继续执行后续的操作。在同步连接中客户端在执行命令时会阻塞当前线程等待服务器的响应直到响应返回或超时。
优点
实现简单代码逻辑直观易于理解和维护。业务逻辑连贯操作按顺序执行业务逻辑没有割裂。
缺点
阻塞当前线程每个命令执行都需要等待响应可能导致线程阻塞影响性能。效率较低在高并发场景下频繁的阻塞和唤醒线程会增加系统开销。
示例访问 Redis并对 counter 实现自增1000次统计用时
以下是一个使用 hiredis 库的 C 程序示例该程序连接到 Redis 服务器对 counter 键进行 1000 次自增操作并统计所用时间。
编译命令
gcc redis-test-sync.c -o redis-test-sync -lhiredis代码示例 (redis-test-sync.c)
#include stdio.h
#include stdlib.h
#include string.h
#include time.h
#include hiredis/hiredis.h// 获取当前时间的毫秒数
int current_tick() {int t 0;struct timespec ti;clock_gettime(CLOCK_MONOTONIC, ti);t (int)ti.tv_sec * 1000;t ti.tv_nsec / 1000000;return t;
}int main(int argc, char argv) {redisContext *c;redisReply *reply;const char *hostname 127.0.0.1;int port 6379;// 设置连接超时时间为1.5秒struct timeval timeout { 1, 500000 }; // 1.5 seconds// 连接到Redis服务器c redisConnectWithTimeout(hostname, port, timeout);if (c NULL || c-err) {if © {printf(Connection error: %s\n, c-errstr);redisFree©;} else {printf(Connection error: cant allocate redis context\n);}exit(1);}// 获取自增次数默认为1000int num (argc 1) ? atoi(argv[1]) : 1000;int before current_tick();// 执行自增操作for (int i 0; i num; i) {reply redisCommand(c, INCR counter); // 1操作printf(INCR counter: %lld\n, reply-integer);freeReplyObject(reply);}int used current_tick() - before;printf(After %d exec redis commands, used %d ms\n, num, used);// 断开连接redisFree©;return 0;
}输出示例
INCR counter: 1
INCR counter: 2
…
INCR counter: 1000
After 1000 exec redis commands, used 150 ms解释
连接Redis服务器使用 redisConnectWithTimeout 函数连接到 Redis 服务器设置超时时间为 1.5 秒。执行自增操作循环执行 INCR counter 命令次数由命令行参数决定默认为 1000 次。统计用时记录操作前后的时间差计算总耗时。输出结果每次自增操作的结果以及总耗时。 1.2 异步连接
异步连接允许客户端在发送命令后不等待响应可以继续执行其他操作适用于高性能和高并发场景。异步连接通常通过事件驱动机制实现可以充分利用多核 CPU 和网络资源。
优点
非阻塞操作不会阻塞当前线程提升系统的并发处理能力。更高的效率适合高并发和低延迟要求的应用场景。灵活的业务逻辑可以在等待响应的同时处理其他任务。
缺点
实现复杂代码逻辑较为复杂需要处理事件循环和回调函数。业务逻辑割裂异步操作可能导致业务逻辑分散难以维护。依赖事件库通常需要结合事件驱动库如 libevent、libuv使用。
1.2.1 Redis 驱动
实现异步连接需要一个 Redis 驱动该驱动需要将 Redis 连接融入项目中的 Reactor 模式进行管理。具体步骤如下 实现Redis驱动 服务端使用异步连接需要自己实现 Redis 驱动即将 Redis 连接与项目中的 Reactor 进行融合管理。 设计Redis适配器 构建Redis事件对象包括 hiredis 事件对象和 Reactor 事件对象。适配事件控制复用项目中的 Reactor 事件循环。 hiredis 的封装规则 Reactor 的实现所有的 IO 由用户实现。适配器的实现hiredis 提供事件操作接口用户需要适配这些接口。不同的网络库和平台对事件操作接口的实现可能不同。
用户需要适配的 hiredis 事件接口包括
addRead添加读事件delRead删除读事件addWrite添加写事件delWrite删除写事件cleanup事件对象释放scheduleTimer
1.2.2 示例
以下示例展示了如何实现 Redis 异步连接包括 Reactor 的实现、Redis 适配器以及主体代码。
第1步实现 Reactor
文件reactor.h
#ifndef _MARKREACTOR
#define _MARKREACTOR#include sys/epoll.h
#include stdio.h
#include unistd.h // read write
#include fcntl.h // fcntl
#include sys/types.h // listen
#include sys/socket.h // socket
#include errno.h // errno
#include arpa/inet.h // inet_addr htons
#include assert.h // assert
#include stdlib.h // malloc
#include string.h // memcpy memmove#include chainbuffer/buffer.h // 自定义缓冲区实现#define MAX_EVENT_NUM 512 // 每次用户拷贝事件的最大数目
#define MAX_CONN ((116)-1) // 事件对象的最大数目65535typedef struct event_s event_t;typedef void (*event_callback_fn)(int fd, int events, void *privdata);
typedef void (*error_callback_fn)(int fd, char * err);// Reactor对象管理IO的全局变量
typedef struct {int epfd; // epoll文件描述符int listenfd; // 监听的文件描述符int stop; // 停止循环标记event_t *events; // 存储所有事件对象存储在堆上记得释放int iter; // 用于遍历events获取未被使用的位置struct epoll_event fire[MAX_EVENT_NUM]; // 用户态数组用于拷贝IO事件到用户态
} reactor_t;// 事件对象sockitem保存每个fd对应的IO状态
struct event_s {int fd; // 事件对应的文件描述符reactor_t *r; // 指向Reactor全局对象buffer_t in; // 读缓冲待读取buffer_t out; // 写缓冲待发送event_callback_fn read_fn; // 读回调函数event_callback_fn write_fn; // 写回调函数error_callback_fn error_fn; // 错误回调函数
};// 函数声明
int event_buffer_read(event_t *e);
int event_buffer_write(event_t *e, void * buf, int sz);reactor_t * create_reactor();void release_reactor(reactor_t * r);event_t * new_event(reactor_t *R, int fd,event_callback_fn rd,event_callback_fn wt,error_callback_fn err);void free_event(event_t *e);int set_nonblock(int fd);int add_event(reactor_t *R, int events, event_t *e);int del_event(reactor_t *R, event_t *e);int enable_event(reactor_t *R, event_t *e, int readable, int writeable);void eventloop_once(reactor_t * r, int timeout);void stop_eventloop(reactor_t * r);void eventloop(reactor_t * r);int create_server(reactor_t *R, short port, event_callback_fn func);int event_buffer_read(event_t *e);int event_buffer_write(event_t *e, void * buf, int sz);#endif文件reactor.c
#include reactor.h// 创建Reactor对象
reactor_t *
create_reactor() {reactor_t *r (reactor_t *)malloc(sizeof(r));r-epfd epoll_create(1);r-listenfd 0;r-stop 0;r-iter 0;r-events (event_t)malloc(sizeof(event_t)*MAX_CONN);memset(r-events, 0, sizeof(event_t)*MAX_CONN);memset(r-fire, 0, sizeof(struct epoll_event) * MAX_EVENT_NUM);return r;
}// 释放Reactor对象
void
release_reactor(reactor_t * r) {free(r-events);close(r-epfd);free®;
}// 获取Reactor的事件堆event上的空闲事件对象
static event_t *
_get_event_t(reactor_t *r) {r-iter;while (r-events[r-iter MAX_CONN].fd 0) {r-iter;}return r-events[r-iter];
}// 创建事件对象
event_t *
new_event(reactor_t *R, int fd,event_callback_fn rd,event_callback_fn wt,error_callback_fn err) {assert(rd ! 0 || wt ! 0 || err ! 0);// 获取空闲事件对象event_t *e _get_event_t®;// 初始化事件对象e-r R;e-fd fd;buffer_init(e-in, 1024*16);buffer_init(e-out, 1024*16);e-read_fn rd;e-write_fn wt;e-error_fn err;return e;
}// 释放事件对象分配的buffer空间
void
free_event(event_t *e) {buffer_free(e-in);buffer_free(e-out);
}// 设置非阻塞的fd
int
set_nonblock(int fd) {int flag fcntl(fd, F_GETFL, 0);return fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}// 添加事件
int
add_event(reactor_t *R, int events, event_t *e) {struct epoll_event ev;ev.events events;ev.data.ptr e;if (epoll_ctl(R-epfd, EPOLL_CTL_ADD, e-fd, ev) -1) {printf(Add event error, fd %d\n, e-fd);return 1;}return 0;
}// 删除事件
int
del_event(reactor_t *R, event_t *e) {epoll_ctl(R-epfd, EPOLL_CTL_DEL, e-fd, NULL);free_event(e);return 0;
}// 修改事件读事件 or 写事件
int
enable_event(reactor_t *R, event_t *e, int readable, int writeable) {struct epoll_event ev;ev.events (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0);ev.data.ptr e;if (epoll_ctl(R-epfd, EPOLL_CTL_MOD, e-fd, ev) -1) {return 1;}return 0;
}// 一次事件循环
void
eventloop_once(reactor_t * r, int timeout) {int n epoll_wait(r-epfd, r-fire, MAX_EVENT_NUM, timeout);for (int i 0; i n; i) {struct epoll_event *e r-fire[i];int mask e-events;if (e-events EPOLLERR) mask | EPOLLIN | EPOLLOUT;if (e-events EPOLLHUP) mask | EPOLLIN | EPOLLOUT;event_t et (event_t) e-data.ptr;// 处理读事件if (mask EPOLLIN) {if (et-read_fn)et-read_fn(et-fd, EPOLLIN, et);}// 处理写事件if (mask EPOLLOUT) {if (et-write_fn)et-write_fn(et-fd, EPOLLOUT, et);else {uint8_t * buf buffer_write_atmost(et-out);event_buffer_write(et, buf, buffer_len(et-out));}}}
}// 停止事件循环
void
stop_eventloop(reactor_t * r) {r-stop 1;
}// 事件循环
void
eventloop(reactor_t * r) {while (!r-stop) {eventloop_once(r, -1); // 阻塞等待事件}
}// 创建服务器
int
create_server(reactor_t *R, short port, event_callback_fn func) {int listenfd socket(AF_INET, SOCK_STREAM, 0);if (listenfd 0) {printf(Create listenfd error!\n);return -1;}struct sockaddr_in addr;memset(addr, 0, sizeof(struct sockaddr_in));addr.sin_family AF_INET;addr.sin_port htons(port);addr.sin_addr.s_addr INADDR_ANY;// 设置地址重用允许快速重启服务器int reuse 1;if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void )reuse, sizeof(int)) -1) {printf(Reuse address error: %s\n, strerror(errno));return -1;}if (bind(listenfd, (struct sockaddr)addr, sizeof(struct sockaddr_in)) 0) {printf(Bind error: %s\n, strerror(errno));return -1;}if (listen(listenfd, 5) 0) {printf(Listen error: %s\n, strerror(errno));return -1;}if (set_nonblock(listenfd) 0) {printf(Set nonblock error: %s\n, strerror(errno));return -1;}R-listenfd listenfd;event_t *e new_event(R, listenfd, func, 0, 0);add_event(R, EPOLLIN, e);printf(Listening on port: %d\n, port);return 0;
}// 读取数据
int
event_buffer_read(event_t *e) {int fd e-fd;int num 0;while (1) {// TODO: 不要在这里使用固定大小的缓冲区char buf[1024] {0};int n read(fd, buf, 1024);if (n 0) { // 半关闭状态printf(Close connection, fd %d\n, fd);if (e-error_fn)e-error_fn(fd, Close socket);del_event(e-r, e);close(fd);return 0;} else if (n 0) { // 异常if (errno EINTR) // 被中断重试continue;if (errno EWOULDBLOCK) // 阻塞因为read buffer为空break;printf(Read error, fd %d, err %s\n, fd, strerror(errno));if (e-error_fn)e-error_fn(fd, strerror(errno));del_event(e-r, e);close(fd);return 0;} else { // 正常printf(Received data from client: %s, buf);buffer_add(e-in, buf, n);}// 多次读取的话按序接在后面num n;}return num;
}// 向对端发送数据
static int
_write_socket(event_t *e, void * buf, int sz) {int fd e-fd;while (1) {int n write(fd, buf, sz);if (n 0) {if (errno EINTR)continue;if (errno EWOULDBLOCK)break;if (e-error_fn)e-error_fn(fd, strerror(errno));del_event(e-r, e);close(e-fd);}return n;}return 0;
}// 写数据
int
event_buffer_write(event_t *e, void * buf, int sz) {buffer_t *r e-out;if (buffer_len® 0) {int n _write_socket(e, buf, sz);if (n 0 || n sz) {// 发送失败将未发送的数据写入缓冲区并注册写事件buffer_add(e-out, (char *)buf n, sz - n);enable_event(e-r, e, 1, 1);return 0;} else if (n 0) return 0;return 1;}buffer_add(e-out, (char *)buf, sz);return 1;
}第2步实现 Redis 适配器
文件adapter_async.h
#ifndef _MARKADAPTER
#define _MARKADAPTER#include hiredis/hiredis.h
#include hiredis/async.h
#include reactor.h// Redis事件对象
typedef struct {event_t e; // Reactor事件对象int mask; // 存储注册的事件redisAsyncContext *ctx; // hiredis异步上下文
} redis_event_t;// Redis对象读事件回调
static void redisReadHandler(int fd, int events, void *privdata) {(void)fd;(void)events;event_t e (event_t)privdata;redis_event_t *re (redis_event_t *)(char *)e;redisAsyncHandleRead(re-ctx);
}// Redis对象写事件回调
static void redisWriteHandler(int fd, int events, void *privdata) {(void)fd;(void)events;event_t e (event_t)privdata;redis_event_t *re (redis_event_t *)(char *)e;redisAsyncHandleWrite(re-ctx);
}/* brief 更新Reactor管理的事件对象* param privdata Redis事件对象* param flag 要设置的epoll事件类型 * param remove 1 删除该事件0 添加该事件*/
static void redisEventUpdate(void *privdata, int flag, int remove) {redis_event_t *re (redis_event_t *)privdata;reactor_t *r re-e.r;int prevMask re-mask;int enable 0; // Redis事件对象删除该事件if (remove) {if ((re-mask flag) 0) {return;}re-mask ~flag;enable 0;} // Redis事件对象添加该事件else {if (re-mask flag) {return; } re-mask | flag;enable 1;}// 对Reactor事件对象的处理// 1. 删除该事件if (re-mask 0) {del_event(r, re-e);} // 2. 添加该事件首次加入else if (prevMask 0) {add_event(r, re-mask, re-e);} // 3. 修改该事件else {// 注册读事件if (flag EPOLLIN) {enable_event(r, re-e, enable, 0);} // 注册写事件else if (flag EPOLLOUT) {enable_event(r, re-e, 0, enable);}}
}// 添加读事件
static void redisAddRead(void *privdata) {redis_event_t *re (redis_event_t *)privdata;re-e.read_fn redisReadHandler;redisEventUpdate(privdata, EPOLLIN, 0);
}// 删除读事件
static void redisDelRead(void *privdata) {redis_event_t *re (redis_event_t *)privdata;re-e.read_fn 0;redisEventUpdate(privdata, EPOLLIN, 1);
}// 添加写事件
static void redisAddWrite(void *privdata) {redis_event_t *re (redis_event_t *)privdata;re-e.write_fn redisWriteHandler;redisEventUpdate(privdata, EPOLLOUT, 0);
}// 删除写事件
static void redisDelWrite(void *privdata) {redis_event_t *re (redis_event_t *)privdata;re-e.write_fn 0;redisEventUpdate(privdata, EPOLLOUT, 1);
}// 释放Redis事件对象
static void redisCleanup(void *privdata) {redis_event_t *re (redis_event_t *)privdata;reactor_t *r re-e.r;del_event(r, re-e);free(re);
}// 绑定Redis异步上下文到Reactor
static int redisAttach(reactor_t *r, redisAsyncContext *ac) { redisContext *c (ac-c); // 获取Redis同步上下文redis_event_t re; // Redis事件对象/ 确保没有重复绑定 /if (ac-ev.data ! NULL)return REDIS_ERR;/ 创建容器用于ctx和读写事件 /re (redis_event_t)malloc(sizeof(*re));if (re NULL) {return REDIS_ERR;} // 初始化Redis事件对象re-ctx ac; // 绑定Redis异步上下文re-e.fd c-fd; // 绑定Redis的fdre-e.r r; // 绑定Reactorre-mask 0; // 初始化事件掩码// 设置hiredis的事件接口用户实现这些接口ac-ev.addRead redisAddRead;ac-ev.delRead redisDelRead;ac-ev.addWrite redisAddWrite;ac-ev.delWrite redisDelWrite;ac-ev.cleanup redisCleanup;ac-ev.data re;return REDIS_OK;
}#endif第3步实现主体代码
编译命令
gcc chainbuffer/buffer.c redis-test-async.c reactor.c -o redis-test-async -lhiredis代码示例 (redis-test-async.c)
#include hiredis/hiredis.h
#include hiredis/async.h
#include time.h#include reactor.h
#include adapter_async.hstatic reactor_t *R;
static int cnt, before, num;// 获取当前时间的毫秒数
int current_tick() {int t 0;struct timespec ti;clock_gettime(CLOCK_MONOTONIC, ti);t (int)ti.tv_sec * 1000;t ti.tv_nsec / 1000000;return t;
}// 回调函数用于处理Redis响应
void getCallback(redisAsyncContext *c, void *r, void *privdata) {redisReply reply r;if (reply NULL) return;printf(argv[%s]: %lld\n, (char)privdata, reply-integer);/* 当收到所有回复后断开连接并停止事件循环 */cnt;if (cnt num) {int used current_tick() - before;printf(After %d exec redis commands, used %d ms\n, num, used);redisAsyncDisconnect©;}
}// 连接回调函数
void connectCallback(const redisAsyncContext *c, int status) {if (status ! REDIS_OK) {printf(Error: %s\n, c-errstr);stop_eventloop®;return;}printf(Connected…\n);
}// 断开连接回调函数
void disconnectCallback(const redisAsyncContext *c, int status) {if (status ! REDIS_OK) {printf(Error: %s\n, c-errstr);stop_eventloop®;return;}printf(Disconnected…\n);stop_eventloop®;
}int main(int argc, char **argv) {// 创建Redis异步上下文redisAsyncContext c redisAsyncConnect(127.0.0.1, 6379);if (c-err) {/ 暂时让c泄漏 */printf(Error: %s\n, c-errstr);return 1;}// 创建Reactor对象R create_reactor();// 绑定Reactor对象和Redis异步上下文redisAttach(R, c);// 设置连接和断开回调函数redisAsyncSetConnectCallback(c, connectCallback);redisAsyncSetDisconnectCallback(c, disconnectCallback);// 记录开始时间before current_tick();// 获取自增次数默认为1000num (argc 1) ? atoi(argv[1]) : 1000;// 发送异步自增命令for (int i 0; i num; i) {redisAsyncCommand(c, getCallback, count, INCR counter);}// 运行事件循环eventloop®;// 释放Reactor对象release_reactor®;return 0;
}解释
创建Redis异步上下文使用 redisAsyncConnect 函数连接到 Redis 服务器。创建并绑定Reactor创建一个 Reactor 对象并将其与 Redis 异步上下文绑定以便通过 Reactor 管理 Redis 的事件。设置回调函数 connectCallback处理连接成功或失败的回调。disconnectCallback处理断开连接的回调。getCallback处理每次 INCR counter 命令的响应并在完成所有命令后断开连接。 发送异步命令循环发送 INCR counter 命令不会阻塞主线程。运行事件循环通过 Reactor 的 eventloop 函数处理所有异步事件。释放资源事件循环结束后释放 Reactor 对象。
输出示例
Connected…
argv[count]: 1
argv[count]: 2
…
argv[count]: 1000
After 1000 exec redis commands, used 150 ms
Disconnected…参考
0voice · GitHub
- 上一篇: 电子商务网站开发技术的背景电商平台有哪些
- 下一篇: 电子商务网站开发教程课本例题网站添加icp备案号
相关文章
-
电子商务网站开发技术的背景电商平台有哪些
电子商务网站开发技术的背景电商平台有哪些
- 技术栈
- 2026年03月21日
-
电子商务网站开发过程论文阿里云虚拟主机配置wordpress
电子商务网站开发过程论文阿里云虚拟主机配置wordpress
- 技术栈
- 2026年03月21日
-
电子商务网站开发附件网站子域名什么意思
电子商务网站开发附件网站子域名什么意思
- 技术栈
- 2026年03月21日
-
电子商务网站开发教程课本例题网站添加icp备案号
电子商务网站开发教程课本例题网站添加icp备案号
- 技术栈
- 2026年03月21日
-
电子商务网站开发教程课后答案网站建设的运用场景
电子商务网站开发教程课后答案网站建设的运用场景
- 技术栈
- 2026年03月21日
-
电子商务网站开发实训报告网站一直显示建设中
电子商务网站开发实训报告网站一直显示建设中
- 技术栈
- 2026年03月21日






