1、標頭檔案
#include #include #ifdef _windows
#pragma comment(lib,"ws2_32.lib") //socket程式設計需用的動態鏈結庫
#pragma comment(lib,"kernel32.lib") //iocp需要用到的動態鏈結庫
#endif
//log_view->log(str, ...) 功能:輸出日誌到介面
2、載入套接字型檔
bool iocpserver::loadsockdll()
if (lobyte(wsa.wversion) != 2 || hibyte(wsa.wversion) != 2)
return true;
}
3、建立iocp+建立iocp工作執行緒
bool iocpserver::initiocp()
log_view->log("建立iocp處理執行緒...");
system_info info;
getsysteminfo(&info);
for (int i = 0; i < info.dwnumberofprocessors*2; ++i)
return true;
}
createiocompletionport引數說明:
param:有效的檔案控制代碼 或 invalid_handle_value(一般用這個)
param:null(新建iocp時)
param:0。
param:作業系統允許同時處理i/o完成埠資料報的最大執行緒數,如果此引數為零,則最大執行緒數等於cpu數量。
建立的工作執行緒數量為cpu數量*2,考慮到執行緒查詢修改資料庫時有等鎖的情況,多餘的執行緒可以替補。
4、建立socket、繫結、監聽+建立接收客戶端連線請求執行緒
bool iocpserver::initsocket(const string& ip, unsigned short port)
log_view->log("繫結");
sockaddr_in addr;
addr.sin_family = af_inet;
addr.sin_port = htons(port);
addr.sin_addr.s_un.s_addr = inet_addr(ip.c_str());
if(0 != ::bind(m_socket, (sockaddr*)&addr, sizeof(addr)))
log_view->log("監聽");
if (0 != listen(m_socket, 100))
log_view->log("建立accept執行緒");
m_accpetthread = new thread(std::bind(&iocpserver::acceptproc, this));
return true;
}
5、接收客戶端連線請求執行緒
void iocpserver::acceptproc()
//將iocp埠與客戶端socket繫結
createiocompletionport((handle)clientsocket, m_iocp, (ulong_ptr)clientsocket, 0);
//通知新增連線,收到通知的模組處理為客戶端建立會話物件
string ip = inet_ntoa(addr.sin_addr);
unsigned short port = htons(addr.sin_port);
if (!m_notify->addconnect(clientsocket, ip, port))
//為客戶端投遞接收請求
siocpcontent* ct = new siocpcontent(buff_len, eiocptype::iocprecv);
if (!deliveryrecvrequest(clientsocket, ct))
}log_view->log("accept執行緒自然退出");
}
createiocompletionport引數說明:
param:有效的檔案控制代碼 或 invalid_handle_value,這裡用客戶端socket
param:現有i/o完成埠的控制代碼(與socket繫結時)
param:傳送給處理函式的引數,即傳給getqueuedcompletionstatus第三個引數
param:作業系統允許同時處理i/o完成埠資料報的最大執行緒數,如果此引數為零,則最大執行緒數等於cpu數量。
6、iocp工作執行緒
void iocpserver::workerproc(int tag)
else} }
log_view->log("iocp執行緒[%d]自然退出", tag);
}
getqueuedcompletionstatus引數說明
param:之前建立的iocp埠
param:收到的資料長度
param:iocp埠與socket繫結時,createiocompletionport的第三個引數
param:投遞請求時,createiocompletionport的第六個引數,是個指標
param:等待通知的時間,infinite即一直等
7、為客戶端投遞接收請求
bool iocpserver::deliveryrecvrequest(unsigned sock, siocpcontent *content)
else if (ret == socket_error && wsagetlasterror() != wsa_io_pending)
return true;
}
8、釋放資源(憤怒地寫在一起)
//執行緒自然退出標誌
m_stopthread = true;
//釋放socket
if (invalid_socket != m_socket)
if (m_accpetthread)
delete m_accpetthread;
m_accpetthread = null;
log_view->log("accept執行緒結束");
}//釋放iocp相關
if (m_iocp)
for (size_t i = 0; i < m_workerthread.size(); ++i)
;itoa(i+1, buff, 10);
if (m_workerthread[i]->joinable())
log_view->log("執行緒結束:", i+1);
delete m_workerthread[i];
}m_workerthread.clear();
//解除安裝套接字型檔
wsacleanup();
9、siocpcontent結構體
#include #define buff_len (1024)
enum eiocptype
;struct siocpcontent
siocpcontent(char* buff, int len)
~siocpcontent()
};
IOCP簡單實現
本人工作是服務端效能測試,因工作需要開發機械人框架,選用底層的時候看到網上滿大街的iocp介紹,還有說iocp比wsaasyncselect複雜等等,所以只好轉wsaasyncselect實現。因併發客戶端需要進行除錯測試,壓力測試工具作為客戶端來說效能十分重要,沒有經過測試的鬼知道秒併發多少請求,...
簡單的iocp例子
include include include include include using namespace std define i port 1666 define i addr 0.0.0.0 define dft buffer size 4096 define opt read 0 def...
IOCP 實現的基本步驟
呼叫iocp的步驟如下 抽象出乙個完成埠大概的處理流程 1 建立乙個完成埠。2 建立乙個執行緒a 3 a執行緒迴圈呼叫getqueuedcompletionstatus 函式來得到i o操作結果,這個函式是阻塞函式 4 主線程迴圈裡呼叫accept等待客戶端連線上來。5 主線程裡accept返回新連...