网络通信引擎--C++ 与 lua

10 篇文章 0 订阅
7 篇文章 0 订阅

最近想做一个网信引擎 想要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)
{


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值