日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用完成例程(Completion Routine)实现的重叠I/O模型

發布時間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用完成例程(Completion Routine)实现的重叠I/O模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
//
/// 用完成例程(Completion Routine)實現的重疊I/O模型
/// 異步IO模型
/// 用完成例程來實現重疊I/O比用事件通知簡單得多。在這個模型中,主線程只用不停的接受連接
/// 即可;輔助線程判斷有沒有新的客戶端連接被建立,如果有,就為那個客戶端套接字激活一個
/// 異步的WSARecv操作,然后調用SleepEx使線程處于一種可警告的等待狀態,以使得I/O完成后
/// CompletionROUTINE可以被內核調用。如果輔助線程不調用SleepEx,則內核在完成一次I/O操作后,
/// 無法調用完成例程(因為完成例程的運行應該和當初激活WSARecv異步操作的代碼在同一個線程之內)。
/// 完成例程內的實現代碼比較簡單,它取出接收到的數據,然后將數據原封不動的發送給客戶端,
/// 最后重新激活另一個WSARecv異步操作。
/// 注意,在這里用到了“尾隨數據”。
/// 我們在調用WSARecv的時候,參數lpOverlapped實際上指向一個比它大得多的結構PER_IO_OPERATION_DATA,
/// 這個結構除了WSAOVERLAPPED以外,還被我們附加了緩沖區的結構信息,另外還包括客戶端套接字等重要的信息。
/// 這樣,在完成例程中通過參數lpOverlapped拿到的不僅僅是WSAOVERLAPPED結構,
/// 還有后邊尾隨的包含客戶端套接字和接收數據緩沖區等重要信息。這樣的C語言技巧在我后面介紹完成端口的時候還會使用到。
//
//
/// 打開信封----掏出信紙----閱讀信件----回復信件==>完成例程
/// 老陳接收到新的信件后,一般的程序是:打開信封----掏出信紙----閱讀信件----回復信件
/// ......為了進一步減輕用戶負擔,微軟又開發了一種新的技術:用戶只要告訴微軟對信件的
/// 操作步驟,微軟信箱將按照這些步驟去處理信件,不再需要用戶親自拆信/閱讀/回復了!老陳
/// 終于過上了小資生活!??
//

#pragma?once?
#include?<WINSOCK2.H>
#include?<stdio.h>
#define?PORT 5150
#define?MSGSIZE 1024
#pragma?comment(lib,?"ws2_32.lib")
typedef?struct
{
?WSAOVERLAPPED overlap;
?WSABUF Buffer;
?char?szMessage[MSGSIZE];
?DWORD NumberOfBytesRecvd;
?DWORD Flags;?
?SOCKET?sClient;
}PER_IO_OPERATION_DATA,?*LPPER_IO_OPERATION_DATA;
DWORD WINAPI WorkerThread(LPVOID);
void?CALLBACK CompletionROUTINE(DWORD,?DWORD,?LPWSAOVERLAPPED,?DWORD);
//相應的完成例程函數

SOCKET?g_sNewClientConnection;
BOOL?g_bNewConnectionArrived?=?FALSE;
int?main()
{
?WSADATA wsaData;
?SOCKET?sListen;
?SOCKADDR_IN?local,?client;
?DWORD dwThreadId;
?int?iaddrSize?=?sizeof(SOCKADDR_IN);
?
// Initialize Windows Socket library

?WSAStartup(0x0202,?&wsaData);
?
// Create listening socket

?sListen?=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);
?
// Bind

?local.sin_addr.S_un.S_addr?=?htonl(INADDR_ANY);
?local.sin_family?=?AF_INET;
?local.sin_port?=?htons(PORT);
?bind(sListen,?(struct?sockaddr?*)&local,?sizeof(SOCKADDR_IN));
?
// Listen

?listen(sListen,?3);
?
// Create worker thread

?CreateThread(NULL,?0,?WorkerThread,?NULL,?0,?&dwThreadId);
?while?(TRUE)
?{
??
// Accept a connection

??
// 這里的寫法肯定是有問題的

??g_sNewClientConnection?=?accept(sListen,?(struct?sockaddr?*)&client,?&iaddrSize);
??g_bNewConnectionArrived?=?TRUE;
??printf("Accepted client:%s:%d\n",?inet_ntoa(client.sin_addr),?ntohs(client.sin_port));
?}
}
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
?LPPER_IO_OPERATION_DATA lpPerIOData?=?NULL;
?while?(TRUE)
?{
??if?(g_bNewConnectionArrived)
??{
???
// Launch an asynchronous operation for new arrived connection

???lpPerIOData?=?(LPPER_IO_OPERATION_DATA)HeapAlloc(
????GetProcessHeap(),
????HEAP_ZERO_MEMORY,
????sizeof(PER_IO_OPERATION_DATA));
???lpPerIOData->Buffer.len?=?MSGSIZE;
???lpPerIOData->Buffer.buf?=?lpPerIOData->szMessage;
???lpPerIOData->sClient?=?g_sNewClientConnection;
???WSARecv(lpPerIOData->sClient,
????&lpPerIOData->Buffer,
????1,
????&lpPerIOData->NumberOfBytesRecvd,
????&lpPerIOData->Flags,
????&lpPerIOData->overlap,
????CompletionROUTINE);
//注意這里向系統登記了一個回調函數,將會在接收數據完成的時候進行相應的調用?

???g_bNewConnectionArrived?=?FALSE;
??}
??SleepEx(1000,?TRUE);
?}
?return?0;
}
void?CALLBACK CompletionROUTINE(DWORD dwError,
????????DWORD cbTransferred,
????????LPWSAOVERLAPPED lpOverlapped,
????????DWORD dwFlags)
{
?
//注意這一句話,將LPWSAOVERLAPPED類型的lpOverlapped轉化成了LPPER_IO_OPERATION_DATA

?LPPER_IO_OPERATION_DATA lpPerIOData?=?(LPPER_IO_OPERATION_DATA)lpOverlapped;
?if?(dwError?!=?0?||?cbTransferred?==?0)
?{
??
// Connection was closed by client

??closesocket(lpPerIOData->sClient);
??HeapFree(GetProcessHeap(),?0,?lpPerIOData);
?}
?else
?{
??lpPerIOData->szMessage[cbTransferred]?=?'\0';
??send(lpPerIOData->sClient,?lpPerIOData->szMessage,?cbTransferred,?0);
??
// Launch another asynchronous operation

??memset(&lpPerIOData->overlap,?0,?sizeof(WSAOVERLAPPED));
??lpPerIOData->Buffer.len?=?MSGSIZE;
??lpPerIOData->Buffer.buf?=?lpPerIOData->szMessage;?
??WSARecv(lpPerIOData->sClient,
???&lpPerIOData->Buffer,
???1,
???&lpPerIOData->NumberOfBytesRecvd,
???&lpPerIOData->Flags,
???&lpPerIOData->overlap,
???CompletionROUTINE);
?}
}

總結

以上是生活随笔為你收集整理的用完成例程(Completion Routine)实现的重叠I/O模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。