最近在一直在看libevent的源码说实在的比较难,主要是开源代码的注解比较少所以细节有时 候不太懂,不过这些不妨碍我们对整个框架的了解。
大体看过源代码后发现整个libevent是采用单线程写的,那么如何使用libevent实现多线程呢?百度后发现memcache的IO事件部分是用libevent实现的所以有看了下memcahce的IO部分。memcache的IO部分采用的,消息+同步队列来实现的。仿照这个模式写了一个简单IO事件程序。服务器端程序如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LISTAE_SOKCET_NUM 3
#define MAX_THREAD 10
struct receive_queue
{
int thread_id;
struct sockaddr receive_addr;
int receivefd;
};
typedef struct
{
int thread_id;
int notify_receive_fd;
int notify_send_fd;
struct event notify_event;
struct event_base *base;
} LIBEVENT_THREAD;
LIBEVENT_THREAD *thread;
struct timeval tv;
struct event main_event;
struct event_base * main_base;
void thread_libevent_process(int fd, short event,void *arg)
{
LIBEVENT_THREAD * me = (LIBEVENT_THREAD *)arg;
fd = me->notify_receive_fd;
char temp[2];
read(fd,temp, 1);
printf("the thread_id is %d and the read data is %c \n", me->thread_id, temp[0]);
}
static void setup_thread(LIBEVENT_THREAD * thread, int idx)
{
int i;
thread->thread_id = idx;
thread->base = event_init();
event_set(&thread->notify_event, thread->notify_receive_fd, EV_READ|EV_PERSIST, thread_libevent_process, thread);
event_base_set(thread->base, &thread->notify_event);
if(event_add(&thread->notify_event,0) == -1)
{
perror("can't add event\n");
exit(0);
}
}
static void *work_thread( void *arg)
{
LIBEVENT_THREAD *me = (LIBEVENT_THREAD *)arg;
event_base_loop(me->base, 0);
}
static void thread_init()
{
int i;
thread =(LIBEVENT_THREAD *)malloc(sizeof(LIBEVENT_THREAD)*MAX_THREAD);
for( i =0; i< MAX_THREAD; i++)
{
pthread_t id;
int fds[2];
if(pipe(fds))
{
perror("cant't create pipe\n ");
exit(0);
}
thread[i].thread_id = i;
thread[i].notify_receive_fd = fds[0];
thread[i].notify_send_fd = fds[1];
setup_thread(&thread[i], i);
pthread_create(&id, NULL, work_thread, &thread[i]);
}
}
int latest_thread_id = 0;
//****************socket create*************************************
int socketcreate()
{
int i;
int fd;
struct sockaddr_in server;
memset(&server, 0, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(8000);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket error\n");
exit(0);
}
if(bind(fd, (struct sockaddr*)&server, sizeof(struct sockaddr)) == -1)
{
perror("bind error\n");
exit(0);
}
if(listen(fd,4)== -1)
{
perror("listen error\n");
exit(0);
}
return fd;
}
void sig_handler(const int sig)
{
printf("receive signal\n");
exit(0);
}
void drive_machine()
{
struct sockaddr recevie_addr1;
socklen_t len;
int stop = 0;
int fd = socketcreate();
signal(SIGINT, sig_handler);
while(!stop)
{
printf("begin accept \n");
int recevie_fd = accept(fd, &recevie_addr1, &len);
if(recevie_fd != -1)
{
int id = (latest_thread_id +1)%MAX_THREAD; //thread chose used in memcache
latest_thread_id++;
write(thread[id].notify_send_fd, "c",1); //notify thread
}
else
{
perror("accept error");
exit(0);
}
}
}
//*************************set timer not used*****************************************
static void dispatch_thread(int fd, short event, void *arg)
{
printf("time wakeup\n");
int id = (latest_thread_id +1)%MAX_THREAD;
latest_thread_id++;
write(thread[id].notify_send_fd, "c", 1 );
tv.tv_sec =2;
tv.tv_usec = 0;
event_add(&main_event, &tv);
}
//*********************************************************************8
int main()
{
thread_init();
/*
tv.tv_sec = 2;
tv.tv_usec = 0;
main_base = event_init();
evtimer_set(&main_event,dispatch_thread, NULL);
event_add(&main_event, &tv);
event_base_loop(main_base, 0);
*/
drive_machine();
return 0;
}
测试程序如下:
#!/usr/bin/python
import time
from socket import *
class socket_create:
time1 = 0
def socket_init(self):
for i in range(1,30):
try:
fd = socket()
host = gethostname()
port = 8000
fd.connect((host,port))
fd.send("hello")
except:
print "socket error"
finally:
fd.close()
self.time1 = self.time1 +1
print "the " + str(self.time1)+"'s " + " time connect"
time.sleep(2)
if __name__ == "__main__":
Connect = socket_create()
Connect.socket_init()
结果: