最近想做一个网信引擎 想要C++结合lua 来写 ,C++层用epoll ,lua 层来进行逻辑处理 ,后期想加上protobuf .
可能引擎刚开始还是很初级,本人想不断将期完善 ,满足其本的功能。
1. 写一个lua解释器程序, 比如 test test.lua
test 是一个可执行文件,与lua 文件进行交互,test接受数据,交给lua 代码来进行逻辑处理,lua 将处理结果返回给C++层,test将处理后的数据发送给相应的连接。
2.C++ 这一块 用epoll ,不断地接受客户端的连接与数据 ,刚开始直接用单线程,后面可能会用线程池,任务队列,来保证稳定性。
=========> 后来发现用单线程不行,在收到epollIN 消息时,来解析数据包,或者做其他操作,可能耗时较长,从而形成阻塞的情况,因为ET模式,有阻塞的情况,后面的连接就没法连接上,而没丢弃。找了好久,终于发现用线程池,信号量、加锁可以解决这种情况。在后面会贴出代码
struct task{
int fd; //需要读写的文件描述符
struct task *next; //下一个任务
};
//线程的任务函数
void * readtask(void *args);
pthread_mutex_t mutex;
pthread_cond_t cond1;//目标条件变量
struct task *readhead=NULL,*readtail=NULL,*writehead=NULL;
pthread_t tid1,tid2;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond1,NULL);
//初始化用于读线程池的线程
pthread_create(&tid1,NULL,readtask,NULL);
pthread_create(&tid2,NULL,readtask,NULL);
if (events[i].events & EPOLLIN)
{
if ( sockfd < 0) continue;
new_task=new task();
new_task->fd=sockfd;
new_task->next=NULL;
//添加新的读任务
pthread_mutex_lock(&mutex);
if(readhead==NULL)
{
readhead=new_task;
readtail=new_task;
}
else
{
readtail->next=new_task;
readtail=new_task;
}
//唤醒所有等待cond1条件的线程
pthread_cond_broadcast(&cond1);
pthread_mutex_unlock(&mutex);
}
static int count111 = 0;
void * readtask(void *args)
{
int fd=-1;
unsigned int n;
//用于把读出来的数据传递出去
while(1){
pthread_mutex_lock(&mutex);
//等待到任务队列不为空
while(readhead==NULL) // 当连接的链表为空时
pthread_cond_wait(&cond1,&mutex); // 等待条件变量
fd=readhead->fd;
//从任务队列取出一个读任务
struct task *tmp=readhead;
readhead = readhead->next;
delete tmp;
pthread_mutex_unlock(&mutex);
data = new user_data();
data->fd=fd;
char recvBuf[1024] = {0};
int ret = 999;
int rs = 1;
while(rs)
{
ret = recv(fd,recvBuf,1024,0);// 接受客户端消息
cout <<"the data recv ret = " << ret <<endl;
if (ret > 0 )
{
recvBuf[ret] = '\0';
string data = recvBuf;
//数据的解析
demo::People p;
p.ParseFromString(data);
cout << "People: " << endl;
cout << "Name: " << p.name() << endl;
cout << "ID: " << p.id() << endl;
cout << "Email: " << p.email() << endl;
}
if(ret < 0)
{
//由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可//读在这里就当作是该次事件已处理过。
if(errno == EAGAIN)
{
printf("EAGAIN\n");
break;
}
else{
printf("recv error!\n");
close(fd);
break;
}
}
else if(ret == 0)
{
// 这里表示对端的socket已正常关闭.
rs = 0;
}
if(ret == sizeof(recvBuf))
rs = 1; // 需要再次读取
else
rs = 0;
}
if(ret>0){ //返回数据
char buf[1000] = {0};
sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");
send(fd,buf,strlen(buf),0);
close(fd);
}
}
}
http://blog.chinaunix.net/uid-1849361-id-2825417.html
http://blog.chinaunix.net/uid-311680-id-2439722.html
3. protobuf 数据的解析 是放在C++ 这层还是在 lua 层 着实让人有点为难 ,暂时没想到的办法,后期找到了会更新到csdn
-- 设置服务器端口与ip
function setServerForEpoll(port,ip)
end
对应的C++ 代码
lua_State* L;
const char * ip = NULL ; --- 作为全局变量
int port = 0;
static int setServerForEpoll( lua_State *L )
{
int n=lua_gettop(L);
cout << "====>" <<n <<endl;
if (lua_isstring(L,1))
{
ip = lua_tostring(L,1);
cout << ip <<endl;
}
if(lua_isnumber(L,2))
{
port = lua_tonumber(L,2);
cout << port <<endl;
}
return 0; --- 返回数为0
}
-- 对接受的消息做处理
function onReadData(data,sockfd,cmd)
print("=================>",data.Name,data.ID,sockfd,cmd);
return 100;
end
C++ 代码如下
lua_getglobal(L,"onReadData");//压入函数名
lua_newtable(L); //压入一个table {Name: ,ID: ,Email: }
lua_pushstring(L, "Name");
lua_pushstring(L, p.name().c_str());
lua_settable(L, -3);
lua_pushstring(L, "ID");
lua_pushnumber(L, 123 );
lua_settable(L, -3);
lua_pushstring(L, "Email:");
lua_pushstring(L, p.email().c_str());
lua_settable(L, -3);
lua_pushnumber(L,sockfd);
int cmd = 1001;
lua_pushnumber(L,cmd);
lua_pcall(L,3,1,0);
int num =(int)lua_tonumber(L,-1);//处理返回值
cout << num <<endl;
lua_pop(L,1);
如是是返回一个table 代码下次会贴出来
function sendData(sockfd, data ,cmd)
{
}
--- 消息群发
function sendToAll(data,cmd)
{
}
--- 得到当前连接的句柄
function getSockfd(cmd)
{
}