之前的程式,都是一個 connect 一個 thread , 在連線不多情況下還 ok , 但是萬一
需要處理上千個 connection ? 例如 , clients 透過 socket 來取得 行情 , 此時, 你的
server 可能 處理一千個連線, 這些連線絕大部分是 recv 行情資料 , 小部份是 send 所要取得行情的股票代碼!!
方法是使用 epoll , 我測試 epoll 最不習慣的地方在於, 如果你的程式需要 clients 先送上四碼代表資料長度,
後面再送上真正的資料,由於 tcp/ip 是 stream-based protocal , 所以就算是那四碼都有可能被分成兩次封包傳送 !!
一個 connect 一個 thread 的 程式,只要使用 之前我寫的介面,直到收到整整四個 bytes再return 的 function 即可 ,
然而 , epoll 這種 event-driven 程式 , 對於處理這種資料流傳一半的情況要花多點時間,且容易有 bug ,
使用 libevent library 這問題變的非常容易解決 , 先看一段程式碼 :
void read_cb(struct bufferevent *bev, void *arg)
{
char record[256] ;
int idy,n;
evutil_socket_t fd = bufferevent_getfd(bev);
struct evbuffer *input = bufferevent_get_input(bev);
int ifieldwidth = 0 ;
ifieldwidth = sizeof(DataFeedClient[0].ordid[0]) ; //"|" included
while(1)
{
size_t len = evbuffer_get_length(input);
//printf("fd=(%u),len=(%d)\n",fd,len) ;
size_t leftlen = len ;
while(1)
{
if(leftlen >= ifieldwidth)
{
evbuffer_copyout(input, record, ifieldwidth);
record[ifieldwidth-1]=0x00 ; //take off "|"
//printf("(%s)\n",record) ;
evbuffer_drain(input,ifieldwidth);
leftlen = leftlen - ifieldwidth ;
if(strncmp(record,"START",5)==0)
{
++DataFeedClient[fd].seqno1 ;
DataFeedClient[fd].fillarridx = 0 ;
for(idy=0;idy<MAXORDID;idy++){
memset(DataFeedClient[fd].ordid[idy],0x00,
sizeof(DataFeedClient[0].ordid[0]) ) ;
}//for
}
else if(strncmp(record,"END",3)==0)
{
++DataFeedClient[fd].seqno2 ;
printdatafeed(fd) ;
}else{
if(DataFeedClient[fd].fillarridx <= (MAXORDID -1) )
strcpy(DataFeedClient[fd].ordid[DataFeedClient[fd].fillarridx],record) ;
++DataFeedClient[fd].fillarridx ;
}
}else //if
break ;
}//while
break ;
}
//printf("out of while \n") ;
}
你只要每次都去 get_length , 未滿 4 就跳出 , 滿四的話,不先取出來,例如這四碼是 "0100" , 表示資料長度是 100 ,
所以直到 get_length >= 104 , 才將資料取出 , 這樣處理方便太多了 !!!
copyout 是將資料 copy 出來 , drain 把資料給從 buffer 刪除 , libevent 在 buffer 處理比起自己使用 epoll 處理每個
connect buffer 實在容易的多了 !!!
留言列表