第一步 :双线程
// SelectServer.cpp
#include <windows.h>
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
DWORD WINAPI SelectProc(LPVOID lpParameter)
{
if (NULL == lpParameter)
{
printf("invalid thread param!\n");
return -1;
}
SOCKET sAccept = *(SOCKET*)(lpParameter);
char szRecv[4096] = {0};
fd_set fdRead;
fd_set fdWrite;
fd_set fdExcept;
timeval time;
time.tv_sec = INFINITE;
time.tv_usec = 0;
for ( ; ;)
{
FD_ZERO(&fdRead);
FD_SET(sAccept, &fdRead); // 1.这个要放在select 前,每次都要处理的
int nRet = select(0, &fdRead, NULL, NULL, &time/*NULL*/);
if (SOCKET_ERROR == nRet)
{
DWORD dwLastErr = WSAGetLastError();
printf("select socket error! err: %u\n", dwLastErr);
break;
}
if( FD_ISSET( sAccept, &fdRead ) )
//if (fdRead.fd_array[0] == sAccept)
{
printf("select a read socket\n");
nRet = recv(sAccept, szRecv, 4096, 0);
if (SOCKET_ERROR != nRet)
{
printf("recv data: %s\n", szRecv);
}
nRet = send(sAccept, szRecv, strlen(szRecv), 0);
if (SOCKET_ERROR == nRet)
{
printf("send data error\n");
break;
}
printf("send data: %s\n", szRecv);
FD_CLR( sAccept , &fdRead );
closesocket(sAccept);
sAccept = INVALID_SOCKET;
}
if (INVALID_SOCKET == sAccept)
{
printf("I'm INVALID_SOCKET ,I will return\n");
return 0;
}
}
if (INVALID_SOCKET != sAccept)
{
closesocket(sAccept);
sAccept = INVALID_SOCKET;
}
printf("thread exit\n");
return 0;
}
int main()
{
DWORD dwVersion = 0;
WSADATA wsaData;
DWORD dwErr = 0;
int kk =0;
dwErr = WSAStartup(MAKEWORD(0x2, 0x2), &wsaData);
if (0 != dwErr)
{
printf("winsock init error!\n");
return -1;
}
if (0x2 != LOBYTE(wsaData.wVersion) ||
0x2 != HIBYTE(wsaData.wVersion))
{
// couldn't find a usable WinSock DLL.
printf("request winsock version error!\n");
WSACleanup();
return -1;
}
//SOCKET sAccept = INVALID_SOCKET;
SOCKET sAccept[512] = {INVALID_SOCKET}; //这个要注意,如果只用一个会覆盖,因为可能多个连接
SOCKET sListen = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sListen)
{
printf("create a socket error!\n");
WSACleanup();
return -1;
}
sockaddr_in servAddr;
ZeroMemory(&servAddr, sizeof(servAddr));
servAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(80);
sockaddr_in clientAddr;
ZeroMemory(&clientAddr, sizeof(clientAddr));
int nLen = sizeof(clientAddr);
DWORD dwThreadID = 0;
HANDLE hThread = NULL;
if (SOCKET_ERROR == bind(sListen, (struct sockaddr*)&servAddr, sizeof(servAddr)))
{
printf("bind socket error!\n");
dwErr = WSAGetLastError();
goto _QUIT;
}
if (SOCKET_ERROR == listen(sListen, SOMAXCONN))
{
printf("listen socket error!\n");
dwErr = WSAGetLastError();
goto _QUIT;
}
printf("listen......\n");
while (1)
{
sAccept[kk] = accept(sListen, (sockaddr *)&clientAddr, &nLen);
if (INVALID_SOCKET == sAccept[kk])
{
printf("accept a socket error!\n");
dwErr = WSAGetLastError();
break;
}
printf("accept a socket\n");
hThread = CreateThread(NULL, 0, SelectProc, &sAccept[kk], 0, &dwThreadID);
if (NULL == hThread)
{
printf("create thread error!\n");
dwErr = -1;
goto _QUIT;
}
kk++;
}
_QUIT:
if (INVALID_SOCKET != sListen)
{
closesocket(sListen);
sListen = INVALID_SOCKET;
}
WSACleanup();
return dwErr;
}
这样,并不是完全的异步方式
异步单线程
#include <stdio.h>
#include <string.h>
#include <WINSOCK2.H>
#pragma comment(lib,"ws2_32.lib")
#define STR_SERVER_IP "127.0.0.1"
#define INT_SERVER_PORT 80
#define INT_DATABUFFER_SIZE 2560
bool reachDelayTime(SYSTEMTIME nowTime,SYSTEMTIME startTime)
{
//是先算后面的吗
if (nowTime.wYear>startTime.wYear ||
nowTime.wMonth > startTime.wMonth ||
nowTime.wDay>startTime.wDay||
nowTime.wHour> startTime.wHour||
nowTime.wMinute>startTime.wMinute||
nowTime.wSecond>=(startTime.wSecond+2)) //>=2s 实际为1s以上
{
return true;
}
return false;
}
int main(int argc, char* argv[])
{
SYSTEMTIME startT,nowT;
GetLocalTime(&startT);
/*
printf("now1 %d %d \n",startT.wSecond,startT.wMilliseconds );
Sleep(1);
GetLocalTime(&nowT);
nowT.wMonth = startT.wMonth+0;
printf("now2 %d %d \n",nowT.wSecond,nowT.wMilliseconds );
printf("reachDelayTime=%d \n",reachDelayTime(nowT,startT) );
//printf("now2 %d \n",time2 );
return 1;
*/
WORD dwVersion = MAKEWORD(2,2);
WSAData wsaData;
WSAStartup(WINSOCK_VERSION,&wsaData);
SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockServer) {
printf("Failed to create socket!\r\n");
WSACleanup();
return -1;
}
sockaddr_in addrServer;
memset(&addrServer,0,sizeof(sockaddr_in));
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(INT_SERVER_PORT);
addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//addrServer.sin_addr.s_addr = htonl(INADDR_ANY);
int iResult;
bool bReuseAddr = true;
iResult=setsockopt(sockServer,SOL_SOCKET,SO_REUSEADDR,(char *)&bReuseAddr,sizeof(bReuseAddr));
if(SOCKET_ERROR == iResult) {
printf("Failed to set resueaddr socket!\r\n");
WSACleanup();
return -1;
}
//unsigned long cmd = 1;
// iResult= ioctlsocket(sockServer,FIONBIO,&cmd);
iResult = bind(sockServer,(sockaddr *)&addrServer,sizeof(addrServer));
if (SOCKET_ERROR == iResult) {
printf("Failed to bind address!\r\n");
WSACleanup();
return -1;
}
if (0 != listen(sockServer,5)) {
printf("Failed to listen client!\r\n");
WSACleanup();
return -1;
}
UINT i = 0;
SOCKET sockAccept;
sockaddr_in addrAccept;
int iAcceptLen = sizeof(addrAccept);
char szDataBuff[INT_DATABUFFER_SIZE];
int iRecvSize;
int t1 = INVALID_SOCKET;
SOCKET sAccept[512] = {INVALID_SOCKET}; //这个要注意,如果只用一个会覆盖,因为可能多个连接
memset(sAccept,INVALID_SOCKET,512*sizeof(SOCKET));
sockaddr_in addrTemp;
int iTempLen;
fd_set fdRead;
timeval tm;
tm.tv_sec = 0;
tm.tv_usec = 1000;
printf("Start server...\r\n");
int iTemp=0;
while(1)
{
FD_ZERO(&fdRead);
FD_SET(sockServer, &fdRead);
//printf("INVALID_SOCKET %d \n",INVALID_SOCKET);
for( iTemp=0;iTemp<512;iTemp++)
{
if (sAccept[iTemp] != INVALID_SOCKET )
{
FD_SET(sAccept[iTemp], &fdRead);
}
}
iResult = select(0, &fdRead, NULL, NULL,&tm/*NULL*/); //&tm
if (0 <= iResult)
{
printf("iResult=%d \n", iResult);
if (FD_ISSET(sockServer, &fdRead))
{
memset(&addrAccept,0,sizeof(addrTemp));
sockAccept = accept(sockServer, (sockaddr *)&addrAccept, &iAcceptLen);
if (INVALID_SOCKET != sockAccept)
{
sAccept[iTemp] == INVALID_SOCKET; // 马上还要重新设置
printf("%s:%d has connected server!\r\n", inet_ntoa(addrAccept.sin_addr),
ntohs(addrAccept.sin_port));
}
for( iTemp=0;iTemp<512;iTemp++)
{
if (sAccept[iTemp] == INVALID_SOCKET )
{
sAccept[iTemp] = sockAccept;
break;
}
}
}
for(iTemp=0;iTemp<512;iTemp++)
{
if(sAccept[iTemp]!= INVALID_SOCKET)
{
if (FD_ISSET(sAccept[iTemp], &fdRead))
{
{ //非服务器,接收数据(因为fd是读数据集)
memset(szDataBuff, 0, INT_DATABUFFER_SIZE);
iRecvSize = recv(sAccept[iTemp], szDataBuff, INT_DATABUFFER_SIZE, 0);
memset(&addrTemp, 0, sizeof(addrTemp));
iTempLen = sizeof(addrTemp);
getpeername(sAccept[iTemp], (sockaddr *)&addrTemp, &iTempLen);
// an error occurs
if (SOCKET_ERROR == iRecvSize)
{
closesocket(sAccept[iTemp]);
sAccept[iTemp] = INVALID_SOCKET;
i--;
printf("Failed to recv data ,%s:%d errorcode:%d.iTemp=%d\r\n",
inet_ntoa(addrTemp.sin_addr),ntohs(addrTemp.sin_port),WSAGetLastError(),iTemp);
continue;
}
// 客户socket关闭
if (0 == iRecvSize)
{
printf("%s:%d has closed iTemp=%d!\r\n",inet_ntoa(addrTemp.sin_addr),
ntohs(addrTemp.sin_port),iTemp);
closesocket(sAccept[iTemp]);
sAccept[iTemp] = INVALID_SOCKET;
i--;
}
// no error occurs, returns the number of bytes received
if (0 < iRecvSize)
{
printf("iTemp=%d recv %s:%d data:%s\r\n",iTemp, inet_ntoa(addrTemp.sin_addr),
ntohs(addrTemp.sin_port),szDataBuff);
char szEcho[2560] = {0};
sprintf(szEcho, "Server has got: %s.", szDataBuff);
send(sAccept[iTemp], szEcho, strlen(szEcho), 0);
closesocket(sAccept[iTemp]);
sAccept[iTemp] = INVALID_SOCKET;
}
}
}
}
}
}
else if (SOCKET_ERROR == iResult)
{
int iErr = WSAGetLastError();
//WSACleanup();
printf("Faild to select sockt in server!(Error: %d)\r\n", iErr);
Sleep(100);
}
}
WSACleanup();
return 0;
}