[질문] 소켓프로그래밍인데....좀 봐주세여

pcguy7의 이미지

비동기 소켓이 작동이 안하는것 같아요..
서버에서 패킷을 보내두 소켓이벤트가 발생하지 않는것 같아요...
뭐가 잘못된건지..아시는 분은 답변좀 해주세여..제발요...

참고로 헤더파일은 생략할께여..

#include "KOREA client.h"					


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow )
{
	MSG msg;

	// 소켓 초기화
	WSADATA wsaData;
	WSAStartup( MAKEWORD( 2, 2 ), &wsaData );


	// 윈도우 클래스 초기화
	WNDCLASS	wndclass;
	wndclass.style         = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc   = WndProc;
	wndclass.cbClsExtra    = 0;
	wndclass.cbWndExtra    = 0;
	wndclass.hInstance     = hInstance;
	wndclass.hIcon         = NULL;
	wndclass.hCursor       = LoadCursor( NULL, IDC_ARROW );
	wndclass.hbrBackground = CreateSolidBrush( RGB( 255, 255, 255 ) );
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;

	// 클래스 등록
	RegisterClass( &wndclass );

		

	// 메인 윈도우 생성
	HWND hwnd = CreateWindow(	szAppName,
								szAppName, 
								WS_SYSMENU | WS_VISIBLE | WS_MINIMIZEBOX,
								200,						// 윈도우 좌상단 좌표
								200,
								360,						// 윈도우 크기
								440,
								NULL,
								NULL,						// 메뉴 핸들
								hInstance,
								NULL );

	// 윈도우 화면 표시
	ShowWindow( hwnd, nCmdShow );
	UpdateWindow( hwnd );
	
	g_hWnd = hwnd;
	g_hInst = hInstance;

	// 메시지 루프
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}

	// 소켓 종료화
	WSACleanup();

	return (int) msg.wParam ;
}

/*************************************************************************************************************/
/*																											 */
/* 1. 윈도우 프로시저																					     */
/* 2. 윈도우에서 발행한 메시지를 처리한다.																	 */
/*																											 */
/*************************************************************************************************************/
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message )
	{
		HANDLE_MSG(hWnd, WM_CREATE,	     OnCreate);
		HANDLE_MSG(hWnd, WM_SOCKEVENT,   OnSockEvent);
		HANDLE_MSG(hWnd, WM_LBUTTONDOWN, OnLButtonDown);
		HANDLE_MSG(hWnd, WM_PAINT,       OnPaint);
		HANDLE_MSG(hWnd, WM_DESTROY,     OnDestroy);
	}

	return DefWindowProc( hWnd, message, wParam, lParam );
}

// 디버거용
void OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
	
}

// WM_CREATE 메시지 핸들러
BOOL OnCreate( HWND hWnd, LPCREATESTRUCT lpCreateStruct )
{
	// 메인 윈도우 표시하기 전에 IP 적는 다이얼로그 박스 표시
	DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_LOGIN), hWnd, DialogProc, IDD_LOGIN);
	return TRUE;
}

// WM_PAINT 메시지 핸들러
void OnPaint(HWND hWnd)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int y = 1;

	hdc = BeginPaint(hWnd, &ps);

	EndPaint(hWnd, &ps);
}


// WM_DESTROY 메시지 핸들러
// 1. 프로그램을 종료시킵니다.
void OnDestroy( HWND hWnd )
{
	PostQuitMessage( 0 );
}

/*************************************************************************************************************/
/*																											 */
/* 1. 다이얼로그 프로시저																				     */
/* 2. 다이얼로그에서  발행한 메시지를 처리한다.																 */
/*																											 */
/*************************************************************************************************************/
BOOL CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		HANDLE_MSG(hWndDlg, WM_INITDIALOG, OnInitDialog);
		HANDLE_MSG(hWndDlg, WM_COMMAND,    OnDlgCommand);
	}

	return FALSE;
}

// WM_INITDIALOG 메시지 핸들러
BOOL OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam)
{
	// IP 콘트롤에 포커스 옮김
	SetFocus(GetDlgItem(hWnd, IDC_IP));
	return TRUE;
}

