[英]Context independent C++ TCP Server Class
我正在基於I / O復用(選擇)方式對TCP Server類進行編碼。 下面的代碼段解釋了基本思想:
GenericApp.cpp
TServer *server = new Tserver(/*parameters*/);
server->mainLoop();
就目前而言,服務器的行為與上下文無關,但以某種方式可以改善。
實際狀態
receive(sockFd , buffer);
MSGData * msg= MSGFactory::getInstance()->createMessage(Utils::getHeader(buffer,1024));
EventHandler * rightHandler =eventBinder->getHandler(msg->type());
rightHandler->callback(msg);
在這個版本中,主循環從套接字讀取,實例化正確類型的消息對象並調用適當的處理程序(某些東西可能無法正常工作,因為它可以編譯,但我尚未對其進行測試)。 如您所見,這允許程序員定義其消息類型和適當的處理程序,但是一旦主循環啟動,就無法執行任何操作。 我需要使服務器的這一部分更具可定制性,以使此類適合更多的問題。
MainLoop代碼
void TServer::mainLoop()
{
int sockFd;
int connFd;
int maxFd;
int maxi;
int i;
int nready;
maxFd = listenFd;
maxi = -1;
for(i = 0 ; i< FD_SETSIZE ; i++) clients[i] = -1; //Should be in the constructor?
FD_ZERO(&allset); //Should be in the constructor?
FD_SET(listenFd,&allset); //Should be in the constructor?
for(;;)
{
rset = allset;
nready = select (maxFd + 1 , &rset , NULL,NULL,NULL);
if(FD_ISSET( listenFd , &rset ))
{
cliLen = sizeof(cliAddr);
connFd = accept(listenFd , (struct sockaddr *) &cliAddr, &cliLen);
for (i = 0; i < FD_SETSIZE; i++)
{
if (clients[i] < 0)
{
clients[i] = connFd; /* save descriptor */
break;
}
}
if (i == FD_SETSIZE) //!!HANDLE ERROR
FD_SET(connFd, &allset); /* add new descriptor to set */
if (connFd > maxFd) maxFd = connFd; /* for select */
if (i > maxi) maxi = i; /* max index in client[] array */
if (--nready <= 0) continue;
}
for (i = 0; i <= maxi; i++)
{
/* check all clients for data */
if ( (sockFd = clients[i]) < 0) continue;
if (FD_ISSET(sockFd, &rset))
{
//!!SHOULD CLEAN BUFFER BEFORE READ
receive(sockFd , buffer);
MSGData * msg = MSGFactory::getInstance()->createMessage(Utils::getHeader(buffer,1024));
EventHandler * rightHandler =eventBinder->getHandler(msg->type());
rightHandler->callback(msg);
}
if (--nready <= 0) break; /* no more readable descriptors */
}
}
}
您對執行此操作的好方法有任何建議嗎? 謝謝。
您的問題不僅需要堆棧溢出問題。 您可以在這些書中找到好的想法:
基本上,您想要做的是reactor
。 您可以找到實現此模式的開源庫。 例如:
如果您希望處理程序能夠進行更多處理,則可以為它們提供對TCPServer的引用,以及為以下事件注冊套接字的方式:
read
,套接字已准備好讀取 write
,套接字准備寫 accept
,監聽套接字已經准備好接受(用select
讀取) close
,插座關閉 timeout
,等待下一個事件的時間已過期( select
允許以指定超時) 使處理程序可以實現各種協議half-duplex
或full-duplex
:
write
事件的作用,它使處理程序知道何時可以在套接字上發送。 read
事件也是如此。 它不應在主循環中,而應在套接字read
處理程序中。 timeout
注冊事件處理程序的可能性,以便可以實現timers
並刪除空閑連接。 這會導致一些問題:
state-machine
,以對網絡事件做出反應並更新它想要接收的事件。 queue
進行通信。 之所以需要該隊列,是因為一個套接字的就緒與另一個套接字的就緒無關。 而且您可能會在一個上閱讀某些內容,而沒有准備好在另一個上發送它。 priority queue
如您所見,這不是簡單的問題。 您可能希望減少框架的通用性以簡化其設計。 (例如僅處理half-duplex
協議,例如簡單HTTP)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.