노출되는 이미지가 불편하시겠지만 양해를 구합니다. 노출, 클릭등에 관한 자료로 활용 중입니다.

OnTimer - SetTimer


작업1) 메시지를 등록한다.


WM_TIMER->OnTimer을 추가하면

void SetTimerTestDlg::OnTimer(UINT_PTR nIDEvent)
{
    CDialog::OnTimer(nIDEvent);
}

가 자동으로 생성이 된다.. 



작업 2) 그리고 두개의 함수를 만들어 준다.

void SetTimerTestDlg::OnStartTimer()
{

    //1은 ID, 1000는 시간(ms)
    SetTimer(1, 30*1000, 0);  // 30초에 한번 실행
}

void SetTimerTestDlg::OnStopTimer()
{

    // 타이머 종료 
    KillTimer(1);
}


*  추가 설명

// OnStartTimer()은 타이머 시작 이고
// OnStopTimer()은 타이머 중지 이다.

void SetTimerTestDlg::OnTimer(UINT_PTR nIDEvent)
{

    printf(" timer called \n");
    CDialog::OnTimer(nIDEvent);
}


라고 실행할 명령어( 테스트로 printf)를 입력하고 OnStartTimer를 실행하면
1초에 한 번씩 프린트를 실행하게 된다.

타이머 종료할때는 OnStopTimer()를 실행하면된다.


블로그 이미지

StartGuide

I want to share the basic to programming of each category and how to solve the error. This basic instruction can be extended further. And I have been worked in southeast Asia more than 3 years. And I want to have the chance to work another country.

,
노출되는 이미지가 불편하시겠지만 양해를 구합니다. 노출, 클릭등에 관한 자료로 활용 중입니다.

C# Packet Class

바이트 버퍼링 전송 수신 send receive

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;

namespace LClient
{
    public partial class Packet
    {
        NetworkStream _stream;
        BinaryWriter _writer;

        byte[] _buffer;
        byte[] _data;

        public void setStream( NetworkStream stream )
        {
            _stream = stream;
            _writer = new BinaryWriter(_stream);
        }

        public void read()
        {
            byte[] blen = new byte[4];
            int read = _stream.Read(blen, 0, blen.Length);
            int ilen = BitConverter.ToInt32(blen,0);
            
            _data = new byte[ilen];
            _stream.Read(_data, 0, ilen);

        }
        public int readInt()
        {
            //보관
            byte[] t = new byte[_data.Length];
            Array.Copy(_data, 0, t, 0, _data.Length);

            byte[] idata = new byte[4];
            Array.Copy(_data, 0, idata, 0, idata.Length);

            _data = new byte[t.Length - idata.Length];
            Array.Copy(t, idata.Length, _data, 0, _data.Length);

            return BitConverter.ToInt32(idata, 0);
        }

        public String readUTF8()
        {
            //보관
            byte[] t = new byte[_data.Length];
            Array.Copy(_data, 0, t, 0, _data.Length);

            byte[] sl = new byte[2];
            Array.Copy(_data, 0, sl, 0, sl.Length );
            short slen = BitConverter.ToInt16(sl,0);

            byte[] sd = new byte[slen];
            Array.Copy(_data, 0, sd, 0, sd.Length);

            if ( t.Length < sl.Length+slen )
            {
                return null;
            }
            else 
            {
                _data = new byte[t.Length - (sl.Length + sd.Length)];

                Array.Copy(t,(sl.Length+sd.Length),
                            _data,0, _data.Length);

                return Encoding.UTF8.GetString(sd);
            }

        }

        public void WriteInt( int num )
        {
            if (_buffer == null)
            {
                _buffer = BitConverter.GetBytes(num);
            }
            else
            {

                byte[] b = BitConverter.GetBytes(num);

                byte[] t = new byte[_buffer.Length];
                Array.Copy(_buffer, 0, t, 0, _buffer.Length);

                _buffer = new byte[t.Length + b.Length];

                Array.Copy(t, 0, _buffer, 0, t.Length);
                Array.Copy(b, 0, _buffer, t.Length, b.Length);
            }

        }

        public void WriteUTF( String str )
        {
            if (_buffer == null)
            {
                byte[] b = Encoding.UTF8.GetBytes(str);
                byte[] a = BitConverter.GetBytes((short)b.Length);

                _buffer = new byte[a.Length + b.Length];

                Array.Copy(a, 0, _buffer, 0, a.Length);
                Array.Copy(b, 0, _buffer, a.Length, b.Length);
            }
            else
            {
                byte[] t = new byte[_buffer.Length];
                Array.Copy(_buffer, 0, t, 0, _buffer.Length);
                byte[] b = Encoding.UTF8.GetBytes(str);
                byte[] a = BitConverter.GetBytes((short)b.Length);

                _buffer = new byte[t.Length + a.Length + b.Length];

                Array.Copy(t, 0, _buffer, 0, t.Length);
                Array.Copy(a, 0, _buffer, t.Length, a.Length);
                Array.Copy(b, 0, _buffer, t.Length + a.Length, b.Length);

            }
                
        }

        public void Flush()
        {
            // size
            _writer.Write(_buffer.Length);

            // data
            _stream.Write(_buffer, 0, _buffer.Length);

            _stream.Flush();
        }

        public int getLength()
        {
            return _buffer.Length;
        }
        public byte[] getData()
        {
            return _data;
        }
    }
}


'Application, App > VC++' 카테고리의 다른 글

OnTimer - SetTimer  (0) 2016.12.15
Stack with std::list  (0) 2016.12.15
Effective C++ 목차  (0) 2016.12.15
IO Completion Port 작성하기 ( 2010.10.06 )  (0) 2016.12.15
블로그 이미지

StartGuide

I want to share the basic to programming of each category and how to solve the error. This basic instruction can be extended further. And I have been worked in southeast Asia more than 3 years. And I want to have the chance to work another country.

,
노출되는 이미지가 불편하시겠지만 양해를 구합니다. 노출, 클릭등에 관한 자료로 활용 중입니다.

Stack with std::list

#pragma once

#include 
#include 

/*
	Size : Unlimited
	I/O : LIFO, FIFO
*/

template
class NLStack
{
public :
	enum OutType
	{
		LIFO = 0,
		FIFO = 1,
	};
private:
	NLStack()
	{
		Clear();
	}

public:
	NLStack(int out) : m_Out(out)
	{
		Clear();	
	}

	void Clear()
	{
		if ( m_Stack.empty() == false )
		{
			m_Stack.clear();
		}
	}
	int Count() 
	{
		return static_cast( m_Stack.size() ) ;
	}

	bool IsEmpty() 
	{
		return m_Stack.empty();
	}

	// store data 
	void Push( T data )
	{
		m_Stack.push_back( data );
	}
	// extract data
	bool Pop ( T*data )
	{
		if ( IsEmpty() )
			return false;

		switch( m_Out)
		{
		case FIFO:
			//FIFO
			memcpy( data, &m_Stack.front(), sizeof(T) );
			m_Stack.pop_front();
			break;
		case LIFO:
			//LIFO
			memcpy( data, &m_Stack.back(), sizeof(T) );
			m_Stack.pop_back();
			break;
		}
		return true;
	}
	void SetOutType( int out )
	{
		m_Out = out; 
	}

private:
	std::list 	m_Stack;
	int				m_Out;
};



블로그 이미지

StartGuide

I want to share the basic to programming of each category and how to solve the error. This basic instruction can be extended further. And I have been worked in southeast Asia more than 3 years. And I want to have the chance to work another country.

,
노출되는 이미지가 불편하시겠지만 양해를 구합니다. 노출, 클릭등에 관한 자료로 활용 중입니다.


 Effective C++ 목차




목차

Chapter 1. C++에 왔으면 C++의 법을 따릅시다.
 항목 1. C++를 언어들의 연합체로 바라보는 안목은 필수
 항목 2. #define을 쓰려거든 const, enum, inline을 떠올리자.  - #define 컴파일 에러시 디버깅 어려움
 항목 3. 낌새만 보이면 const를 들이대 보자! - const 외부 변경 불가능
 항목 4. 객체를 사용하기 전에 반드시 그 객체를 초기화하자.
 

 Chapter 2. 생성자, 소멸자 및 대입 연산자
 항목 5. C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자.
 항목 6. 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해 버리자.
 항목 7. 다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자.
 항목 8. 예외가 소멸자를 떠나지 못하도록 붙들어 놓자.
 항목 9. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자.
 항목 10. 대입 연산자는 *this의 참조자를 반환하게 하자.
 항목 11. operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자.
 항목 12. 객체의 모든 부분을 빠짐없이 복사하자.
 

 Chapter 3. 자원 관리
 항목 13. 자원 관리에는 객체가 그만!
 항목 14. 자원 관리 클래스의 복사 동작에 대해 진지하게 고찰하자.
 항목 15. 자원 관리 클래스에서 관리되는 자원은 외부에서 접근할 수 있도록 하자.
 항목 16. new 및 delete를 사용할 때는 형태를 반드시 맞추자.
 항목 17. new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자.
 

 Chapter 4. 설계 및 선언
 항목 18. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자.
 항목 19. 클래스 설계는 타입 설계와 똑같이 취급하자.
 항목 20. '값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대게 낫다.
 항목 21. 함수에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자.
 항목 22. 데이터 멤버가 선언될 곳은 private 영역임을 명심하자.
 항목 23. 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자.
 항목 24. 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자.
 항목 25. 예외를 던지지 않는 swap에 대한 지원도 생각해보자.
 

 Chapter 5. 구현 
 항목 26. 변수 정의는 늦출 수 있는 데 까지 늦추는 근성을 발휘하자.
 항목 27. 캐스팅은 절약, 또 절약! 잊지 말자.
 항목 28. 내부에서 사용하는 객체에 대한 "핸들"을 반환하는 코드는 되도록 피하자.
 항목 29. 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자!
 항목 30. 인라인 함수는 미주알고주알 따져서 이해해 두자.
 항목 31. 파일 사이의 컴파일 의존성을 최대로 줄이자.
 

 Chapter 6. 상속, 그리고 객체 지향 설계 
 항목 32. public 상속 모형은 반드시 "is-a"를 따르도록 만들자.
 항목 33. 상속된 이름을 숨기는 일은 피하자.
 항목 34. 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자.
 항목 35. 가상 함수 대신 쓸 것들도 생각해 두는 자세를 시시때때로 길러 두자.
 항목 36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물!
 항목 37. 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자.
 항목 38. "has-a" 혹은 "is-implemented-in-terms-of"를 모형화 할때는 객체 합성을 사용하자.
 항목 39. private 상속은 심사숙고해서 구사하자.
 항목 40. 다중 상속은 심사숙고해서 사용하자.
 

 Chapter 7. 템플릿과 일반화 프로그래밍
 항목 41. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터
 항목 42. typename의 두 가지 의미를 제대로 파악하자.
 항목 43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자.
 항목 44. 매개변수에 독립적인 코드는 템플릿으로부터 분리시키자.
 항목 45. "호환되는 모든 타입"을 받아들이는 데는 멤버 함수 템플릿이 직방!
 항목 46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자.
 항목 47. 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자.
 항목 48. 템플릿 메타프로그래밍, 하지 않겠는가?
 

 Chapter 8. new와 delete를 내 맘대로
 항목 49. new 처리자의 동작 원리를 제대로 이해하자.
 항목 50. new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 두자.
 항목 51. new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘 알아 두자.
 항목 52. 위치지정 new를 작성한다면 위치지정 delete도 같이 준비하자.

  Chapter 9. 그 밖의 이야기들
 항목 53. 컴파일러 경고를 지나치지 말자.
 항목 54. TR1을 포함한 표준 라이브러리 구성요소와 편안한 친구가 되자.
 항목 55. Boo자유친! 부스트를 늘 여러분 가까이에
 


http://kelly.springnote.com/pages/552442

블로그 이미지

StartGuide

I want to share the basic to programming of each category and how to solve the error. This basic instruction can be extended further. And I have been worked in southeast Asia more than 3 years. And I want to have the chance to work another country.

,
노출되는 이미지가 불편하시겠지만 양해를 구합니다. 노출, 클릭등에 관한 자료로 활용 중입니다.

IO Completion Port 작성 하기





1. MFC 프로젝트 - 다이얼로그 방식

프로젝트명 : IOCompletionPort 

생성 : 
자동 ( IOCompletionPortDlg.h / IOCompletionPortDlg.cpp / class CIOCompletionPort() {} /
        로 생김(자동으로 C가 붙음) )


2. 다이얼로그에  ListBox Control 추가

---- 흠

3. 버튼을 옮겨서 : 서버 시작 버튼을 만들고.....클릭시 함수처리부분에서 호출 및 사용될  class 정의


4.  class 정의 :  cIOCompletionPort

5. 클래스 마법사에서 ListBox 멤버 변수 작성 - IOCompletionPortDlg.cpp
6. ListBox에 문자 출력하는 함수 작성 - IOCompletionPortDlg.cpp
IOCompletionPortDlg.h
// 흠 흠 흠
#include "afxwin.h"
#include "resource.h"

#include "cIOCompletionPort.h"

#define	LISTEN_PORT		8000

///..........

public:
	void OutputMsg(char * szOutputString,...);
	CListBox m_ctOutput;
	boolean		m_bServerStarted;
	cIOCompletionPort m_IOCompletionPort;

	afx_msg void OnBnClickedStartserver();
	afx_msg void OnBnClickedCancel();



