'MFC/Serial & Socket'에 해당되는 글 3건

  1. 2010.12.17 SingleLock
  2. 2010.11.29 Server에서 멀티소켓 관리하기
  3. 2010.11.29 Thread를 사용해서 Socket관리하기
MFC/Serial & Socket 2010. 12. 17. 11:55

CSingleLock Base Class 없습니다.

CSingleLock 클래스 객체 다중 스레드 프로그램 리소스에 대한 액세스 제어 사용되는 액세스 제어 메커니즘 나타냅니다.

동기화 클래스 CSemaphore, CMutex, CCriticalSection, 그리고 CEvent 사용하기 위해서는,  당신은 CSingleLock 또는 CMultiLock Object 하나를 동기화 객체를 기다려야 합니다. CSingleLock 사용자가 번에 하나의 객체를 기다릴 사용하고  CMultiLock 여러 개의객체가 있을 특정한 시간에 사용할 있습니다.


CSingleLock 개체 사용하려면 관리 리소스의 클래스 멤버 함수 내부 생성자 호출합니다. 그런 다음 리소스 사용할 있는지 확인하려면 IsLocked 멤버 함수 호출합니다. 경우, 멤버 함수 나머지 계속합니다. 리소스 사용할 수없는 경우, 릴리스 수있는 리소스에 대한 지정된 시간 금액 또는 반환 실패 기다립니다. CSingleLock 개체를 다시 사용하거나 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
:
MFC/Serial & Socket 2010. 11. 29. 11:59

메신저 서버에서는 클라이언트가 접속할 때 마다 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
:
MFC/Serial & Socket 2010. 11. 29. 10:43

소켓통신을 할 때 짧은 메시지는 빠르게 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가 실행되며 ThreadInitInstance()함수가 실행된다.

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
: