文档章节

Redis 网络编程

老汉-憨憨
 老汉-憨憨
发布于 2017/07/25 15:53
字数 712
阅读 8
收藏 1
点赞 0
评论 0
/**
 * 
 * 基于Redis网络事件框架Demo
 * 
 * @author xushun
 * 
 *  email : xushun007@gmail.com
 */


#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include "ae.h"
#include "anet.h"


#define MAX_LEN 10240
#define MAX_REQUEST_SIZE 5120

#define PORT 23456
#define IP_ADDR_LEN 40

#define TIMER_LOOP_CYCLE 10000

// 读数据状态
#define OK 0
#define ERR -1
#define NO_READY 1

// 存放错误信息的字符串
char g_err_string[MAX_LEN];

// 事件循环体
aeEventLoop *g_event_loop = NULL;

// 客户端结构体
typedef struct client {
	int fd;                    // 文件描述符
	char ipaddr[IP_ADDR_LEN];  // client IP 地址
	int port;                  // 端口
	char request[MAX_LEN];     // 客户端请求字符串
	char response[MAX_LEN];    // 响应字符串
	int len;                   // 缓冲长度
	int rsplen;
}client_t;

client_t* createClient() {
	client_t* c = malloc(sizeof(client_t));
	if(c == NULL) {
		fprintf(stderr, "alloc mem failure.");
		exit(1);
	}
	c->fd = -1;
	c->len = 0;
	c->rsplen = 0;
	return c;
}

// 定时器
int PrintTimer(struct aeEventLoop *eventLoop, long long id, void *clientData)
{
	static int i = 0;
	printf("Timer: %d\n", i++);
	// TIMER_LOOP_CYCLE/1000 秒后再次执行该函数
	return TIMER_LOOP_CYCLE;
}

//停止事件循环
void StopServer()
{
	aeStop(g_event_loop);
}

// 客户退出处理函数
void ClientClose(aeEventLoop *el, client_t* c, int err)
{
	//如果err为0,则说明是正常退出,否则就是异常退出
	if( 0 == err )
		printf("Client quit: %d\n", c->fd);
	else if( -1 == err )
		fprintf(stderr, "Client Error: %s\n", strerror(errno));

	//删除结点,关闭文件
	aeDeleteFileEvent(el, c->fd, AE_READABLE);
	close(c->fd);
	free(c);
}

// 响应客户
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {	
	client_t* c = privdata;
	int nwritten = c->rsplen;
	int res, sentlen = 0;
	
	printf("Request From %s:%d : %s\n", c->ipaddr, c->port, c->response);
	while(nwritten) {
	    res = write(fd, c->response + sentlen, c->rsplen - sentlen);

	    // 写入出错
	    if (res == -1) {
		if (errno == EAGAIN) {
		    continue;
		} else {
		    fprintf(stderr, "send response to client failure.\n");
		    ClientClose(el, c, res);
		}
	    }
            
            nwritten -= res;
            sentlen += res;

            if (sentlen == c->rsplen) {
                c->rsplen = 0;
            }
	}

	aeDeleteFileEvent(el,c->fd,AE_WRITABLE);
}

int processBuffer(aeEventLoop *el, client_t* c, int res) {
	char *newline = strstr(c->request,"\r\n");
	int reqlen;	

	if(newline == NULL) {
		if(c->len > MAX_REQUEST_SIZE) {
			fprintf(stderr,"Protocol error: too big request");
			ClientClose(el, c, res);
			return ERR;
		}
		return NO_READY;
	}

	reqlen = newline - c->request + 2;
	memcpy(c->response, c->request, reqlen);
	c->rsplen = reqlen;
	c->len -= reqlen;
	if(c->len)
		memmove(c->request, c->request+reqlen, c->len);

	return OK;
}

// 读取客户端数据
void ReadFromClient(aeEventLoop *el, int fd, void *privdata, int mask)
{
	int res;
	client_t* c = privdata;
	res = read(fd, c->request + c->len, MAX_LEN - c->len);
	if( res <= 0 )
	{
		ClientClose(el, c, res);
		return;
	}
	c->len += res;	
	
	if(processBuffer(el, c, res) == OK) {
		if(aeCreateFileEvent(el, fd, AE_WRITABLE, sendReplyToClient, c) == AE_ERR)  {
			fprintf(stderr, "Can't Register File Writeable Event.\n");
			ClientClose(el, c, res);
		}			
	}
	
}



