回显服务器--libevent的使用

<span style="font-size:18px;">1,要使用libevent首先需要安装了,安装地址http://libevent.org/,我选着的1.4稳定版本的了,安装过程就是常用linux安装的3步而已</span>
<span style="font-size:18px;">2,在使用libevent之前,了解一下常用的并发服务器的模型还是有必要的基于事件触发的库,<a target=_blank href="http://blog.csdn.net/sun734274006/article/details/41897487" style="color: rgb(0, 0, 0); text-decoration: none; font-family: 'Microsoft YaHei'; line-height: 30px;">常见多线程与并发服务器设计方案举例</a></span>
<span style="font-size:18px;">3,代码+解释</span>
<pre name="code" class="cpp"><span style="font-size:24px;">/*
* Compile with:
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
*/

#include <sys/types.h>
#include <sys/stat.h>

#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event.h>

#define PORT        54321
#define BACKLOG     20
#define MEM_SIZE    1024

struct event_base* base;  /*其实就是reactor(反应堆),可以形象的比喻为一个总管理,管理所有提供服务的服务者*/

struct sock_ev {
	struct event* read_ev;
	struct event* write_ev;
	char* buffer;
};

//这是为了能够完全整体的释放内存,以前是这样写的,
//如果客户端关闭size==0时候,write_ev,没有得到释放,导致内存泄漏,其实我觉得不用这样封装结构体也可以的,但是封装结构体过后感觉更加面向对象的了的感觉
//void on_read(int sock, short event, void* arg){
//struct event* write_ev;
//    int size;
//     char* buffer = (char*)malloc(MEM_SIZE);
//     bzero(buffer, MEM_SIZE);
//    size = recv(sock, buffer, MEM_SIZE, 0);
//     printf("receive data:%s, size:%d\n", buffer, size);
//    if (size == 0) {
//         event_del((struct event*)arg);
//         free((struct event*)arg);
//         close(sock);
//         return;
//
//			}
//     write_ev = (struct event*) malloc(sizeof(struct event));;
//     event_set(write_ev, sock, EV_WRITE, on_write, buffer);
//     event_base_set(base, write_ev);
//     event_add(write_ev, NULL);
//}

void release_sock_event(struct sock_ev* ev)
{
	event_del(ev->read_ev);
	free(ev->read_ev);
	free(ev->write_ev);
	free(ev->buffer);
	free(ev);
}

void on_write(int sock, short event, void* arg)
{
	char* buffer = (char*)arg;
	send(sock, buffer, strlen(buffer), 0);
	//注意这里需要释放,是在on_read里面malloc的
	free(buffer);
}

void on_read(int sock, short event, void* arg)
{

	int size;
	struct sock_ev* ev = (struct sock_ev*)arg;
	ev->buffer = (char*)malloc(MEM_SIZE);
	bzero(ev->buffer, MEM_SIZE);
	size = recv(sock, ev->buffer, MEM_SIZE, 0);
	printf("receive data:%s, size:%d\n", ev->buffer, size);

	//当从socket读返回0标志对方已经关闭了连接,因此这个时候就没必要继续监听该套接口上的事件,
	//由于EV_READ在on_accept函数里是用EV_PERSIST(持久)参数注册的,因此要显示的调用event_del函数取消对该事件的监听。
	if (size == 0) {
		release_sock_event(ev);
		close(sock);
		return;
	}
	event_set(ev->write_ev, sock, EV_WRITE, on_write, ev->buffer);
	event_base_set(base, ev->write_ev);
	event_add(ev->write_ev, NULL);
}

void on_accept(int sock, short event, void* arg)
{
	struct sockaddr_in cli_addr;
	int newfd, sin_size;

	//这里必须要malloc,因为这个事件最后是要base里面的,如果是栈中分配,这个函数执行接受过后,变量的值被回收过后,在"后面"工作的base,将对一个空的操作,那样会crash
	struct sock_ev* ev = (struct sock_ev*)malloc(sizeof(struct sock_ev));

	ev->read_ev = (struct event*)malloc(sizeof(struct event));
	ev->write_ev = (struct event*)malloc(sizeof(struct event));
	sin_size = sizeof(struct sockaddr_in);
	newfd = accept(sock, (struct sockaddr*)&cli_addr, &sin_size);
	//这里就是,监听这个sock,是否是可读,如果可以折触发on_read函数了,当然这里的event_set函数是系统补推荐的,建议使用event_assign函数具体可以看文档
	event_set(ev->read_ev, newfd, EV_READ | EV_PERSIST, on_read, ev);

	event_base_set(base, ev->read_ev);
	event_add(ev->read_ev, NULL);
}