IOCompletionPortDlg.cpp
/// 사용자 추가
void CIOCompletionPortDlg::OutputMsg(char * szOutputString,...)
{

	char szOutStr[1024];
	va_list argptr;

	va_start(argptr, szOutputString) ;
	vsprintf( szOutStr, szOutputString, argptr );
	va_end(argptr);

	
	//  CListBox에 추가

	// 속성 - > 구성속성->일반 -> 멀티 바이트 문자 조합 MBCS
	//m_ctOutput.SetCurSel( m_ctOutput.AddString( szOutStr ) );

	m_ctOutput.InsertString(0, szOutStr) ;

}



void CIOCompletionPortDlg::OnBnClickedStartserver()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.

		if ( ! m_bServerStarted  ) {
			OutputMsg("0.----서버 ");

			m_IOCompletionPort.SetMainDlg(this);
			bool bRet = m_IOCompletionPort.InitSocket();

			OutputMsg("1.----포트:%d", LISTEN_PORT );
			m_IOCompletionPort.BindandListen(LISTEN_PORT);

			OutputMsg("2.----가동 " );
			m_IOCompletionPort.StartServer();

			m_bServerStarted=true;
		} else {
			OutputMsg("****************서버 가동중 : 누르지 마세요 ******************");
		}

}


void CIOCompletionPortDlg::OnBnClickedCancel()
{
	// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.

	m_IOCompletionPort.DestroyThread();

	CDialogEx::OnCancel();
}


cIOCompletionPort.h
// 1. 패킷 사이즈
#define MAX_SOCKBUF		1024
// 2. 클라이언트 수
#define		MAX_CLIENT	1024
// 3. 쓰레스 수
#define		MAX_WORKERTHREAD	4


enum	enumOperation {
	OP_RECV,
	OP_SEND
};

/// WSAOVERLAPPED 구조체를 확장시켜 필요한 정보 추가
struct stOverlappedEx {
	WSAOVERLAPPED		m_wsaOverlapped;	// Overlapped I/O 구조체
	SOCKET				m_socketClient;		// client socket
	WSABUF				m_wsaBuf;			// Overlapped I/O 작업 버퍼
	char				m_szBuf[MAX_SOCKBUF];	// 데이타 버퍼
	enumOperation		m_eOperation;			// 작업 동작 종류
};
/// client 정보를 담기 위한 구조체
struct	stClientInfo {
	SOCKET				m_socketClient;		// 클라이언트와 연결되는 소켓
	stOverlappedEx		m_stRecvOverlappedEx;	// Recv Overlapped I/O 작업을 위한 변수
	stOverlappedEx		m_stSendOverlappedEx;	// Send Overlapped I/O 작업을 위한 변수

	/// 생성자에서 멤버 변수들을 초기화
	stClientInfo() 
	{
		m_socketClient = INVALID_SOCKET;
		ZeroMemory( &m_stRecvOverlappedEx, sizeof(m_stRecvOverlappedEx) );
		ZeroMemory( &m_stSendOverlappedEx, sizeof(m_stSendOverlappedEx) );
	}
};


class CIOCompletionPortDlg;

class cIOCompletionPort
{
public:
	cIOCompletionPort(void);
	~cIOCompletionPort(void);
	bool InitSocket(void);

	bool BindandListen(int nPort);
	bool StartServer(void);
	bool CreateWorkerThread(void);
	bool CreateAccepterThread(void);
	stClientInfo * GetEmptyClientInfo(void);
	bool BindIOCompletionPort(stClientInfo * pClientInfo);

	bool BindRecv(stClientInfo * pClientInfo);
	bool SendMsg(stClientInfo * pClientInfo, char * pMsg, int nLen);
	void WorkerThread(void);
	void AccepterThread(void);
	void SetMainDlg(CIOCompletionPortDlg * pMainDlg);
	void DestroyThread(void);
	void CloseSocket(stClientInfo * pClientInfo, bool bIsForce=false);
private:
	// 1. 클라이언트 정보 저장 구조체
	stClientInfo *	m_pClientInfo;

	// 2. 클라이언트 접속을 받기위한 리슨 소켓
	SOCKET			m_socketListen;

	// 3. 접속 되어 있는 클라이언트 수
	int				m_nClientCnt;

	// 4. 메인 윈도우 포인터
	CIOCompletionPortDlg *		m_pMainDlg;

	// 5. 작업 스레드 핸들
	HANDLE			m_hWorkerThread[MAX_WORKERTHREAD];

