今天簡單實踐了最基本的 IOCP http server , 原則上是用我第二天寫的 one2Many httpServer 改的。
中間會擷取跟 IOCP 有關的部分講講。
其實我不覺得大家有必要深入的去讀原始碼, 因為真的有點複雜, 會了也沒太大作用, 我想, 只要稍微看過我寫的概念, 心中大概有些認知, 之後讀 node 的原始碼時應該就夠用了。
https://gist.github.com/leon123858/29ecce37aa3c43c59b8362cd336c75ef
以下會用 3 個步驟來解釋 IOCP 在這個 http server 中的意義
httpServer() {
// 上略, 僅創建 TCP 連線 socket
// 創建 IOCP 公用 queue
eventQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
if (eventQueue == NULL)
errorHandle("IOCP create");
// 將 TCP 連線事件註冊進 IOCP, 等待客戶端連線的事件發生
if (CreateIoCompletionPort((HANDLE)listenSocket, eventQueue, (ULONG_PTR)0, 0) == NULL)
errorHandle("IOCP listen");
// 創建沉睡的 threadpool 等待訊息傳入的事件發生後醒來處理事件
for (int i = 0; i < THREADPOOL_SIZE; i++)
workerThreads[i] = thread(&httpServer::workerThreadFunction, this, eventQueue);
}
// 創建連線客戶端 socket
struct sockaddr_in clientSocketSetting;
int clientSocketSettingLength;
clientSocketSettingLength = sizeof(clientSocketSetting);
SOCKET messageSocket = accept(listenSocket, (struct sockaddr*)&clientSocketSetting, &clientSocketSettingLength);
// 把連線客戶端的 socket 註冊進 IOCP , 所以等下 WSARecv 把客戶端的訊息傳入 queue 後, 也會觸發事件。
ioInformation* ioInfo = new ioInformation(messageSocket);
if (CreateIoCompletionPort((HANDLE)messageSocket, eventQueue, (ULONG_PTR)ioInfo, 0) == NULL)
errorHandle("IOCP listen");
// 把客戶端的訊息傳入 queue , 傳進去後會觸發事件喚醒 threadpool 中的 thread。
WSARecv(messageSocket, &(ioInfo->wsaBuf),1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
while (true){
// IOCP 提供的方法, 使 thread 沉睡, 當 queue 中有一個事件, 就喚醒一條 thread, 且取出資料
result = GetQueuedCompletionStatus(eventQueue,&ipNumberOfBytes,(PULONG_PTR)&ipCompletionKey,&ipOverlap,INFINITE);
// 確認事件類型
if (result == 0 || ipNumberOfBytes == 0)
continue;
// http response
ioInformation* ioInfo = (ioInformation*)ipCompletionKey;
request req = request(ioInfo->wsaBuf.buf, ioInfo->wsaBuf.len);
if (req.requestType < 0) {
delete ioInfo;
continue;
}
cout << req.typeName[req.requestType] << " : " << req.filePath << endl;
int sentResult = responseClient(req, ioInfo->socket);
if (sentResult <= 0) {
printf("send error\n");
break;
}
delete ioInfo;
}
明天會開始探討一個關於 node 的小實驗。
明天見