程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用多路復用I/O模型實現支持多個客戶端的通信服務

用多路復用I/O模型實現支持多個客戶端的通信服務

編輯:關於VC++

引言

多路復用I/O模型是UNIX/LINUX用得的最多的一種I/O模型。這種I/O模型在技術上的實現是包括select()以及FD_XXX的幾個宏及常量。在單個進程中支持的客戶端數量由FD_SETSIZE決定。Solaris 10和Linux 9.0默認為1024個,Windows 2000是64個。本文用代碼給出該I/O模型處理多Client的一種實現。

用select開發一個通信服務器

這個服務器包括接收模塊、發送模塊和套接口管理模塊。我們只演示與select實現有關的部分,即接收模塊和套接口管理模塊。下面服務器類關系圖:

tcp_listen是tcp實現監聽功能,tcp_comm實現tcp的發送和接收,下在我們重點在於recv和sock_list這兩個類。sock_list定義如下:

class sock_list
{
public:
// 功能:將一個值插入到list的尾部
// 參數:要插入的tcp_comm對象
void insert(tcp_comm* t);
// 功能:刪除一個指定的元素
// 參數:指向要刪除的tcp_comm對象的指針
void remove(tcp_comm* t);
// 功能:從隊列取得所有的元素
// 參數:存放指向tcp_comm對象指針的向量
void get_all(std::vector<tcp_comm*>& vec);
private:
std::list<tcp_comm*> _sock_list;
};

sock_list實現tcp_comm對象的管理。下面我們來看recv類的定義:

class recv
{
public:
// 功能: 啟動通信服務
bool start();
private:
// 功能: 接收核心函數,通過多路復用支持多個客戶端
// 返回值: 正常, 0; 失敗,-1
int do_select();

// 初始化套接口集合
void init_readfds(const vector<tcp*>& vec, fd_set* set);
private:
sock_list* _list;
tcp_listen* _listen; // 監聽套接口
};

start()是給外部調用的:創建監聽套接口對象;監聽;執行do_select()。init_readfds將監聽套接口對象和socket_list中的通信套接口對象加入到套接口讀套接口集合中。do_select()比較重要,流程:

用init_readfds初始化讀套接口集合;

執行select(),返回進行到下一步;

先檢測監聽套接口是否有連接到來,並將新的連接加入到sock_list中;

再檢測sock_list中的套接口是否有數據可接收。

實現代碼:

int recv::do_select()
{
fd_set readfds;
int listen = _listen->get_handle();
while (true)
{
vector<tcp_comm*> vec;
_list->get_all(vec);  // 獲得sock_list中的所有套接口句柄
init_readfds(vec, &readfds);
select(...);
// 檢查監聽套接字句柄,有新的連接到,建立新的連接
if (FD_ISSET(listen, &readfds)) 
{
tcp_comm* client = new tcp_comm;
_listen->accept(*client);
_list->insert(client);// 將已連接的套接字對象放到sock_list中
}
// 檢查所有的客戶端套接字句柄
vector<tcp_comm*>::iterator it;
for (it = vec.begin(); it != vec.end(); it++)
{
if (FD_ISSET((*it)->get_handle(), &readfds))
// 這裡是*it作為參數進行數據接收
}
}
}

為減少代碼量,我省去了出錯處理、細節;本來類都在某個名稱空間中的,也省去了。

多進程(線程)和select合作

上面是在一個進程中的情況,可以考慮多線程中每一個線程實現select。以solaris 10為例,開100個線程,一個線程支持1024個套接口,那就是100 * 1024,10萬個。集群服務中的前端均衡器的實現可以考慮一下這個技術,不過效率將是一個極大的考驗。

結論

本文重點講述在單進程的環境使用select支持多個客戶端。經常看見一些服務程序,用到了select也是來一個連接,fork一個子進程處理。在單進程中處理多個客戶端的目的是使開發的程序更易理解、維護;多進程往往較單進程復雜些。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved