'MFC/Serial & Socket'에 해당되는 글 3건
- 2010.12.17 SingleLock
- 2010.11.29 Server에서 멀티소켓 관리하기
- 2010.11.29 Thread를 사용해서 Socket관리하기
CSingleLock는 Base Class가 없습니다.
CSingleLock 클래스의 객체는 다중 스레드 프로그램의 리소스에 대한 액세스를 제어에 사용되는 액세스 제어 메커니즘을 나타냅니다.
동기화 클래스인 CSemaphore, CMutex, CCriticalSection, 그리고 CEvent를 사용하기 위해서는, 당신은 CSingleLock 또는 CMultiLock중 Object 중 하나를 꼭 동기화 될 객체를 기다려야 합니다. CSingleLock은 사용자가 한 번에 하나의 객체를 기다릴 때 사용하고 CMultiLock은 여러 개의객체가 있을 때 특정한 시간에 사용할 수 있습니다.
CSingleLock
CSingleLock 개체 CSyncObject에서 파생 개체의 존재를 필요로합니다. 이것은 보통 관리 리소스의 클래스의 데이터 멤버입니다.
class CSingleLock { // Constructors public: CSingleLock(CSyncObject* pObject, BOOL bInitialLock = FALSE); // Operations public: BOOL Lock(DWORD dwTimeOut = INFINITE); BOOL Unlock(); BOOL Unlock(LONG lCount, LPLONG lPrevCount = NULL); BOOL IsLocked(); // Implementation public: ~CSingleLock(); protected: CSyncObject* m_pObject; HANDLE m_hObject; BOOL m_bAcquired; }; ///////////////////////////////////////////////////////////////////////////// // CMultiLock class CMultiLock { // Constructor public: CMultiLock(CSyncObject* ppObjects[], DWORD dwCount, BOOL bInitialLock = FALSE); // Operations public: DWORD Lock(DWORD dwTimeOut = INFINITE, BOOL bWaitForAll = TRUE, DWORD dwWakeMask = 0); BOOL Unlock(); BOOL Unlock(LONG lCount, LPLONG lPrevCount = NULL); BOOL IsLocked(DWORD dwItem); // Implementation public: ~CMultiLock(); protected: HANDLE m_hPreallocated[8]; BOOL m_bPreallocated[8]; CSyncObject* const * m_ppObjectArray; HANDLE* m_pHandleArray; BOOL* m_bLockedArray; DWORD m_dwCount; };
'MFC > Serial & Socket' 카테고리의 다른 글
Server에서 멀티소켓 관리하기 (0) | 2010.11.29 |
---|---|
Thread를 사용해서 Socket관리하기 (0) | 2010.11.29 |
메신저 서버에서는 클라이언트가 접속할 때 마다 Thread를 생성해서 소켓을 붙여서 관리한다
그렇게 되면 접속된 소켓을 저장하고 메시지를 보낼 소켓을 찾아서 그 소켓에게만 메시지를 보내는 등의 관리가 필요하다
CObList m_Socklist; |
CObject를 저장할 수 있는 리스트 변수이다.
pDlg->m_Socklist.AddTail(pThread); pDlg->m_Accetpcnt = pDlg->m_Socklist.GetCount(); |
Accept가 이루어지면 해당 스레드를 리스트의 맨 뒤에 추가한다
그 후 리스트에 저장된 객체의 수를 읽어와서 현재 접속자를 계산한다.
void CIntSocket::RECEIVE_LOGIN() { CDENT_MSG_SERVERDlg* p = (CDENT_MSG_SERVERDlg*)m_pWnd; char* buf = new char[1024]; memset(buf,0x00,1024); DWORD dwREAD = Receive(buf,1024); if(CheckLastError(GetLastError()) != 0) { CString lastERR; lastERR.Format("[%d] 에러발생",CheckLastError(GetLastError())); TRACE("%s",lastERR); return; } CString msg = buf; delete buf; p->m_memberL.AddString(msg); SendMsg* m = new SendMsg(0x01,msg,sizeof(msg)); p->SendMessage(SEND_ALL_USER,(WPARAM)m,0); } |
afx_msg void CDENT_MSG_SERVERDlg::SendAllUser(WPARAM w,LPARAM l) { SendMsg* m = (SendMsg*)w; CString msg = m->GetMsg(); int size = m->GetSize(); int header = m ->GetHeader(); m_CriticalSection.Lock(); CSockThread* pSock; POSITION pos =m_Socklist.GetHeadPosition(); int result; while (pos != NULL) { pSock = (CSockThread*)m_Socklist.GetAt(pos); result = pSock->m_CIntSocket.Send(&header,4); if(CheckLastError(GetLastError()) != 0) { CString lastERR; lastERR.Format("[%d] 에러발생",CheckLastError(GetLastError())); TRACE("%s",lastERR); return; } Sleep(5); result = pSock->m_CIntSocket.Send(msg,size); if(CheckLastError(GetLastError()) != 0) { CString lastERR; lastERR.Format("[%d] 에러발생",CheckLastError(GetLastError())); TRACE("%s",lastERR); return; } Sleep(5); m_Socklist.GetNext(pos); } m_CriticalSection.Unlock(); delete m; } |
저장된 Thread의 소켓을 사용하여 각각의 소켓으로 Send하는 함수이다.
SendMessage를 이용하여 받은 메시지를 구조체화 시켜 그 구조체의 포인터를 넘겨받아 데이터를 풀고 해당 데이터를 처음부터 끝까지 저장된 Thread의 소켓에 Send해준다.
<채팅메세지이기 때문에 전체 접속자에게 모두 뿌려준다>
'MFC > Serial & Socket' 카테고리의 다른 글
SingleLock (0) | 2010.12.17 |
---|---|
Thread를 사용해서 Socket관리하기 (0) | 2010.11.29 |
소켓통신을 할 때 짧은 메시지는 빠르게 Send/Receive하기 때문에 못 느끼지만 용량이 큰 파일을 보내거나 받을 때 Thread를 사용하지 않으면 프로그램이 응답 없음 상태로 되어 버린다.
그래서 파일전송을 할 때에는 서버에서는 접속하는 Socket이 생길 때 마다 Socket을 생성하고 Thread를 생성하여 Thread안에 소켓을 붙여서 관리하면 프로그램이 응답 없음 상태가 되는 것을 막을 수 있다.
소켓을 Thread에 붙이려면 두 가지 함수가 필요하다
BOOL CAsyncSocket::Attach(SOCKET hSocket, long lEvent) { ASSERT(hSocket != INVALID_SOCKET); m_hSocket = hSocket; CAsyncSocket::AttachHandle(hSocket, this); return AsyncSelect(lEvent); } |
SOCKET CAsyncSocket::Detach() { SOCKET hSocket = m_hSocket; if (AsyncSelect(0)) { CAsyncSocket::KillSocket(hSocket, this); m_hSocket = INVALID_SOCKET; return hSocket; } return INVALID_SOCKET; } |
Detach()함수는 해당 소켓을 분리하는 것이고 Attach()함수는 인자로 받은 소켓을 자신이 갖고있는 소켓변수에 붙이는 역할을 한다.
void CServSocket::OnAccept(int nErrorCode) { CIntSocket sock; Accept(sock); CSockThread* pThread = (CSockThread*)AfxBeginThread (RUNTIME_CLASS(CSockThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED); if(!pThread) { sock.Close(); TRACE("Thread could not be Created\n"); return; } //thread에 변수 초기화 CDENT_MSG_SERVERDlg* pDlg = (CDENT_MSG_SERVERDlg*)m_pWnd; pThread->m_CIntSocket.SetDlg(pDlg); pThread->m_CIntSocket.m_CriticalSection = &pDlg->m_CriticalSection; pThread->m_CIntSocket.m_FilePath = &pDlg->m_DlgFilePath; pThread->m_CIntSocket.m_pThread = (CWinThread*)pThread; //접속자 추가 CString ipnum = sock.GetUserIP(); pDlg->m_memberL.AddString(ipnum); pDlg->UpdateData(TRUE); // pThread->m_CIntSocket.SEND_LOING_MSG_ALL(ipnum,pDlg); SendMsg* m = new SendMsg(0x01,ipnum,ipnum.GetLength()); pDlg->SendMessage(SEND_ALL_USER,(WPARAM)m,0); pThread->m_hSocket = sock.Detach();//스레드에 소켓을 분리하여 소켓의 핸들을 넘겨준다 pDlg->m_Socklist.AddTail(pThread); sock.m_pThread = pThread; pThread->ResumeThread(); pDlg->m_Accetpcnt = pDlg->m_Socklist.GetCount(); pDlg->UpdateData(FALSE); //접속자리스트에 방금 접속한 현재 리스트를 전송한다 if(pDlg->m_Accetpcnt > 0) { pThread->m_CIntSocket.Send_LoginList(pThread); } CString _msg; _msg.Format("<<SYSTEM MESSAGE>> [%s] LOGIN",ipnum); pDlg->m_log.AddString(_msg); CSocket::OnAccept(nErrorCode); } |
메신저에서 Accept가 되었을 때 쓰레드를 생성하고 여러 개의 Socket을 관리하기 위하여 리스트에 스레드를 저장한다.
CSockThread* pThread = (CSockThread*)AfxBeginThread
(RUNTIME_CLASS(CSockThread),THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
CREATE_SUSPENDED는 스레드를 생성하고 우선 대기상태로 생성하는 인자이며
pThread->ResumeThread(); 를 호출하는 순간 Thread가 실행되며 Thread의 InitInstance()함수가 실행된다.
pThread->m_hSocket = sock.Detach(); 부분은 Accept시칸 Socket을 분리하여 Thread의 소켓변수에 넣는다. 아직은 Thread에 소켓을 Attach 한 것이 아니기 때문에 완전하게 분리해서 붙인 것은 아니다
BOOL CSockThread::InitInstance() { m_CIntSocket.Attach(m_hSocket); return TRUE; } |
pThread->ResumeThread(); 를 호출하면 실행되는 Thread의 함수이다
Detach하여 받은 Socket변수를 Attach하는 부분이다
소켓을 Thread에 붙이는 순서로 서버 기준이며 클라이언트에서는 소켓이 Connect되면 이와 같은 방법으로 Thread에 소켓을 붙이게 된다
'MFC > Serial & Socket' 카테고리의 다른 글
SingleLock (0) | 2010.12.17 |
---|---|
Server에서 멀티소켓 관리하기 (0) | 2010.11.29 |