	// 6. 접속 스레드 핸들
	HANDLE			m_hAccepterThread;

	// 7. CompletionPort 객체 핸들
	HANDLE			m_hIOCP;

	// 8. 작업 스레드 동작 플래그
	bool			m_bWorkerRun;

	// 9. 접속 스레드 동작 플래그
	bool			m_bAccepterRun;

	// 10. 소켓 버퍼
	char			m_szBuf[1024];

};



cIOCompletionPort.cpp
#include "StdAfx.h"

#include "cIOCompletionPort.h"

//// 흠
#include "IOCompletionPortDlg.h"

/// 쓰레드 만들기 
/// WSARecv , WSASend의 Overlapped I/O 작업을 위한 
unsigned int WINAPI	CallWorkerThread(LPVOID p)
{
	cIOCompletionPort * pOverlappedEvent = (cIOCompletionPort *)p;

	pOverlappedEvent->WorkerThread();

	return 0;
}
unsigned int WINAPI	CallAccepterThread(LPVOID p)
{
	cIOCompletionPort * pOverlappedEvent = (cIOCompletionPort *)p;

	pOverlappedEvent->AccepterThread();

	return 0;
}
/// 
cIOCompletionPort::cIOCompletionPort(void)
{
	/// 모든 멤버 변수들의 초기화
	m_pMainDlg = NULL;
	m_bWorkerRun	= true;
	m_bAccepterRun	= true;
	m_nClientCnt = 0;
	m_hAccepterThread = NULL;
	m_hIOCP	= NULL;
	m_socketListen = INVALID_SOCKET;
	ZeroMemory(m_szBuf, 1024);
	for ( int i=0; i < MAX_WORKERTHREAD; i++ ) {
		m_hWorkerThread [i] = NULL;
	}
	m_pClientInfo = new stClientInfo[MAX_CLIENT];
}


cIOCompletionPort::~cIOCompletionPort(void)
{
	// 윈속 사용 해재
	WSACleanup();
	// 다 사용한 객체 삭제
	if ( m_pClientInfo ) 
	{
		delete[] m_pClientInfo;
		m_pClientInfo = NULL;
	}
}


bool cIOCompletionPort::InitSocket(void)
{
	WSADATA	wsaData;

	// 윈속 버젼 2.2
	int nRet = WSAStartup( MAKEWORD(2,2) , &wsaData);
	if ( 0 != nRet ) {

		m_pMainDlg->OutputMsg("[에러]WSAStartup() 실패:%d:",WSAGetLastError() );

		return false;
	}
	m_socketListen = WSASocket(AF_INET, SOCK_STREAM,
					IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED );

	if ( INVALID_SOCKET == m_socketListen ) {

		m_pMainDlg->OutputMsg("[에러]WSASocket() 실패:%d:",WSAGetLastError() );

		return false;

	}
	m_pMainDlg->OutputMsg(" InitSocket() 성공" );
	///
	return true;
}




bool cIOCompletionPort::BindandListen(int nPort)
{

	SOCKADDR_IN		stServerAddr;

	stServerAddr.sin_family = AF_INET;

	stServerAddr.sin_port = htons(nPort);

	stServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

	int nRet = bind( m_socketListen, (SOCKADDR *)&stServerAddr, sizeof(SOCKADDR_IN) );
	if ( 0 != nRet ) {

		m_pMainDlg->OutputMsg("[에러] bind() 실패:%d:",WSAGetLastError() );

		return false;

	}
	nRet = listen( m_socketListen, 5 ) ;
	if ( 0 != nRet ) {

		m_pMainDlg->OutputMsg("[에러] listen() 실패:%d:",WSAGetLastError() );

		return false;

	}
	m_pMainDlg->OutputMsg(" BindandListen() 성공" );
	///
	return true;
}





bool cIOCompletionPort::CreateWorkerThread(void)
{

	unsigned int uiThreadId = 0;

	/// Waiting Thread Queue에 대기 상태로 넣을 쓰레드들 생성
	/// 권장하는 개수 : cpu *2 +1

	for ( int i =0; i < MAX_WORKERTHREAD; i++ ) 
	{

		m_hWorkerThread[i] = (HANDLE)_beginthreadex(NULL, 0,
							&CallWorkerThread,
							this,
							CREATE_SUSPENDED,
							&uiThreadId);
		if ( m_hWorkerThread[i] == NULL ) 
		{
			m_pMainDlg->OutputMsg("[에러] CreateWorkerThread() 실패:%d:",GetLastError() );

			return false;
		}
		ResumeThread( m_hWorkerThread[i] );
	}


	m_pMainDlg->OutputMsg(" CreateWorkerThread() 성공" );
	///
	return true;
}


bool cIOCompletionPort::CreateAccepterThread(void)
{

	unsigned int uiThreadId = 0;

	/// 클라이언트 접속 요청을 받은 쓰레드 생성
	m_hAccepterThread = (HANDLE)_beginthreadex(NULL, 0,
						&CallAccepterThread,
						this,
						CREATE_SUSPENDED,
						&uiThreadId);
	if ( m_hAccepterThread == NULL ) 
	{
		m_pMainDlg->OutputMsg("[에러] CreateAccepterThread() 실패:%d:",GetLastError() );

		return false;
	}
	ResumeThread( m_hAccepterThread );


	m_pMainDlg->OutputMsg(" CreateAccepterThread() 성공" );
	///
	return true;
}
////
bool cIOCompletionPort::BindIOCompletionPort(stClientInfo * pClientInfo)
{

	HANDLE hIOCP;

	/// socket 과 pClientInfo를  CompletionPort객체와 연결 시킨다.
	hIOCP = CreateIoCompletionPort( (HANDLE)pClientInfo->m_socketClient,
			m_hIOCP,
			reinterpret_cast( pClientInfo ),
			0);
	if ( NULL == hIOCP || m_hIOCP != hIOCP ) 
	{
		m_pMainDlg->OutputMsg("[에러] CreateIoCompletionPort() 실패:%d:",GetLastError() );

		return false;
	}


	m_pMainDlg->OutputMsg(" BindIOCompletionPort() 성공" );
	///
	return true;
}

bool cIOCompletionPort::StartServer(void)
{


	m_hIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE,
								NULL,
								NULL,
								0);
	if ( NULL == m_hIOCP ) 
	{
		m_pMainDlg->OutputMsg("[에러] CreateIoCompletionPort() 실패:%d:",GetLastError() );

		return false;
	}

	
	bool bRet = CreateWorkerThread();
	if ( false == bRet ) 
	{
		m_pMainDlg->OutputMsg("[에러] CreateWorkerThread() 실패:%d:",GetLastError() );

		return false;
	}

	bRet = CreateAccepterThread();
	if ( false == bRet ) 
	{
		m_pMainDlg->OutputMsg("[에러] CreateAccepterThread() 실패:%d:",GetLastError() );

		return false;
	}

	m_pMainDlg->OutputMsg(" StartServer() 성공" );
	///
	return true;
}

	
bool cIOCompletionPort::BindRecv(stClientInfo * pClientInfo)
{
	DWORD	dwFlag = 0;
	DWORD	dwRecvNumBytes = 0;


	// Overlapped I/O Setting
	pClientInfo->m_stRecvOverlappedEx.m_wsaBuf.len = MAX_SOCKBUF;
	pClientInfo->m_stRecvOverlappedEx.m_wsaBuf.buf = 
		pClientInfo->m_stRecvOverlappedEx.m_szBuf;
	pClientInfo->m_stRecvOverlappedEx.m_eOperation = OP_RECV;

	
	//// 입력 버퍼 클리어 ???????????????
	//ZeroMemory(pClientInfo->m_stRecvOverlappedEx.m_szBuf, 1024);

	int nRet = WSARecv( pClientInfo->m_socketClient,
						&(pClientInfo->m_stRecvOverlappedEx.m_wsaBuf),
						1,
						&dwRecvNumBytes,
						&dwFlag,
						(LPWSAOVERLAPPED)&(pClientInfo->m_stRecvOverlappedEx),
						NULL);
	/// socket_error 이면 client socket이 끊어 진걸로 처리한다.
	if ( nRet ==  SOCKET_ERROR && ( ERROR_IO_PENDING != WSAGetLastError()  )  ) 
	{
		m_pMainDlg->OutputMsg("[에러] BindRecv WSARecv() 실패 WSAGetLastError:%d:",WSAGetLastError() );

		return false;
	}
	m_pMainDlg->OutputMsg("[알림] BindRecv WSARecv() 성공");
	return true;
}


