소켓프로그램 관련 질문입니다.

3권에서 새로 도입된 네트웍 및 멀티플레이어 프로그로그래밍 섹션을 위한 게시판입니다.

Moderator: 류광

Locked
비회원

소켓프로그램 관련 질문입니다.

Post by 비회원 »

안녕하세요 ㅠ 프로그램을 짜다가 안되는 부분이 있어서요;

bool AsNetwork::serverSetting(AsNetwork *_network)
{
if(WSAStartup(MAKEWORD(2, 2), &S_wsaData) != 0)
ErrorHandling("Server WSAStartup() error!");

InitializeCriticalSection(&CS);//크리티컬 섹션 생성

S_hServerSock = socket(PF_INET, SOCK_STREAM, 0); // 소켓 생성
if(S_hServerSock==INVALID_SOCKET)
ErrorHandling("Server socket() error");

memset(&S_ServerAddr, 0, sizeof(S_ServerAddr));

S_ServerAddr.sin_family = AF_INET;
S_ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
S_ServerAddr.sin_port = htons(dwPort);


//바인드원래자리

wantExitCheck = false;

S_AcceptThread = (HANDLE)_beginthreadex(NULL,0,severAccept,(void*)_network,0,(unsigned*)&S_AcceptThreadID);
if(S_AcceptThread == NULL)
{
ErrorHandling("Sever Error Thread");
}
CloseHandle(S_AcceptThread);

return true; // 서버라는 뜻
}

이렇게 서버에서 소켓을 만든후에

UINT WINAPI severAccept(void *arg)
{
AsNetwork *_network = reinterpret_cast<AsNetwork>(arg);

if(bind(_network->S_hServerSock,(SOCKADDR*)&_network->S_ServerAddr,sizeof(_network->S_ServerAddr))==SOCKET_ERROR)
_network->ErrorHandling("Sever bind() error");

if(listen(_network->S_hServerSock,5) == SOCKET_ERROR)
_network->ErrorHandling("Sever listen() error");

int clntLen = sizeof(_network->S_ClntAddr);
_network->S_hClntSock = accept(_network->S_hServerSock,(SOCKADDR*)&_network->S_ClntAddr,&clntLen);

memset(&_network->S_ClntAddr, 0, sizeof(_network->S_ClntAddr));


_network->acceptCheck = true;

GamePackets temp = {0,};
_network->makePacket(0,3,-1,_network->wt_id_Character,-1,-1,-1,&temp);
bool errcheck = AsQueue::outQueuePush(temp);
_network->makePacket(0,4,-1,_network->wt_id_Map,-1,-1,-1,&temp);
errcheck = AsQueue::outQueuePush(temp);
_network->makePacket(0,5,-1,_network->wt_id_Time,-1,-1,-1,&temp);
errcheck = AsQueue::outQueuePush(temp);
_network->makePacket(0,6,-1,_network->wt_id_Gold,-1,-1,-1,&temp);
errcheck = AsQueue::outQueuePush(temp);

_network->S_RecvThread =
(HANDLE)_beginthreadex(NULL,0,severRecvMSG,
(void*)_network,0,(unsigned*)&_network->S_RecvThreadID);
if(_network->S_RecvThread == NULL)
{
_network->ErrorHandling("Sever Error Thread");
}
CloseHandle(_network->S_RecvThread);

_endthreadex(0);
return 0;
}

이렇게 바인드 및 리슨을 합니다.

그리고 리시브에서 소켓을 종료 했을때
다시 유저를 접속시키기 위해서


closesocket(_network->S_hClntSock);
WSACleanup();
_network->S_AcceptThread = (HANDLE)_beginthreadex(NULL,0,severAccept,
(void*)_network,0,(unsigned*)&_network->S_AcceptThreadID);
if(_network->S_AcceptThread == NULL)
{
_network->ErrorHandling("Sever Error Thread");
}
CloseHandle(_network->S_AcceptThread);

이코드처럼 해지를 시키고 다시 UINT WINAPI severAccept(void *arg)
쓰래드를 불러옵니다.

그런데 바인드및 리슨에서 에러코드가 발생하하더라구요

리슨과 바인드는 사실 웨 서버세팅에서 있던 코드지만

엑셉트에서 블로킹이 안먹히는 관계로 밑으로 내린코드인데

정작 그래도 에러코드로 인해 엑셉트 코드에서 블로킹이 되지 않습니다.

이유를 모르겠어서 질문드리구요




또한 TerminateThread 함수 말고
_beginthreadex 쓰래드 함수를 쓰래드 외부에서 해지할수있는 방법이 없을까요
_endthreadex 함수는 쓰래드 내무에서만 발생하는 함수라 외부에서 리스브에서
블로킹된 쓰래드를 꺼서 효율적으로 소켓을 해지시키고 싶은데
방법이 없내요 ㅠ

혹시 해지하는 코드나 더좋은 방법이 있다면 답변 부탁드립니다!!
꼮요!
chadr
Posts: 980
Joined: 2003-06-01 12:28
Location: 모대학
Contact:

Post by chadr »

closesocket(_network->S_hClntSock);
WSACleanup();
_network->S_AcceptThread = (HANDLE)_beginthreadex(NULL,0,severAccept,
(void*)_network,0,(unsigned*)&_network->S_AcceptThreadID);

이렇게 소켓을 닫고 윈속까지 정리해버리시면 이후 모든 소켓 관련 api는 사용을 하지 못합니다.

WSACleanup은 어플리케이션이 종료될때 한번 해주시면 되고 소켓을 닫으셨으면 socket함수로 다시 소켓을 만드셔야합니다.

좀더 부연설명 하자면 WSAStartup윈속을 사용 할 수 있도록 관련 dll을 로딩하고 초기화하는 과정을 수행합니다. 이 함수를 호출하지 않으면 소켓 관련 함수는 모두 에러를 내고 사용하지 못합니다. 이 함수의 반대 함수로 WSACleanup는 윈속 관련 dll을 메모리에서 삭제하는 과정을 수행합니다. 따라서 이 함수를 호출하면 모든 소켓 관련 함수는 사용하지 못합니다.

그런데 궁금한게 왜 바인드 및 리슨 하는 경우를 스레드에서 따로 하시는지요? 일반적으로 서버의 셋업은 같은 스레드에서 한꺼번에 한번만 해도 무방합니다.

그리고 이건 구조상 문제인데.. 클라이언트 1개당 한개의 스레드를 생성할려고 하시는가요? 공부 목적이라면 경험해보는 것도 상관 없지만 스레드는 가능한 적게 만드시고 한번 만든 스레드는 서버가 종료되기 전까지 종료하지 않고 스레드 내부에서 가능한 많은 일을 해주는 것이 성능상 유리합니다.

또한 스레드는 외부에서 강제 종료를 시키는 것보다 자동적으로 리턴코드에 도달하여 스스로 종료가 되도록 놔두는 것을 추천합니다. 또한 스레드 메인 함수가 리턴 되면 스레드에 관련된 리소스는 자동적으로 해제되므로 명시적으로 스레드 메인 함수의 리턴 부분에 스레드 종료 함수를 호출 할 필요는 없습니다.

그냥 테스트와 공부 목적이 아니라면 설계를 다시 하실걸 권해드립니다.
비회원

감사합니다 ㅠ

Post by 비회원 »

감사합니다 ㅠ 좋은답변 됬습니다.
Locked