typedef struct _SocketState // socket state & control
{
char operation;
SOCKET socket;
DWORD length;
char buf[MAX_BUF];
} SocketState;
static SocketState* new_socket_state(void)
{
return (SocketState *)calloc (1, sizeof(SocketState));
}
static WSAOVERLAPPED* new_overlapped(void)
{
return (WSAOVERLAPPED *)calloc (1, sizeof(WSAOVERLAPPED));
}
newSocketState = new_socket_state();
newSocketState->socket = socketState->socket;//此處的socketState->socket是已經建立連接的socket;
CreateIoCompletionPort((HANDLE)newSocketState->socket, cpl_port,(ULONG_PTR)newSocketState, 0) //系結到完成埠上;
==================
我要投遞兩個io:
socketState->operation = OP_READ;
WSARecv(newSocketState ->socket, &wsabuf, 1, NULL, &flags, ovl, NULL)
socketState->operation = OP_WRITE;
WSASend(newSocketState ->socket, &wsabuf, 1, NULL, 0, ovl, NULL)
這里我不可能讓socketState->operation同時為OP_READ或者OP_WRITE兩個值吧?這里應該如何處理?
uj5u.com熱心網友回復:
用 WSAEventSelect(s, hEventObject, FD_READ|FD_WRITE|FD_CLOSE); 事件驅動可以么, 然后用 WSAEnumNetworkEvents 檢查uj5u.com熱心網友回復:
IOCP還要用事件選擇,沒有其它方式嗎?
uj5u.com熱心網友回復:
我的意思是這樣的,先投遞:socketState->operation = OP_READ;
WSARecv(newSocketState ->socket, &wsabuf, 1, NULL, &flags, ovl, NULL)
這個時候GetQueuedCompletionStatus還沒有回傳,也就是WSARecv還沒有完成 ,緊接著投遞
socketState->operation = OP_WRITE;
WSASend(newSocketState ->socket, &wsabuf, 1, NULL, 0, ovl, NULL)
這樣一來socketState->operation = OP_WRITE就覆寫了socketState->operation = OP_READ,然后
GetQueuedCompletionStatus回傳來的操作只能socketState->operation = OP_WRITE,而不會得到socketState->operation = OP_READ。這個怎么解決?
uj5u.com熱心網友回復:
IOCP二:同時發送和接收uj5u.com熱心網友回復:
關鍵是系結的key是相同的newSocketState。
uj5u.com熱心網友回復:
先后幾乎同時投遞WSARecv和WSASend,投遞WSARecv時,設定newSocketState ->operation = OP_READ; 緊接著投遞WSASend時,設定newSocketState ->operation = OP_WRITE;當GetQueuedCompletionStatus回傳兩次(WSARecv和WSASend)后,程式都會進入OP_READ分支處理。
uj5u.com熱心網友回復:
投遞兩次不會覆寫吧,應該會回傳兩次uj5u.com熱心網友回復:
大致看了下,感覺你理解有誤。作為服務器端,recv不是隨便投遞的,recv的物件不是創建出來的,而是accept函式接到連接請求得到的,得到客戶端socket后,才可以對其投遞recv操作。socketState->operation = OP_READ;是什么操作?沒見過。而且現實中不可能上來就投遞send和recv,就像別人打電話問你問題,電話接通后,你不可能問別人什么問題的同時回答他的問題,必須先聽他的問題,再回答他。回到socket,服務器端都是accept后,投遞recv,看看客戶端請求是什么,然后再完成例程里相應請求,也就是投遞send回復。當然,多個客戶端連接的話,這個客戶端的recv和另一個客戶端的send可能同時存在,但那是不同的會話。
uj5u.com熱心網友回復:
8樓分析的有道理投遞是依賴于業務的,并不是連接后就直接投遞讀和寫
server是被動回應的,
需要接收資料才會發出讀投遞;
如果需要發送資料,才會進行寫投遞。
uj5u.com熱心網友回復:
邏輯先不論,如果要投遞兩個請求,使用兩個newSocketState 就可以了uj5u.com熱心網友回復:
你可以同時投遞Send和Recv,系結2個WSBuf,在投遞期間保持系結的buffer有效。uj5u.com熱心網友回復:
IOCP用起來可以說是最方便的框架了。完全不必搞得這么麻煩。事件驅動你可以這么寫:iocp事件的定義:
struct iocp_evt;
/* iocp事件處理函式 */
typedef void (*iocp_evt_handler)(void *priv, struct iocp_evt *evt);
/* 定義iocp事件,將overlapped與事件系結起來 */
struct iocp_evt {
iocp_evt_handler handler;
void *priv;
OVERLAPPED overlapped;
DOWRD numberOfBytes;
DOWRD dwError;
ULONG_PTR key;
}
/* 事件初始化 */
void iocp_evt_init(struct iocp_evt *evt, iocp_evt_handler handler, void *priv)
{
evt->handler = handler;
evt->priv = priv;
memset(&evt->overlapped, 0, sizeof(OVARLAPPED));
}
事件被觸發時的處理函式:
void on_wsa_recv(void *priv, struct iocp_evt *evt)
{
/* 拿到IOCP中的錯誤碼 */
DOWRD dwError = evt->dwError;
/* 拿到IOCP傳輸的位元組數 */
DOWRD numberOfBytes = evt->numberOfBytes;
/* 拿到IOCP系結時的Key */
ULONG_PTR key = evt->key;
/* 拿到自己攜帶的背景關系 */
void *context = priv;
/* ... */
}
投遞IOCP事件處的寫法:
/* 生成iocp事件 */
struct iocp_evt *evt = (struct iocp_evt *)malloc(sizeof(struct iocp_evt));
/* 傳入事件回呼函式和自己的背景關系指標對事件進行初始化 */
iocp_evt_init(evt, on_wsa_recv, user_data);
/* 投遞時,將IOCP事件中的overlapped成員傳入 */
WSARecv(socket, &wsabuf, 1, NULL, &flags, &evt->overlapped, NULL);
GetQueuedCompletionStatus處的寫法:
while (1)
{
DWORD numberOfBytes;
ULONG_PTR key;
LPOVERLAPPED *pOverlapped;
struct iocp_evt *iocp_evt;
DWORD dwError = GetQueuedCompletionStatus(iocp_handle, &numberOfBytes, &key, &pOverlapped, INFINITE) ? 0 : GetLastError();
/* 若pOverlapped不為零,則有一個iocp事件被完成 */
if (pOverlapped != NULL)
{
/* 通過struct iocp_evt的overlapped成員指標拿到iocp_evt指標 */
iocp_evt = CONTAINING_RECORD(pOverlapped, struct iocp_evt, overlapped);
/* 設定此次IOCP事件的處理結果 */
iocp_evt->dwError = dwError;
iocp_evt->key = key;
iocp_evt->numberOfBytes = numberOfBytes;
/* 處理事件 */
iocp_evt->handler(iocp_evt->priv, iocp_evt);
}
};
uj5u.com熱心網友回復:
一個支持上萬高并發的簡單HTTP服務器寫法:https://github.com/xiaoliang314/libatask/blob/master/httpserver_win/httpserver.c
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/37100.html
標籤:網絡編程
