TCP流式套接字的事件物件I/O管理WSAEventSelect程式設計
阿新 • • 發佈:2019-01-27
/* 事件物件I/O管理程式例項 */
/************************************************************************/
#include <WINSOCK2.H>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
int main
{
printf("服務端程式\n");
//------①載入----------
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf("WSAStartup Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("①載入成功\n");
//-------②建立流式套接字------------
SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s==INVALID_SOCKET)
{
printf("socket() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("②已建立監聽套介面:【%d】\n",s);
//將套介面s置於”非阻塞模式“
u_long u1=1;
ioctlsocket(s,FIONBIO,(u_long*)&u1);
//-----------③繫結本地地址---------------------
struct sockaddr_in Sadd;
Sadd.sin_family=AF_INET;
Sadd.sin_port=htons(5555);
Sadd.sin_addr.S_un.S_addr=inet_addr("192.168.31.1");
if (bind(s,(sockaddr*)&Sadd,sizeof(Sadd))==SOCKET_ERROR)
{
printf("bind() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("③繫結成功,本地IP地址:【%s】,埠號:【%d】\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
//--------------④進入監聽狀態-----------------
if (listen(s,5)==SOCKET_ERROR)
{
printf("listen Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("④進入監聽狀態\n");
//--------------⑤建立事件物件-----------------
WSAEVENT NewEvent=WSACreateEvent();
if (NewEvent==WSA_INVALID_EVENT)
{
printf("WSACreateEvent() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("⑤建立一個事件物件,返回的事件物件控制代碼NewEvent=%d\n",NewEvent);
//--------------⑥網路事件註冊------------
int WESerror=WSAEventSelect(s,NewEvent,FD_ACCEPT|FD_CLOSE);
if (WESerror==INVALID_SOCKET)
{
printf("WSAEventSelect() Failed,Error=【%d】\n",WSAGetLastError());
return -1;
}
else
printf("⑥套介面【%d】、事件物件【%d】和網路事件FD_ACCEPT|FD_CLOSE已關聯\n",s,NewEvent);
//-----------準備工作---------------
int t=1;
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int n=0;
eventArray[n]=NewEvent;
sockArray[n]=s;
n++;
//------------迴圈處理-------------
while (true)
{
//---------------⑦等待事件物件--------------
int nIndex=WSAWaitForMultipleEvents(n,eventArray,FALSE,40000,FALSE);
printf("nIndex=%d\n",nIndex);
if (nIndex==WSA_WAIT_FAILED)//------7.1呼叫失敗---------
{
printf("呼叫失敗\n");
break;
}
else if (nIndex==WSA_WAIT_TIMEOUT)//-------7.2超時---------
{
if (t<3)
{
printf("第【%d】次超時\n",t);
t++;
continue;
}
else
{
printf("第【%d】次超時,退出\n",t);
break;
}
}
//---------------7.3網路事件觸發事件物件控制代碼的工作狀態--------
else
{
WSANETWORKEVENTS event;//該結構記錄網路事件和對應出錯程式碼
//---------⑧網路事件查詢-----------
WSAEnumNetworkEvents(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,&event);
WSAResetEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
if ((event.lNetworkEvents&FD_ACCEPT)!=0) //------8.1處理FD_ACCEPT通知訊息
{
if (event.iErrorCode[FD_ACCEPT_BIT]==0)
{
if (n>WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections!\n");
break;
}
SOCKET sNew=accept(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,NULL);
NewEvent=WSACreateEvent();
WSAEventSelect(sNew,NewEvent,FD_READ|FD_CLOSE);
eventArray[n]=NewEvent;
sockArray[n]=sNew;
n++;
}
}
else if (event.lNetworkEvents&FD_READ) //-------8.2處理FD_READ通知訊息
{
if (event.iErrorCode[FD_READ_BIT]==0)
{
char buf[256];
memset(buf,0,256);
int nRecv=recv(sockArray[nIndex-WSA_WAIT_EVENT_0],buf,sizeof(buf),0);
if (nRecv>0)
{
printf("接收到客戶端【%d】資料:%s\n",sockArray[nIndex-WSA_WAIT_EVENT_0],buf);
}
}
}
else if (event.lNetworkEvents&FD_CLOSE) //---------8.3處理FD_CLOSE通知訊息
{
if (event.iErrorCode[FD_CLOSE_BIT]==0)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("套接字為【%d】的已關閉連線\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
else
{
if (event.iErrorCode[FD_CLOSE_BIT]==10053)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("客戶端【%d】非法關閉連線\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
}
for (int j=nIndex-WSA_WAIT_EVENT_0;j<n-1;j++)
{
sockArray[j]=sockArray[j+1];
eventArray[j]=eventArray[j+1];
}
n--;
}
}// end 網路事件觸發
}//end while
printf("退出伺服器程式\n");
closesocket(s);
WSACleanup();
return 0;
}