//接受新连接
void AcceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask)
{
	client_t* c = createClient();

	c->fd = anetTcpAccept(g_err_string, fd, c->ipaddr, &c->port);
	if(c->fd == ANET_ERR) {
		fprintf(stderr, "Accepting client connection: %s", g_err_string);
		free(c);
		return;	
	}
	printf("Connected from %s:%d\n", c->ipaddr, c->port);
	
	if( aeCreateFileEvent(el, c->fd, AE_READABLE, ReadFromClient, c) == AE_ERR )
	{
		fprintf(stderr, "Create File Event fail: fd(%d)\n", c->fd);
		close(c->fd);
                free(c);
	}
}

int main()
{

	printf("Start\n");

	signal(SIGINT, StopServer);

	//初始化网络事件循环
	g_event_loop = aeCreateEventLoop(1024*10);

	//设置监听事件
	int fd = anetTcpServer(g_err_string, PORT, NULL);
	if( ANET_ERR == fd )
		fprintf(stderr, "Open port %d error: %s\n", PORT, g_err_string);
	if( aeCreateFileEvent(g_event_loop, fd, AE_READABLE, AcceptTcpHandler, NULL) == AE_ERR )
		fprintf(stderr, "Unrecoverable error creating server.ipfd file event.");

	//设置定时事件
	aeCreateTimeEvent(g_event_loop, 1, PrintTimer, NULL, NULL);

	//开启事件循环
	aeMain(g_event_loop);

	//删除事件循环
	aeDeleteEventLoop(g_event_loop);

	printf("End\n");
	return 0;
}

Makefile:

objects = ae.o ae_epoll.o anet.o main.o
server : $(objects) 
	gcc -o server $(objects)

$(objects) : ae.h anet.h

ae.o : ae.c
ae_epoll.o : ae_epoll.c
anet.o : anet.c
mian.o : mian.c

clean :
	rm server $(objects)

 

本文转载自:https://github.com/microheart/Redis_Event_Demo

共有 人打赏支持
老汉-憨憨
粉丝 18
博文 322
码字总数 68382
作品 0
深圳
程序员
【推荐】我的书单(Book List)

下面列了我读过的一些编程相关的书籍,写了一些对书的印象,都是个人观点。书名后是我个人对书的推荐强烈度打的分(10分满分),都是拍脑袋打的。 我比较习惯读纸质书,买书也比较谨慎,踩的...

枕边书 ⋅ 01/10 ⋅ 0

acl 3.1.2 版本发布,网络通信与服务器编程框架

acl3.1.2 版本发布了,acl 是 one advanced C/C++ library的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个acl项目主要包含三个函数...

郑树新 ⋅ 2015/05/11 ⋅ 6

acl 网络通信服务器框架 3.1.0 版本发布

acl 3.1.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个 acl 项目主要包含三个...

郑树新 ⋅ 2015/02/08 ⋅ 2

360开源的网络编程库--Pink

Pink是360开源的网络编程库,支持 pb、Redis 等协议。对网络编程的封装,用户实现一个高性能的 server 只需要实现对应的 DealMessage 函数即可。 支持单线程模型、多线程 worker 模型。...

匿名 ⋅ 2016/08/11 ⋅ 1

写个准备读研的学弟的Java学习指南

java开发需要看的书籍 Java编程思想 深入理解Java虚拟机 Java多线程编程的艺术 HeadFirst设计模式 Java并发编程实践战 Spring实战第4版 深入浅出Mybatis原理技术与实战 Effective Java Java性...

u010570551 ⋅ 2017/06/11 ⋅ 0

缓存系列文章--7.无底洞问题(multiget hole)

转载请注明出处哈:http://carlosfu.iteye.com/blog/2269678 最近有点忙,一直没更新博客,继续坚持下去。 一、背景 1. 什么是缓存无底洞问题: 他们发现一个问题--memcached的连接效率下降了...

付磊-起扬 ⋅ 2015/12/14 ⋅ 0

acl 3.1.1 版本发布,跨平台网络通信与服务器框架

acl 3.1.1 版本发布了,acl 是 one advanced C/C++ library的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个acl项目主要包含三个函...

郑树新 ⋅ 2015/03/30 ⋅ 0

acl redis C++ 库被 redis 官方收录