bool cIOCompletionPort::SendMsg(stClientInfo * pClientInfo, char * pMsg, int nLen)
{
	DWORD	dwRecvNumBytes = 0;

	//전송될 메시지를 복사
	CopyMemory( pClientInfo->m_stSendOverlappedEx.m_szBuf, pMsg, nLen );


	// Overlapped I/O Setting 정보
	pClientInfo->m_stSendOverlappedEx.m_wsaBuf.len = nLen;

	pClientInfo->m_stSendOverlappedEx.m_wsaBuf.buf =
							pClientInfo->m_stSendOverlappedEx.m_szBuf;

	pClientInfo->m_stSendOverlappedEx.m_eOperation = OP_SEND;

	int nRet = WSASend( pClientInfo->m_socketClient, 
						&(pClientInfo->m_stSendOverlappedEx.m_wsaBuf),
						1,
						&dwRecvNumBytes,
						0,
						(LPWSAOVERLAPPED)&(pClientInfo->m_stSendOverlappedEx),
						NULL);
	if ( nRet == SOCKET_ERROR ) {
		m_pMainDlg->OutputMsg("[에러] SendMsg WSASend() nRet:%s:","SOCKET_ERROR" );
	}
	/// socket_error 이면 client socket이 끊어 진걸로 처리한다.
	if ( nRet ==  SOCKET_ERROR && ( WSAGetLastError() != ERROR_IO_PENDING )  ) 
	{
		m_pMainDlg->OutputMsg("[에러] SendMsg WSASend() 실패 WSAGetLastError:%d:",WSAGetLastError() );

		return false;
	}
			
	m_pMainDlg->OutputMsg("[알림] SendMsg WSASend() 성공");

	return true;
}
// 할당
stClientInfo * cIOCompletionPort::GetEmptyClientInfo(void)
{
	for(int i = 0; i < MAX_CLIENT; i++ ) 
	{
		if(INVALID_SOCKET == m_pClientInfo[i].m_socketClient) 
		{
			return &m_pClientInfo[i];
		}
	}
	return NULL;
}



// 사용자 접속 받는 쓰레드
void cIOCompletionPort::AccepterThread(void)
{
	SOCKADDR_IN		stClientAddr;

	int nAddrLen = sizeof(SOCKADDR_IN);
	while ( m_bAccepterRun)
	{
		// 접속 받을 구조체 인덱스 얻기
		stClientInfo * pClientInfo = GetEmptyClientInfo();
		if ( NULL == pClientInfo )
		{
			m_pMainDlg->OutputMsg("[에러] NULL == pClientInfo :%s:","Client FULL");

			return ;
		}
		// 클라이언트 접속 요청까지 대기
		pClientInfo->m_socketClient = accept ( m_socketListen,
							(SOCKADDR *)&stClientAddr, &nAddrLen );
		if ( INVALID_SOCKET == pClientInfo->m_socketClient ) {
			continue;
		}
		// I/O Completion Port객체와 소켓을 연결 시킨다.
		bool bRet = BindIOCompletionPort( pClientInfo );
		if ( false == bRet ) {
			return;
		}
		// Recv Overlapped I/O 작업을 요청한다
		bRet = BindRecv(pClientInfo);
		if ( false == bRet ) {
			return;
		}

		m_pMainDlg->OutputMsg("[클라이언트 접속] ip(%s) SOCKET(%d)",
			inet_ntoa( stClientAddr.sin_addr) ,
			pClientInfo->m_socketClient);

		m_nClientCnt ++;

	}
}


