服务端:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>
#define PORT 6000
#define IP_ADDRESS "127.0.0.1"
#define MSGSIZE 1024
class PerSocketData
{
public:
WSAOVERLAPPED overlap;
WSABUF buffer;
char szMessage[MSGSIZE];
DWORD NumberOfBytesRecvd;
DWORD flags;
};
class SocketListWithIOEvent
{
public:
SOCKET socketArray[MAXIMUM_WAIT_OBJECTS];
PerSocketData* overLappedData[MAXIMUM_WAIT_OBJECTS];
WSAEVENT eventArray[MAXIMUM_WAIT_OBJECTS];
int totalConn;
public:
SocketListWithIOEvent()
{
totalConn = 0;
for (size_t i = 0; i < MAXIMUM_WAIT_OBJECTS; i++)
{
socketArray[i] = 0;
overLappedData[i] = NULL;
eventArray[i] = NULL;
}
}
PerSocketData* insetSocket(SOCKET s)
{
socketArray[totalConn] = s;
overLappedData[totalConn] = (PerSocketData*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PerSocketData));
overLappedData[totalConn]->buffer.len = MSGSIZE;
overLappedData[totalConn]->buffer.buf = overLappedData[totalConn]->szMessage;
overLappedData[totalConn]->overlap.hEvent = WSACreateEvent();
eventArray[totalConn] = overLappedData[totalConn]->overlap.hEvent;
return overLappedData[totalConn++];
}
void deleteSocket(int index)
{
closesocket(socketArray[index]);
WSACloseEvent(eventArray[index]);
HeapFree(GetProcessHeap(), 0, overLappedData[index]);
if (index < totalConn - 1)
{
socketArray[index] = socketArray[totalConn - 1];
overLappedData[index] = overLappedData[totalConn - 1];
eventArray[index] = eventArray[totalConn - 1];
}
overLappedData[--totalConn] = NULL;
}
};
//当main的while里面插入的sock,有事件发生时,就不进行continue并往下执行.
//假如一个新的客户端连接并发送了数据:123,main函数里面的while循环里面插入了这个新的客户端,并调用WSArecv接受数据:123.
//所以workThread线程,有事件发生了(接受道数据:123),然后手动复位,通过WSAGetOverlappedResult获取收到的数据,并将数据原封不动的发给客户端.
//然后又调用非阻塞性的WSArecv接受数据,如果调用WSArecv瞬间有数据,那么就又重复以上步骤,如果调用WSArecv瞬间数据还没收到,则WSArecv不管直接返回(会在后台挂起,等待数据到达,有点类似于自己开了个线程,一直等待执行,有数据返回并关闭线程),WSAWaitForMultipleEvents就没有事件发生,就又进行continue,循环等待事件发生.
DWORD WINAPI workThread(LPVOID lpParam)
{
int nRes;
int nCurrentIndex;
DWORD cbTransFerred;
SocketListWithIOEvent* sockList = (SocketListWithIOEvent*)lpParam;
while (true)
{
nRes = WSAWaitForMultipleEvents(sockList->totalConn, sockList->eventArray, FALSE, 1000, FALSE);
if (nRes == WSA_WAIT_FAILED || nRes == WSA_WAIT_TIMEOUT)
{
continue;
}
nCurrentIndex = nRes - WSA_WAIT_EVENT_0;
WSAResetEvent(sockList->eventArray[nCurrentIndex]);
WSAGetOverlappedResult
(sockList->socketArray[nCurrentIndex],
&sockList->overLappedData[nCurrentIndex]->overlap,
&cbTransFerred,
TRUE,
&sockList->overLappedData[sockList->totalConn]->flags);
if (cbTransFerred == 0)
{
printf("Client 断开链接!\r\n");
sockList->deleteSocket(nCurrentIndex);
}
else
{
std::cout << sockList->overLappedData[nCurrentIndex]->szMessage << std::endl;
send(sockList->socketArray[nCurrentIndex], sockList->overLappedData[nCurrentIndex]->szMessage, cbTransFerred, 0);
WSARecv(sockList->socketArray[nCurrentIndex],
&sockList->overLappedData[nCurrentIndex]->buffer,
1,
&sockList->overLappedData[nCurrentIndex]->NumberOfBytesRecvd,
&sockList->overLappedData[nCurrentIndex]->flags,
&sockList->overLappedData[nCurrentIndex]->overlap, NULL);
}
}
return 0;
}
int main()
{
WSADATA wsa;
int nRes = WSAStartup(MAKEWORD(2, 2), &wsa);
if (nRes != 0)
{
printf("WSAStartup Error!\r\n");
return -1;
}
SOCKET serverSocket;
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
printf("socket Error!\r\n");
return -1;
}
sockaddr_in serverAddr;
sockaddr_in clientAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
nRes = bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (nRes != 0)
{
printf("bind Error!\r\n");
return -1;
}
nRes = listen(serverSocket, 10);
if (nRes != 0)
{
printf("listen Error!\r\n");
return -1;
}
printf("Server Runing!\r\n");
int addrLen = sizeof(clientAddr);
SOCKET sockConn;
SocketListWithIOEvent socketList;
HANDLE hThread = CreateThread(NULL, 0, workThread, &socketList, 0, NULL);
if (hThread == NULL)
{
printf("CreareThread Failed!\r\n");
}
CloseHandle(hThread);
//这里面,每一个新连接的客服端的第一次数据,是此处while循环里面WSARecv接收数据,后面的数据全部走线程里面接收,如果没有新的客服端连接,此处while循环里面的accept函数将阻塞,不往下执行,一直等待新的客服端连接,当然上一个已经连接的客服端已经由线程一直接受数据
while (true)
{
sockConn = accept(serverSocket, (sockaddr*)&clientAddr, &addrLen);
if (sockConn == INVALID_SOCKET)
{
printf("accept Failed!\r\n");
return -1;
}
std::cout << "Clinet link:" << inet_ntoa(clientAddr.sin_addr) << ":" << clientAddr.sin_port << std::endl;
PerSocketData* overLappedData = socketList.insetSocket(sockConn);
WSARecv(sockConn, &overLappedData->buffer, 1, &overLappedData->NumberOfBytesRecvd, &overLappedData->flags, &overLappedData->overlap, NULL);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}
客服端:
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>
#include <process.h>
void recv(PVOID pt)
{
SOCKET sHost = *((SOCKET*)pt);
while (true)
{
char buf[64]{ 0 };
int nRes = recv(sHost, buf, sizeof(buf), 0);
if (nRes == SOCKET_ERROR)
{
int nError = WSAGetLastError();
if (nError == WSAEWOULDBLOCK)
{
Sleep(1000);
continue;
}
else if (nError == WSAETIMEDOUT || nError == WSAENETDOWN || nError == WSAECONNRESET)
{
printf("revc failed!\r\n");
closesocket(sHost);
WSACleanup();
return;
}
}
Sleep(100);
printf("\r\nrecv:%s", buf);
printf("\r\ninput your buffer:\r\n");
}
}
int main()
{
WSADATA wsa;
SOCKET sHost;
SOCKADDR_IN serverAddr;
int nRes;
char buf[64]{ 0 };
nRes = WSAStartup(MAKEWORD(2, 2), &wsa);
if (nRes != 0)
{
printf("WSAStartup Error!\r\n");
return -1;
}
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(6000);
serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int sServerAddrlen = sizeof(serverAddr);
int iMode = 1;
nRes = ioctlsocket(sHost, FIONBIO, (u_long*)&iMode);
if (nRes == SOCKET_ERROR)
{
printf("ioctlsocket error!\r\n");
WSACleanup();
return -1;
}
printf("clinet runing...\r\n");
while (true)
{
nRes = connect(sHost, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (nRes == SOCKET_ERROR)
{
int nError = WSAGetLastError();
if (nError == WSAEWOULDBLOCK || nError == WSAEINVAL)
{
Sleep(1);
printf("check!\r\n");
continue;
}
else if (nError == WSAEISCONN)
{
break;
}
else
{
printf("connect failed!\r\n");
closesocket(sHost);
WSACleanup();
return -1;
}
}
}
unsigned long lThreadid = _beginthread(recv, 0, &sHost);
printf("input data:\r\n");
while (true)
{
char szBuffer[1024]{ 0 };
std::cin >> szBuffer;
while (true)
{
nRes = send(sHost, szBuffer, strlen(szBuffer), 0);
if (nRes == SOCKET_ERROR)
{
int nError = WSAGetLastError();
if (nError == WSAEWOULDBLOCK)
{
Sleep(5);
continue;
}
else
{
printf("send failed!\r\n");
closesocket(sHost);
WSACleanup();
return -1;
}
}
break;
}
}
return 0;
}