acl 库中的新增模块 redis C++ 客户端库被 redis 官方正式收录,参见 http://redis.io/clients 中的 C++ 部分,其中 “redis-client for C++” 库即为 acl redis C++ 客户端库。acl 中的 re...

郑树新 ⋅ 2015/03/09 ⋅ 10

Go语言中实现基于 event-loop 网络处理

Go语言中实现基于 event-loop 网络处理 鸟窝2017-11-291 阅读 Go 我们知道, Go语言为并发编程提供了简洁的编程方式, 你可以以"同步"的编程风格来并发执行代码, 比如使用 关键字新开一个g...

鸟窝 ⋅ 2017/11/29 ⋅ 0

双11Java程序员书单推荐

Java 《Java核心技术卷I》 《Java核心技术卷II》 《Java编程思想》 《Java并发编程实战》 《Effective Java》 《Java8实战》 《Java8函数式编程思维》 《深入理解Java虚拟机》 《Java性能权威...

黄步欢 ⋅ 2017/11/04 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java NIO之字符集

1 字符集和编解码的概念 首先,解释一下什么是字符集。顾名思义,就是字符的集合。它的初衷是把现实世界的符号映射为计算机可以理解的字节。比如我创造一个字符集,叫做sex字符集,就包含两个...

士别三日 ⋅ 31分钟前 ⋅ 0

Spring Bean基础

1、Bean之间引用 <!--如果Bean配置在同一个XML文件中,使用local引用--><ref bean="someBean"/><!--如果Bean配置在不同的XML文件中,使用ref引用--><ref local="someBean"/> 其实两种......

霍淇滨 ⋅ 36分钟前 ⋅ 0

05、基于Consul+Upsync+Nginx实现动态负载均衡

1、Consul环境搭建 下载consul_0.7.5_linux_amd64.zip到/usr/local/src目录 cd /usr/local/srcwget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip 解压consu......

北岩 ⋅ 39分钟前 ⋅ 0

Webpack 4 api 了解与使用

webpack 最近升级到了 v4.5+版 01 官方不再支持 node4 以下版本 官方不再支持 node4 以下版本官方不再支持 node4 以下的版本,所以如果你的node版本太低,先开始升级node吧!话说node10 ...

NDweb ⋅ 48分钟前 ⋅ 0

使用nodeJs安装Vue-cli

Vue脚手架就是一个Vue框架开发环境 脚手架的意思是帮你快速开始一个vue的项目,也就是给你一套vue的结构,包含基础的依赖库,只需要 npm install就可以安装,让我们不需要为了编辑或者一些其...

木筏笔歆 ⋅ 今天 ⋅ 0

【微信小程序开发实战】0x00.开发前准备工作

写在开始 本人资深后端码农一枚,近期项目需求,接触到了微信小程序,将学习过程整理成文分享给小伙伴们,由于是边学边整理难免有表述不对的地方,望大家及时指正,感谢。 本人微信号: dream...

dreamans ⋅ 今天 ⋅ 0

linux redis的安装和php7下安装redis扩展

安装redis服务器 (1)下载安装包: $ wget http://download.redis.io/releases/redis-2.8.17.tar.gz (2)编译程序: $ tar xzf redis-2.8.17.tar.gz $ cd redis-2.8.17 $ make $ cd src &&......

concat ⋅ 今天 ⋅ 0

Guava EventBus源码解析

一、EventBus使用场景示例 Guava EventBus是事件发布/订阅框架,采用观察者模式,通过解耦发布者和订阅者简化事件(消息)的传递。这有点像简化版的MQ,除去了Broker,由EventBus托管了订阅&...

SaintTinyBoy ⋅ 今天 ⋅ 0

http怎么做自动跳转https

Apache 版本 如果需要整站跳转,则在网站的配置文件的<Directory>标签内,键入以下内容: RewriteEngine on RewriteCond %{SERVER_PORT} !^443$ RewriteRule ^(.*)?$ https://%{SERVER_NAME......

Helios51 ⋅ 今天 ⋅ 0

Python爬虫,抓取淘宝商品评论内容

作为一个资深吃货,网购各种零食是很频繁的,但是能否在浩瀚的商品库中找到合适的东西,就只能参考评论了!今天给大家分享用python做个抓取淘宝商品评论的小爬虫! 思路 我们就拿“德州扒鸡”...

python玩家 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部