void cIOCompletionPort::WorkerThread(void)
{
	// CompletionKey를 받을 포인터 변수
	stClientInfo * pClientInfo = NULL;

	// 함수 호출 성공여부
	BOOL bSuccess = TRUE;

	// Overlapped I/O작업에서 전송된 데이타 크기
	DWORD dwIoSize = 0;

	// I/O 작업을 위해 요청한 Overlapped 구조체를 받을 포인터
	LPOVERLAPPED lpOverlapped = NULL;

	while ( m_bWorkerRun ) 
	{
		/**
		이 함수로 인해 쓰래들들은 WaitingThread Queue에 대기상태로 들어간다
		완료된 Overlapped I/O 작업이 발생하면 IOCP Queue에서 완료된 작업을 가져와 뒤처리
		그리고 PostQueuedCompletionStatus()함수에 의해 사용자 메시지가 도착되면 쓰레드 종료
		**/
		bSuccess = GetQueuedCompletionStatus( m_hIOCP,
				&dwIoSize,							// 실제 전송된 바이트
				(LPDWORD)&pClientInfo,				// Completionkey
				&lpOverlapped,						// Overlappped I/O 객체
				INFINITE);							// 대기할 시간(무한대기)
		
		// 클라이언트가 접속 끊었을 때
		//
		//  FALSE == bSuccess
		//
		if ( FALSE == bSuccess && 0 == dwIoSize ) 
		{
			m_pMainDlg->OutputMsg("[클라이언트] SOCKET(%d) 접속 끊김",	pClientInfo->m_socketClient);
			CloseSocket(pClientInfo);
			continue;
		}

		// 사용자 스레드 종료 메시지 처리
		//
		//  TRUE == bSuccess
		//

		if ( TRUE == bSuccess && 0 == dwIoSize && NULL == lpOverlapped )
		{
			//
			// WorkerThread 종료
			//
			m_bWorkerRun = false ;
			continue;
		}

		if ( NULL == lpOverlapped ) {
			continue;
		}
		stOverlappedEx * pOverlappedEx =(stOverlappedEx *)lpOverlapped;

		// Overlapped I/O Recv 작업 결과 뒤 처리
		// 
		//	OP_RECV
		//
		if ( OP_RECV == pOverlappedEx->m_eOperation ) 
		{
			pOverlappedEx->m_szBuf[dwIoSize] = NULL;
			m_pMainDlg->OutputMsg("[수신] ( %d ) bytes , msg : %s ",dwIoSize,pOverlappedEx->m_szBuf);

			// 클라이언트에 메시지를 에코한다.
			//BindRecv( pClientInfo );

			//SendMsg(pClientInfo, pOverlappedEx->m_szBuf, dwIoSize );

			//pOverlappedEx->m_eOperation = OP_SEND;
			//BindRecv( pClientInfo );

			SendMsg( pClientInfo, pOverlappedEx->m_szBuf, dwIoSize);

		}
		// Overlapped I/O Send 작업 결과 뒤 처리
		// 
		//	OP_SEND
		//
		else if ( OP_SEND == pOverlappedEx->m_eOperation ) 
		{
			m_pMainDlg->OutputMsg("[송신] ( %d ) bytes , msg : %s ",dwIoSize,pOverlappedEx->m_szBuf);
			
			//// 입력 버퍼 클리어 ???????????????
			ZeroMemory(pOverlappedEx->m_szBuf, 1024);

			BindRecv( pClientInfo );

		}
		else 
		{
			m_pMainDlg->OutputMsg("[클라이언트] SOCKET(%d) 예외 상황 ",pClientInfo->m_socketClient);
		}
		lpOverlapped = NULL;
	}
}

void cIOCompletionPort::SetMainDlg(CIOCompletionPortDlg * pMainDlg)
{
	/// .h에서 .cpp로 옮겨 놓았는데? 문제 없나?
	m_pMainDlg = pMainDlg;
}


void cIOCompletionPort::DestroyThread(void)
{
	for(int i=0; i< MAX_WORKERTHREAD; i++)
	{
		// WaitingThreadQueue에서 대기중인 쓰레드에 사용자 종료 메시지 보내기
		PostQueuedCompletionStatus( m_hIOCP,0,0,NULL);
	}
	for(int i=0; i< MAX_WORKERTHREAD; i++)
	{
		CloseHandle( m_hWorkerThread[i] );
		WaitForSingleObject ( m_hWorkerThread[i], INFINITE );
	}

	m_bAccepterRun = false;
	// Accepter Thread 종료
	closesocket( m_socketListen );
	// Thread 종료
	WaitForSingleObject( m_hAccepterThread, INFINITE );


}


void cIOCompletionPort::CloseSocket(stClientInfo * pClientInfo, bool bIsForce)
{
	struct linger stLinger = {0,0};

	if ( true ) {
		// timeout=0으로 설정되어 강제 종료. 주의 : 데이타 손실 가능성
		// right now !!!
		stLinger.l_onoff = 1;
	}
	// 데이타 송수신 모두 중단
	shutdown( pClientInfo->m_socketClient, SD_BOTH );

	// 소켓 옵션
	setsockopt( pClientInfo->m_socketClient, SOL_SOCKET, SO_LINGER,
			(char *)&stLinger, sizeof(stLinger) );
	// 소켓 연결 종료
	closesocket(pClientInfo->m_socketClient);
	pClientInfo->m_socketClient = INVALID_SOCKET;
}


'Application, App > VC++' 카테고리의 다른 글

OnTimer - SetTimer  (0) 2016.12.15
Packet Class // 바이트 버퍼링 전송 수신 send receive  (0) 2016.12.15
Stack with std::list  (0) 2016.12.15
Effective C++ 목차  (0) 2016.12.15
블로그 이미지

StartGuide

I want to share the basic to programming of each category and how to solve the error. This basic instruction can be extended further. And I have been worked in southeast Asia more than 3 years. And I want to have the chance to work another country.

,