int main(int argc, char* argv[])
{
	struct sockaddr_in my_addr;
	int sock;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	int yes = 1;

	//这是是需要注意一下,我们在编程的时候,有时候不小心我们使用的文件句柄,
	//资源没有释放,而程序有挂了当我们再次使用的时候,就会出线xxxx被用,这里SO_REUSEADDR,就是让他可以重复利用,具体的看以参考<UNP>
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

	//下面这几行就是长用的步骤啦
	memset(&my_addr, 0, sizeof(my_addr));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(PORT);
	my_addr.sin_addr.s_addr = INADDR_ANY;
	bind(sock, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));
	listen(sock, BACKLOG);

	struct event listen_ev;   /*它就是直接提供服务的,它呗 base管理*/

	base = event_base_new();  

	//将我们监听的sock,绑定在listen_ev,即使让listen_ev帮我们管理,我们之处理,请求的到来,请求到来了将触发on_accept函数
	event_set(&listen_ev, sock, EV_READ | EV_PERSIST, on_accept, NULL);

	event_base_set(base, &listen_ev);

	event_add(&listen_ev, NULL);

	//循环调用,就像服务器要一直运行吧,一旦有新的请求过来或者请求的I/O时候会调用处理
	event_base_dispatch(base);

	return 0;
}</span>

</pre><pre name="code" class="cpp">
时间: 2024-10-18 03:31:55

回显服务器--libevent的使用的相关文章

epoll 回显服务器源码

在写epoll回显服务器代码之前,可以先看看上一篇文章:select poll epoll三者之间的比较.最近在继续学习网络编程中的服务端编程中,了解到很多网游服务器是在IOMP(IO完成端口)框架下写的,但是这种方式只能在 Windows 下使用,奇了怪了,这么好的东西为什么不在Linux下也实现一套呢?这个问题我继续学习IOMP再来谈一谈! epoll是linux下高并发服务器的完美方案,因为是基于事件触发的,所以比select快的不只是一个数量级.单线程epoll,触发量可达到15000,

Python网络编程——编写一个简单的回显客户端/服务器应用

今天将python中socket模块的基本API学习完后,照着书上的实例编写一个套接字服务器和客户端.采用python3.5版本,在注释中会标明python2和python3的不同之处. 1.代码 (1)服务器端及对应代码解释 1 # ! /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # 编写回显服务器 4 5 import socket 6 import sys 7 import argparse 8 9 # 定义常量 10 host = 'l

使用Jersey构建图片服务器 有回显图片功能

1.前台界面代码 <form id="jvForm" action="add.do" method="post" enctype="multipart/form-data"> <table> <tr> <td width="20%" class="pn-flabel pn-flabel-h"></td> <td width

服务器libevent bufferevent 初窥

1,最近在学习libevent,记录一下学习过程了,于是简单的一个服务器,回显而已 2,代码 #include <iostream> #include <stdlib.h> #include <event.h> #include <sys/stat.h> #include <string.h> #include <netinet/in.h> #include <sys/socket.h> #include <netd

SpringMVC框架下数据的增删改查,数据类型转换,数据格式化,数据校验,错误输入的消息回显

在eclipse中javaEE环境下: 这儿并没有连接数据库,而是将数据存放在map集合中: 将各种架包导入lib下... web.xml文件配置为 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/

7、struts2 案例( 模型驱动、 防止表单重复提交--拦截器 、数据回显 、值栈 、 OGNL表达式综合运用)

struts2 案例 技术点: 模型驱动 防止表单重复提交–拦截器 数据回显 值栈 OGNL表达式 通配符.路径匹配原则.常量 数据处理的集中方式 请求数据自动封装以及类型转换 1.导包 c3p0-0.9.1.2.jar commons-dbutils-1.6.jar commons-fileupload-1.2.2.jar commons-io-2.0.1.jar commons-lang3-3.1.jar freemarker-2.3.19.jar javassist-3.11.0.GA.j

上传图片至fastdfs分布式文件系统并回显

事件,当我们浏览完图片选中一张时,触发onchange事件将图片上传到服务器并回显. 1 <img width="100" height="100" id="allUrl" src="${brand.imgUrl }"/> 2 <input type="hidden" name="imgUrl" id="imgUrl" value="${b

如何用input标签上传多个图片并回显

本文主要记录如何用input标签和jquery实现多图片的上传和回显,不会涉及后端的交互,大概的效果看图 我们从零来做一个这样的demo 第一步: 我们先完善一下我们的页面,默认的input-file标签非常丑,我们美化一下它,不会的可以百度一下,就是外面套个盒子,设置input的opacity为0,然后外面的盒子设计成我们喜欢的样式即可,我就随便做了一下. 还是放一下源码,只谈效果,不放源码的都是耍流氓 这是body <body> <div class="uploadImgB

图片上传并回显后端篇

图片上传并回显后端篇 我们先看一下效果 继上一篇的图片上传和回显,我们来实战一下图片上传的整个过程,今天我们将打通前后端,我们来真实的了解一下,我们上传的文件,是以什么样的形式上传到服务器,难道也是一张图片?等下我们来揭晓 我们在实战开始前呢,我们先做一下准备工作,比如新建一个java web工程,如果你不懂这个的话,那我建议你先学一下Javaweb,可以去我的公众号找一下这方面的教程.我们就给我们的工程起名为UpImg,我们再给他建一个web包和util包,再把我们以前前端做的图片回显的代码拷