// WM_COMMAND 메시지 핸들러
void OnDlgCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify)
{
	// 다일얼로그 박스에 확인 버튼을 누르면
	if (id == IDOK)
	{
		DWORD dwIP;
		char ID[STRSIZE];
		sockaddr_in ServerAddr;
	
		// IP 주소 저장한다
		SendMessage(GetDlgItem(hWnd, IDC_IP), IPM_GETADDRESS, 0, (LPARAM)&dwIP);

		// ID 를 읽어온다
		GetDlgItemText(hWnd, IDC_ID, ID, sizeof(ID));

		// 소켓 생성
		if ((g_hClientSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
		{
			MessageBox(hWnd, "socket() 함수 에러", NULL, MB_OK);
			return;
		}

		// 주소 구조체 0 으로 초기화
		ZeroMemory(&ServerAddr, sizeof(ServerAddr));

		// 서버 주소 구조체 설정
		ServerAddr.sin_family      = AF_INET;
		ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
		ServerAddr.sin_port        = htons(PORT);

		// 연결요청을 하고 실패하면 에러 표시
		if (connect(g_hClientSocket, (sockaddr *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
		{
			MessageBox(hWnd, "connect() 함수 에러", NULL, MB_OK);
			return;
		}
		// 연결 요청이 되면
		else
		{
			// 접속함과 동시에 ID 를 전송
			// 서버는 받은 ID 를 g_hClientDataList 리스트에 저장한다
			SendPacket(g_hClientSocket, PACKET_LOGIN, ID, lstrlen(ID));
         // 여기에서 소켓을 비동기로 설정했는데 작동이 안되는것 같아요...왜 그런거죠??
			// 클라이언트 소켓을 비동기 소켓으로 전환
			if (WSAAsyncSelect(g_hClientSocket, hWnd, WM_SOCKEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
			{
				MessageBox(hWnd, "WSAAsyncSelect() 함수 에러", NULL, MB_OK);
				return;
			} 

			EndDialog(hWnd, 0);
		}
	}
	// 취소 버튼을 누르면
	else if (id == IDCANCEL)
	{
		EndDialog(hWnd, 0);
		PostQuitMessage(0);
	}
}

/*************************************************************************************************************/
/*																											 */
/* 1. 소켓 이벤트 메시지 핸들러에서 발생한 이벤트에 대한 함수 처리										     */
/*																											 */
/*************************************************************************************************************/
void OnSockEvent( HWND hWnd, SOCKET socket, int nEvent, int nErrorCode )
{
	MessageBox(hWnd, "OnSockEvent 함수 호출", NULL, MB_OK);

	switch (nEvent)
	{
		case FD_READ :
			OnRead(hWnd, socket);
			break;
			
		case FD_CLOSE :
			OnClose(hWnd, socket);
			break; 
	}
}


// FD_READ 소켓 이벤트 메시지 핸들러
// 데이터가 들어오는걸 수신한다
void OnRead(HWND hWnd, SOCKET socket)
{
	PACKETFLAG PacketFlag;
	char *pData = NULL;
	int nDataSize;

	// 데이터 수신
	if (ReadPacket(hWnd, socket, &nDataSize, &PacketFlag, &pData) == FALSE)
	{
		MessageBox(hWnd, "ReadPacket() 함수 에러", NULL, MB_OK);
		return;
	}

	// 데이터 가공 수신
	ProcessClientPacket(socket, PacketFlag, pData, nDataSize);

	delete [] pData;
}

void OnClose(HWND hWnd, SOCKET socket)
{
	MessageBox(hWnd, "서버 프로그램이 종료되었습니다", NULL, MB_OK);
	closesocket(socket);
	PostQuitMessage(0);
}

/*************************************************************************************************************/
/*																											 */
/* 1. 그 밖의 함수들	                                              									     */
/*																											 */
/*************************************************************************************************************/

// 1. 패킷을 읽어옵니다. 읽어올 때, 헤더와 데이터를 분리합니다.
// 2. 헤더나 데이터 전체를 읽기 전까지 프로그램은 블로킹 상태에 빠집니다.
// 3. 예기치 않은 소켓 에러가 발생하면, 프로그램을 종료합니다.
// 4. ppData 인자에 동적으로 할당한 메모리를 반환합니다.
//    따라서, 이 함수를 호출한 곳에서 반드시 메모리를 책임지고 해제해야 합니다.
BOOL ReadPacket( HWND hwnd, SOCKET socket, int* pDataSize, PACKETFLAG* pPacketFlag, char** ppData )
{
	// 패킷 헤더 읽기 : 패킷 길이 + 패킷 식별자
	int pHeader[2];
	int nRecvSize = 0, nTotalRecvSize = 0;

	while( nTotalRecvSize < sizeof( pHeader ) )
	{
		nRecvSize = recv( socket, (char*) pHeader + nTotalRecvSize, sizeof( pHeader ) - nTotalRecvSize, 0 );
		if( nRecvSize != SOCKET_ERROR )
		{
			nTotalRecvSize += nRecvSize;
			continue;
		}

		if( WSAGetLastError() != WSAEWOULDBLOCK )
		{
			assert( FALSE );
			FORWARD_WM_DESTROY( hwnd, SendMessage );
		}
	
		return FALSE;
	} 

	assert( nTotalRecvSize == sizeof( pHeader ) );

	// 패킷 데이터 읽기 : 패킷 길이 - 헤더 길이
	int nDataSize = pHeader[0] - nTotalRecvSize;
	char* pPacketData = new char[nDataSize+1];
	pPacketData[nDataSize] = '\0';

	nTotalRecvSize = 0;
	while( nTotalRecvSize < nDataSize )
	{
		nRecvSize = recv( socket, pPacketData + nTotalRecvSize, nDataSize - nTotalRecvSize, 0 );
		if( nRecvSize != SOCKET_ERROR )
		{
			nTotalRecvSize += nRecvSize;
			continue;
		}

		if( WSAGetLastError() != WSAEWOULDBLOCK )
		{
			assert( FALSE );
			FORWARD_WM_DESTROY( hwnd, SendMessage );
	
			return FALSE;
		}
	} 
	
	assert( nTotalRecvSize == nDataSize );

	// 데이터 반환
	*pDataSize   = nDataSize;
	*pPacketFlag = (PACKETFLAG) pHeader[1];
	*ppData      = pPacketData;

	return TRUE;
}

// 1. 서버 프로그램으로 전달된 패킷을 처리합니다.
// 2. 처리된 패킷을 가공해서 한다.
void ProcessClientPacket( SOCKET socket, PACKETFLAG PacketFlag, char* pData, int nDataSize )
{
	switch( PacketFlag )
	{
		case PACKET_CURRENTUSER :
			MessageBox(g_hWnd, pData, "서버에 현재 접속자", MB_OK);
			break;

		case PACKET_CLOSE :
			MessageBox(g_hWnd, pData, "접속자 연결 종료알림", MB_OK);
			break; 

		default :
			assert( FALSE );
	}
}

// 1. 패킷 전송 함수.
// 2. 모든 종류의 패킷을 내부적으로 구성한 후 전송.
// 3. 문자열 데이터의 경우, 길이에 NULL 문자는 포함하지 않습니다.
int SendPacket( SOCKET socket, PACKETFLAG PacketFlag, void* pData, int nDataSize )
{
	static char pPacket[1024];

	// 패킷 전체 길이 계산
	int nPacketSize = sizeof( int ) + sizeof( PacketFlag ) + nDataSize;

	// 에러 처리
	if( nPacketSize >= sizeof( pPacket ) )
		return 0;

	// 패킷 구성 : 순서대로 패킷 길이, 패킷 식별자, 데이터 복사
	MoveMemory( pPacket, &nPacketSize, sizeof( int ) );
	MoveMemory( pPacket + sizeof( int ), & PacketFlag, sizeof( PacketFlag ) );
	MoveMemory( pPacket + sizeof( int ) + sizeof( PacketFlag ), pData, nDataSize );
    pPacket[nPacketSize] = '\0';

	// 전송
	return send( socket, pPacket, nPacketSize, 0 );
}

왜 비동기 소켓이 작동을 안하는 것일까요...
패키을 서버에서 분명히 보냈는데..send() 로
왜 받지를 못할까요...제발 답변좀 부탁드립니다..
완전한 파일 압축해서 첨부했습니다..

File attachments: 
첨부파일 크기
Package icon 서버&클라이언트.zip930.54 KB
codebank의 이미지

BOOL CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch (uMsg)
   {
      HANDLE_MSG(hWndDlg, WM_INITDIALOG, OnInitDialog);
      HANDLE_MSG(hWndDlg, WM_COMMAND,    OnDlgCommand);
   }

   return FALSE;
}

저부분이 잘못된건 아닌지요???
BOOL CALLBACK DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch (uMsg)
   {
      HANDLE_MSG(hWndDlg, WM_INITDIALOG, OnInitDialog);
      HANDLE_MSG(hWndDlg, WM_COMMAND,    OnDlgCommand);
      HANDLE_MSG(hWndDlg, WM_SOCKEVENT, OnSockEvent);
   }

   return FALSE;
}

뭐 대충 저렇게라도 해야 메시지가 도착했을때 프로시져가 처리하지 않을까요?

------------------------------
좋은 하루 되세요.

pcguy7의 이미지

WM_SOCKEVENT 메시지는 다이얼로그프로시저에 전달되는게 아니라...

메인윈도우로 전달되는 걸로 알로 있는데여...

아닌가여? 아닌가.....-_-;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.