#pragma comment (lib, "ws2_32.lib") #include #include #include //Некоторые константы #define SERVER_ADDRESS "127.0.0.1" //IP-адрес сервера #define SERVER_PORT 999 //Порт сервера #define SERVER_MAX_CONNECTION 64 //Количество подключений #define DATA_BUFSIZE 1024//4096 //Размер буфера #define OPERATION_READ 10 #define OPERATION_WRITE 11 //------------------------------------------ОСНОВНЫЕ ОБЪЯВЛЕНИЯ------------------------------------------------- WSADATA wsaData; //Хранит данные о серверном сокете WORD wVersion = MAKEWORD(2, 2); //0x202; //Версия winsock-интерфейса SOCKET ServerSocket = INVALID_SOCKET; //Дескрипор серверного сокета struct sockaddr_in ServerAddress; //Серверный адрес HANDLE nIOCPort = INVALID_HANDLE_VALUE; //Порт завершения ввода/вывода int wsaError; //Переменная для ошибок WSAEVENT nServerAcceptEvent; //Серверное событие HANDLE nServerAcceptThread = NULL; //Сервеный поток обработки подключений DWORD nServerAcceptThreadID; //ID потока Accept HANDLE nServerAcceptShutdownEvent = NULL; //Событие завершения //Рабочий поток обработки клиентских запросов HANDLE nServerWorkThread = NULL; DWORD nServerWorkThreadID; int nTotalClients = 0; //Общее количество клиентов //Объявление хранилища клиентов //Максимально обрабатываем 64 клиента, т.к. пока один поток //typedef short int sint; typedef struct _SClient { int scParams; //Параметры клиента int scType; //Определяет права клиента и др. short int scLockStatus; //Статус пользователя, занят ли данный слот др. потоками short int scFree; //Байт определяющий свободен ли данный слот SOCKET scSocket; //Сокет клиента sockaddr_in scAddress; //Адресные параметры клиента } SClient, *PSClient; typedef struct _SClientOverlapped { WSAOVERLAPPED scOverlapped; //Структура OVERLAPPED DWORD scOperation; //Операция ввода/вывода WSABUF scDataBuf; //WSABUF char scBuffer[DATA_BUFSIZE]; //Буфер данных DWORD scRecvBytes; //Количество принятых байт DWORD scSendBytes; //Количество отсылаемых байт DWORD scFlags; //Флаги после вызовов Recv и Send } SClientOverlapped, *PSClientOverlapped; const DWORD cSClientSize = sizeof(SClient); //Константа для размера структуры SClient const DWORD cSClientOverlappedSize = sizeof(SClientOverlapped); //Константа для размера структуры SClientOverlapped //------------------------------------------ОБЪЯВЛЕНИЯ ФУНКЦИЙ-------------------------------------------------- DWORD WINAPI ServerAcceptThread(LPVOID lpParam); //Объявление функции обработки подключений DWORD WINAPI ServerWorkThread(LPVOID lpParam); //Объявление функции рабочих потоков //-------------------------------------------------------------------------------------------------------------- int main (int argc, char *argv[]) { //Создание порта завершения ввода/вывода nIOCPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0); if (nIOCPort == NULL) { printf( "Error CreateIoCompletionPort(): %ld\n", GetLastError() ); return 1; } //Создаем поток обработки запросов nServerWorkThread = CreateThread(0, 0, ServerWorkThread, (void*)(1)/*пока передаем 1, поток будем структуру*/, 0, &nServerWorkThreadID); //Инициализация WinSocket wsaError = WSAStartup(wVersion, &wsaData); if ( wsaError != NO_ERROR ) { printf("Error at WSAStartup(): %ld\n", WSAGetLastError() ); return 1; } //Создание сокета ServerSocket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if ( ServerSocket == INVALID_SOCKET ) { printf( "Error WSASocket() at server socket: %ld\n", WSAGetLastError() ); WSACleanup(); return 1; } /*unsigned long NonBlockingMode = TRUE; ioctlsocket(ServerSocket, FIONBIO, &NonBlockingMode); int nZero = 0; setsockopt(ServerSocket, SOL_SOCKET, SO_SNDBUF, (char *)&nZero, sizeof(nZero));*/ //Заполнение адресной структуры sockaddr_in и привязка ее к сокету int SASize = sizeof(struct sockaddr_in); memset(&ServerAddress, 0, SASize); ServerAddress.sin_family = AF_INET; ServerAddress.sin_port = htons(SERVER_PORT); ServerAddress.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); wsaError = bind(ServerSocket, (struct sockaddr*)&ServerAddress, SASize); //Привязка if ( wsaError == SOCKET_ERROR ) { printf( "bind() failed.\n" ); closesocket(ServerSocket); return 1; } nServerAcceptShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //Событие завершения потока Accept nServerAcceptEvent = WSACreateEvent(); //Создание события WSAEventSelect(ServerSocket, nServerAcceptEvent, FD_ACCEPT); //Связываем сокет и событие nServerAcceptEvent с FD_ACCEPT nServerAcceptThread = CreateThread(0, 0, ServerAcceptThread, (void*)ServerSocket, 0, &nServerAcceptThreadID); //Создание потока для обработки входящих подключений //Установка сокета в прослушивающий режим wsaError = listen(ServerSocket, SERVER_MAX_CONNECTION); if ( wsaError == SOCKET_ERROR ) { printf( "Error listening on socket.\n"); return 1; } printf( "Server Started.\n"); //Sleep(32140800); //Засыпаем на 1 год //Цикл для основного потока while (true) { Sleep(1000); } wsaError = closesocket(ServerSocket); if (wsaError == SOCKET_ERROR) { wsaError = WSAGetLastError(); //Обработка ошибки //Логи } //Закрываем IOCP if (CloseHandle(nIOCPort) != S_OK) { //Ошибка CloseHandle //Обработка ошибки //Логи } //Удаляем события остановки для потока входях подключений. CloseHandle(nServerAcceptShutdownEvent); //Чистим Winsock wsaError = WSACleanup(); if (wsaError == SOCKET_ERROR) { wsaError = WSAGetLastError(); //Обработка ошибки //Логи } return 0; } DWORD WINAPI ServerAcceptThread(LPVOID lpParam) { SOCKET ListenSocket = (SOCKET)lpParam; SOCKET ClientSocket = INVALID_SOCKET; sockaddr_in ClientAddress; const int nClientLength = sizeof(ClientAddress); PSClient sClient; PSClientOverlapped sClientOverlapped; DWORD dwFlags = 0; DWORD dwBytes = 0; WSANETWORKEVENTS WSAEvents; while (WAIT_OBJECT_0 != WaitForSingleObject(nServerAcceptShutdownEvent, 0)) { if (WSA_WAIT_TIMEOUT != WSAWaitForMultipleEvents(1, &nServerAcceptEvent, FALSE, WSA_INFINITE, FALSE)) { WSAEnumNetworkEvents(ListenSocket, nServerAcceptEvent, &WSAEvents); //FD_ACCEPT на серверном сокете if ((WSAEvents.lNetworkEvents & FD_ACCEPT) && (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT])) { ClientSocket = WSAAccept(ListenSocket, (struct sockaddr*)&ClientAddress, (int*)&nClientLength, NULL, NULL); if (ClientSocket == INVALID_SOCKET) { continue; } printf( "ClientSocket == %d\n", ClientSocket); //Инициализация и подготовка к Recv if ((sClient = (PSClient) GlobalAlloc(GPTR, sizeof(SClient))) == NULL) { printf("GlobalAlloc(sClient) failed with error %d\n", GetLastError()); delete sClient; closesocket(ClientSocket); ClientSocket = INVALID_SOCKET; continue; } ZeroMemory(sClient, cSClientSize); sClient->scSocket = ClientSocket; sClient->scAddress = ClientAddress; sClient->scFree = 0; sClient->scLockStatus = 0; sClient->scParams = 0; sClient->scType = 0; HANDLE hTemp = CreateIoCompletionPort((HANDLE)sClient->scSocket, nIOCPort, (DWORD)sClient, 0); if (NULL == hTemp) { printf( "Error associate port with socket. CreateIoCompletionPort(): %ld\n", GetLastError() ); delete sClient; ClientSocket = INVALID_SOCKET; } //printf("hTemp == %d; GetLastError() == %d\n", hTemp, GetLastError()); if ((sClientOverlapped = (PSClientOverlapped) GlobalAlloc(GPTR, sizeof(SClientOverlapped))) == NULL) { printf("GlobalAlloc(sClientOverlapped) failed with error %d\n", GetLastError()); delete sClient; closesocket(ClientSocket); ClientSocket = INVALID_SOCKET; continue; } ZeroMemory(&(sClientOverlapped->scOverlapped), sizeof(WSAOVERLAPPED)); /*sClientOverlapped->scOverlapped.hEvent = 0; sClientOverlapped->scOverlapped.Internal = 0; sClientOverlapped->scOverlapped.InternalHigh = 0; sClientOverlapped->scOverlapped.Offset = 0; sClientOverlapped->scOverlapped.OffsetHigh = 0; sClientOverlapped->scOverlapped.Pointer = 0;*/ ZeroMemory(&(sClientOverlapped->scBuffer), DATA_BUFSIZE); sClientOverlapped->scDataBuf.buf = sClientOverlapped->scBuffer; //Подготавливаем WSABUF sClientOverlapped->scDataBuf.len = DATA_BUFSIZE; sClientOverlapped->scOperation = OPERATION_READ; sClientOverlapped->scRecvBytes = 0; sClientOverlapped->scSendBytes = 0; //Делаем первый Recv dwFlags = 0; int nRecvResult = WSARecv(sClient->scSocket, &(sClientOverlapped->scDataBuf), 1, &dwBytes, &dwFlags, &(sClientOverlapped->scOverlapped), NULL); if ((SOCKET_ERROR == nRecvResult) && (WSA_IO_PENDING != WSAGetLastError())) { printf("Error in first WSARecv()\n"); } /*while ((nRecvResult == SOCKET_ERROR) && (WSAGetLastError() == WSA_IO_PENDING)) { int nRecvResult = WSARecv(sClient->scSocket, &(sClientOverlapped->scDataBuf), 1, &dwBytes, &dwFlags, &(sClientOverlapped->scOverlapped), NULL); //continue; }*/ printf("nRecvResult == %d; WSAGetLastError() == %d\n", nRecvResult, WSAGetLastError()); } } } return 0; } DWORD WINAPI ServerWorkThread(LPVOID lpParam) { DWORD dwBytesTransfered = 0; //void *lpContext = NULL; WSAOVERLAPPED *lpOverlapped; bool IOResult; PSClient sClient; PSClientOverlapped sClientOverlapped; DWORD dwFlags = 0; DWORD dwBytes = 0; while (true) { IOResult = GetQueuedCompletionStatus(nIOCPort, &dwBytesTransfered, (LPDWORD)&sClient, (LPWSAOVERLAPPED*)&sClientOverlapped, INFINITE); if (NULL == sClient/*lpContext*/) { printf("SERVER CRASH!!!!"); break; } if ((FALSE == IOResult) || ((TRUE == IOResult) && (0 == dwBytesTransfered))) { //printf( "Error GetQueuedCompletionStatus(): %ld\n", GetLastError() ); printf("Closing socket == %d\n", sClient->scSocket); //delete sClient; GlobalFree(sClient); GlobalFree(sClientOverlapped); continue; } //printf("IOResult == %d; GetLastError() == %d\n", IOResult, GetLastError()); //WSABUF *p_wbuf = &(sClient->scDataBuf); //OVERLAPPED *p_ol = &(sClient->scOverlapped); dwFlags = 0; dwBytes = 0; int nRecvResult = 0; int nSendResult = 0; char c; switch (sClientOverlapped->scOperation) { case OPERATION_READ: //Закончилась операция приема данных printf( "Operation RECV is complete\n"); ZeroMemory(&(sClientOverlapped->scBuffer), DATA_BUFSIZE); //Очищаем для новых данных sClientOverlapped->scDataBuf.buf = sClientOverlapped->scBuffer; //Подготавливаем WSABUF sClientOverlapped->scDataBuf.len = DATA_BUFSIZE; sClientOverlapped->scOperation = OPERATION_READ; //Определяем следующую операцию чтения //Делаем Recv nRecvResult = WSARecv(sClient->scSocket, &(sClientOverlapped->scDataBuf), 1, &dwBytes, &dwFlags, &(sClientOverlapped->scOverlapped)/, NULL); //if ((nRecvResult == SOCKET_ERROR) && (WSAGetLastError() == WSA_IO_PENDING)) continue; printf("nRecvResult == %d; WSAGetLastError() == %d\n", nRecvResult, WSAGetLastError()); //ZeroMemory(&(sClient->scOverlapped), sizeof(WSAOVERLAPPED)); break; case OPERATION_WRITE: printf( "Operation SEND is complete\n"); break; } }//while return 0; }