select 다중 단일 스레드 서버
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#pragma warning(disable: 4996)
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <winsock2.h>
#include <conio.h>
#include <tchar.h>
#else
#include <socket.h>
#endif
#include <vector>
//Buffer Length
#define MAX_BUFFER_LEN 256
class CClientContext //To store and manage client related information
{
private:
int m_nTotalBytes;
int m_nSentBytes;
SOCKET m_Socket; //accepted socket
char m_szBuffer[MAX_BUFFER_LEN];
CClientContext * m_pNext; //this will be a singly linked list
public:
//Get/Set calls
void SetTotalBytes(int n)
{
m_nTotalBytes = n;
}
int GetTotalBytes()
{
return m_nTotalBytes;
}
void SetSentBytes(int n)
{
m_nSentBytes = n;
}
void IncrSentBytes(int n)
{
m_nSentBytes += n;
}
int GetSentBytes()
{
return m_nSentBytes;
}
void SetSocket(SOCKET s)
{
m_Socket = s;
}
SOCKET GetSocket()
{
return m_Socket;
}
void SetBuffer(char *szBuffer)
{
strcpy(m_szBuffer, szBuffer);
}
void GetBuffer(char *szBuffer)
{
strcpy(szBuffer, m_szBuffer);
}
char* GetBuffer()
{
return m_szBuffer;
}
void ZeroBuffer()
{
ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
}
CClientContext* GetNext()
{
return m_pNext;
}
void SetNext(CClientContext *pNext)
{
m_pNext = pNext;
}
//Constructor
CClientContext()
{
m_Socket = SOCKET_ERROR;
ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
m_nTotalBytes = 0;
m_nSentBytes = 0;
m_pNext = NULL;
}
//destructor
~CClientContext()
{
closesocket(m_Socket);
}
};
//Head of the client context singly linked list
CClientContext *g_pClientContextHead = NULL;
//Global FD Sets
fd_set g_ReadSet, g_WriteSet, g_ExceptSet;
//global functions
void AcceptConnections(SOCKET ListenSocket);
void InitSets(SOCKET ListenSocket);
int GetSocketSpecificError(SOCKET Socket);
CClientContext* GetClientContextHead();
void AddClientContextToList(CClientContext *pClientContext);
CClientContext* DeleteClientContext(CClientContext *pClientContext);
int main(int argc, char *argv[])
{
//Validate the input
if (argc < 2)
{
printf("
Usage: %s port.", argv[0]);
goto error;
}
// Initialize Winsock
WSADATA wsaData;
int nResult;
nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (NO_ERROR != nResult)
{
printf("
Error occurred while executing WSAStartup().");
return 1; //error
}
else
{
printf("
WSAStartup() successful.");
}
SOCKET ListenSocket;
int nPortNo;
struct sockaddr_in ServerAddress;
//Create a socket
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == ListenSocket)
{
printf("
Error occurred while opening socket: %ld.", WSAGetLastError());
goto error;
}
else
{
printf("
socket() successful.");
}
//Cleanup and Init with 0 the ServerAddress
ZeroMemory((char *)&ServerAddress, sizeof(ServerAddress));
//Port number will be supplied as a commandline argument
nPortNo = atoi(argv[1]);
//Fill up the address structure
ServerAddress.sin_family = AF_INET;
ServerAddress.sin_addr.s_addr = INADDR_ANY; //WinSock will supply address
ServerAddress.sin_port = htons(nPortNo); //comes from commandline
//Assign local address and port number
if (SOCKET_ERROR == bind(ListenSocket, (struct sockaddr *) &ServerAddress, sizeof(ServerAddress)))
{
closesocket(ListenSocket);
printf("
Error occurred while binding.");
goto error;
}
else
{
printf("
bind() successful.");
}
//Make the socket a listening socket
if (SOCKET_ERROR == listen(ListenSocket,SOMAXCONN))
{
closesocket(ListenSocket);
printf("
Error occurred while listening.");
goto error;
}
else
{
printf("
listen() successful.");
}
//This function will take are of multiple clients using select()/accept()
AcceptConnections(ListenSocket);
//Close open sockets
closesocket(ListenSocket);
//Cleanup Winsock
WSACleanup();
return 0; //success
error:
// Cleanup Winsock
WSACleanup();
return 1; //error
}
//Initialize the Sets
void InitSets(SOCKET ListenSocket)
{
//Initialize
FD_ZERO(&g_ReadSet);
FD_ZERO(&g_WriteSet);
FD_ZERO(&g_ExceptSet);
//Assign the ListenSocket to Sets
FD_SET(ListenSocket, &g_ReadSet);
FD_SET(ListenSocket, &g_ExceptSet);
//Iterate the client context list and assign the sockets to Sets
CClientContext *pClientContext = GetClientContextHead();
while(pClientContext)
{
if(pClientContext->GetSentBytes() < pClientContext->GetTotalBytes())
{
//We have data to send
FD_SET(pClientContext->GetSocket(), &g_WriteSet);
}
else
{
//We can read on this socket
FD_SET(pClientContext->GetSocket(), &g_ReadSet);
}
//Add it to Exception Set
FD_SET(pClientContext->GetSocket(), &g_ExceptSet);
//Move to next node on the list
pClientContext = pClientContext->GetNext();
}
}
//This function will loop on while it will manage multiple clients using select()
void AcceptConnections(SOCKET ListenSocket)
{
while (true)
{
InitSets(ListenSocket);
if (select(0, &g_ReadSet, &g_WriteSet, &g_ExceptSet, 0) > 0)
{
//One of the socket changed state, let's process it.
//ListenSocket? Accept the new connection
if (FD_ISSET(ListenSocket, &g_ReadSet))
{
sockaddr_in ClientAddress;
int nClientLength = sizeof(ClientAddress);
//Accept remote connection attempt from the client
SOCKET Socket = accept(ListenSocket, (sockaddr*)&ClientAddress, &nClientLength);
if (INVALID_SOCKET == Socket)
{
printf("
Error occurred while accepting socket: %ld.", GetSocketSpecificError(ListenSocket));
}
//Display Client's IP
printf("
Client connected from: %s", inet_ntoa(ClientAddress.sin_addr));
//Making it a non blocking socket
u_long nNoBlock = 1;
ioctlsocket(Socket, FIONBIO, &nNoBlock);
CClientContext *pClientContext = new CClientContext;
pClientContext->SetSocket(Socket);
//Add the client context to the list
AddClientContextToList(pClientContext);
}
//Error occured for ListenSocket?
if (FD_ISSET(ListenSocket, &g_ExceptSet))
{
printf("
Error occurred while accepting socket: %ld.", GetSocketSpecificError(ListenSocket));
continue;
}
//Iterate the client context list to see if any of the socket there has changed its state
CClientContext *pClientContext = GetClientContextHead();
while (pClientContext)
{
//Check in Read Set
if (FD_ISSET(pClientContext->GetSocket(), &g_ReadSet))
{
int nBytes = recv(pClientContext->GetSocket(), pClientContext->GetBuffer(), MAX_BUFFER_LEN, 0);
if ((0 == nBytes) || (SOCKET_ERROR == nBytes))
{
if (0 != nBytes) //Some error occured, client didn't close the connection
{
printf("
Error occurred while recieving on the socket: %d.", GetSocketSpecificError(pClientContext->GetSocket()));
}
//In either case remove the client from list
pClientContext = DeleteClientContext(pClientContext);
continue;
}
//Set the buffer
pClientContext->SetTotalBytes(nBytes);
pClientContext->SetSentBytes(0);
printf("
The following message was received: %s", pClientContext->GetBuffer());
}
//Check in Write Set
if (FD_ISSET(pClientContext->GetSocket(), &g_WriteSet))
{
int nBytes = 0;
if (0 < (pClientContext->GetTotalBytes() - pClientContext->GetSentBytes()))
{
nBytes = send(pClientContext->GetSocket(), (pClientContext->GetBuffer() + pClientContext->GetSentBytes()), (pClientContext->GetTotalBytes() - pClientContext->GetSentBytes()), 0);
if (SOCKET_ERROR == nBytes)
{
printf("
Error occurred while sending on the socket: %d.", GetSocketSpecificError(pClientContext->GetSocket()));
pClientContext = DeleteClientContext(pClientContext);
continue;
}
if (nBytes == (pClientContext->GetTotalBytes() - pClientContext->GetSentBytes()))
{
//We are done sending the data, reset Buffer Size
pClientContext->SetTotalBytes(0);
pClientContext->SetSentBytes(0);
}
else
{
pClientContext->IncrSentBytes(nBytes);
}
}
}
//Check in Exception Set
if (FD_ISSET(pClientContext->GetSocket(), &g_ExceptSet))
{
printf("
Error occurred on the socket: %d.", GetSocketSpecificError(pClientContext->GetSocket()));
pClientContext = DeleteClientContext(pClientContext);
continue;
}
//Move to next node on the list
pClientContext = pClientContext->GetNext();
}//while
}
else //select
{
printf("
Error occurred while executing select(): %ld.", WSAGetLastError());
return; //Get out of this function
}
}
}
//When using select() multiple sockets may have errors
//This function will give us the socket specific error
//WSAGetLastError() can't be relied upon
int GetSocketSpecificError(SOCKET Socket)
{
int nOptionValue;
int nOptionValueLength = sizeof(nOptionValue);
//Get error code specific to this socket
getsockopt(Socket, SOL_SOCKET, SO_ERROR, (char*)&nOptionValue, &nOptionValueLength);
return nOptionValue;
}
//Get the head node pointer
CClientContext* GetClientContextHead()
{
return g_pClientContextHead;
}
//Add a new client context to the list
void AddClientContextToList(CClientContext *pClientContext)
{
//Add the new client context right at the head
pClientContext->SetNext(g_pClientContextHead);
g_pClientContextHead = pClientContext;
}
//This function will delete the node and will return the next node of the list
CClientContext * DeleteClientContext(CClientContext *pClientContext)
{
//See if we have to delete the head node
if (pClientContext == g_pClientContextHead)
{
CClientContext *pTemp = g_pClientContextHead;
g_pClientContextHead = g_pClientContextHead->GetNext();
delete pTemp;
return g_pClientContextHead;
}
//Iterate the list and delete the appropriate node
CClientContext *pPrev = g_pClientContextHead;
CClientContext *pCurr = g_pClientContextHead->GetNext();
while (pCurr)
{
if (pCurr == pClientContext)
{
CClientContext *pTemp = pCurr->GetNext();
pPrev->SetNext(pTemp);
delete pCurr;
return pTemp;
}
pPrev = pCurr;
pCurr = pCurr->GetNext();
}
return NULL;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
React 구성 요소에서 소켓 이벤트 리스너가 여러 번 실행됩니다.기본적이지만 종종 간과되는 사이드 프로젝트를 하면서 배운 것이 있습니다. 이 프로젝트에는 단순히 두 가지 주요 부분이 포함되어 있습니다. 프런트 엔드: 반응 및 재료 UI 백엔드: Express, Typescript...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.