文档章节

Redis 网络编程

老汉-憨憨
 老汉-憨憨
发布于 2017/07/25 15:53
字数 712
阅读 8
收藏 1
/**
 * 
 * 基于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
0
360开源的网络编程库--Pink

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

匿名
2016/08/11
919
1
acl 3.1.2 版本发布,网络通信与服务器编程框架

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

郑树新
2015/05/11
1K
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.8K
2
写个准备读研的学弟的Java学习指南

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

u010570551
2017/06/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

github精选:微信小程序开发技巧(12月31日更新)2016

框架部分 所有页面都需要在 app.json 文件中注册在 pages 数组中,注册格式为:"路径/文件名" 注:文件名无需添加扩展名 app.josn 中的 pages 数组中的第一个页面为小程序的启动页 每个页面的...

阿K1225
24分钟前
1
0
OSChina 周日乱弹 —— 小心着凉 @红薯

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子:5.33起,其声呜呜然,如怨如慕,如泣如诉。余音袅袅,不绝如缕。分享Arch Enemy的单曲《Bridge Of Destiny (2009)》 《Bridge Of...

小小编辑
今天
338
4
what f,,

anlve
今天
10
0
初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
今天
15
0
现场看路演了!

HiBlock
昨天
28
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部