在多客户端连接发送信息的条件下,能够显示不同客户端的端口号,在断开连接后显示断开客户端的端口号。
#pragma warning(disable:4996)
#include<iostream>
#include<WinSock2.h>
#include<tchar.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
//事件句柄和socket句柄表
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int nEventTotal = 0;
USHORT nPort = 9990;//监听端口号
//初始化环境
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
//创建监听
SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//设置地址绑定socket
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
::bind(sListen, (struct sockaddr*)&sin, sizeof(struct sockaddr));
::listen(sListen, 5);
cout << "成功监听端口" << ntohs(sin.sin_port) << endl;
//创建事件对象,并注册网络事件
WSAEVENT myevent = ::WSACreateEvent();
::WSAEventSelect(sListen, myevent, FD_ACCEPT | FD_CLOSE);
eventArray[nEventTotal] = myevent;
sockArray[nEventTotal] = sListen;
nEventTotal++;
//处理网络事件
while (TRUE)
{
//在所有事件对象上等待,只要有一个事件对象变为已授信,则函数返回
int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);
nIndex = nIndex - WSA_WAIT_EVENT_0;
//对每个事件调用wsawaitformultipleevents函数,以确定其状态
for (int i = nIndex; i < nEventTotal; i++)
{
int ret;
ret = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE);
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
WSANETWORKEVENTS event1;
::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event1);
if (event1.lNetworkEvents & FD_ACCEPT)
{
if (event1.iErrorCode[FD_ACCEPT_BIT] == 0)
{
//连接太多,暂不处理
if (nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf("太多连接!");
continue;
}
int len = sizeof(sockaddr_in);
SOCKET sNew = ::accept(sockArray[i], (sockaddr*)&sin, &len);
cout << "接受一个客户端" <<inet_ntoa(sin.sin_addr)<<":["<<sin.sin_port << "]" << endl;
WSAEVENT newEvent = ::WSACreateEvent();//为新套接字创建对象
::WSAEventSelect(sNew, newEvent, FD_READ | FD_CLOSE | FD_WRITE);
//将新建的事件netEvent保存到eventArray数组中
eventArray[nEventTotal] = newEvent;
sockArray[nEventTotal] = sNew;
nEventTotal++;
}
}
else if (event1.lNetworkEvents & FD_READ)
{
if (event1.iErrorCode[FD_READ_BIT] == 0)
{
char szText[256];
int nRecv = ::recv(sockArray[i], szText, strlen(szText), 0);
int ss = sockArray[i];
int l = sizeof(sockaddr_in);
if (nRecv > 0)
{
szText[nRecv] = '\0';
SYSTEMTIME st;
GetLocalTime(&st);
char sDateTime[30];
getpeername(ss,reinterpret_cast<sockaddr*>(&sin),&l );
sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
//打印输出信息
printf("%s接收到来自客户端[%s:%d]:%s \n",sDateTime,inet_ntoa(sin.sin_addr),sin.sin_port,szText );
strcpy(szText, "msg 接收到消息");
int nSnd = ::send(sockArray[i], szText, strlen(szText), 0);
}
}
}
else if (event1.lNetworkEvents & FD_CLOSE)//处理close消息
{
//关闭socket,删除组内对应记录
SYSTEMTIME st;
GetLocalTime(&st);
char sDateTime[30];
sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
printf("%s客户端[%s:%d]:下线 \n", sDateTime, inet_ntoa(sin.sin_addr), sin.sin_port, 0);
if (event1.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(sockArray[i]);
for (int j = i; j < nEventTotal - 1; j++)
{
eventArray[j] = eventArray[j + 1];
sockArray[j] = sockArray[j + 1];
}
nEventTotal--;
}
}
else if (event1.lNetworkEvents & FD_WRITE)
{
char szText[256] = "msg 接收消息";
int nSnd = ::send(sockArray[i], szText, strlen(szText), 0);
cout << "客户端连接允许写入数据" << endl;
}
}
}
}
}