tcp recv 함수에서 문자열 수신 받지 못하는 문제 질문입니다.

balgarac1의 이미지

각기 다른 6개의 구조체 패킷을 주고 받습니다.
로그인 요청 구조체,
로그인 응답 구조체,

쿼리 요청 구조체,
쿼리 응답 구조체,

등등을 주고 받는데

클라이언트에서 프록시, 프록시에서 서버는 연결 설정은 됩니다만..
메세지 수신이 되지 않습니다..

해당 이벤트 마다(로그인 요청이 왔을 때는 로그인 요청 구조체로 recv 하는) 메세지 수신 하는 것보다

함수 하나 만들어놓고 큰 버퍼에 담은 뒤 메세지 타입을 보고 식별하는 식의 논리로 짰는데

만들어 놓은 함수의 첫번째 recv에서 수신이 안되고 있습니다..

왜 그런건가요... 가르침 부탁드립니다..

// 생성자
CNetwork::CNetwork()
{
	// 변수 초기화
	m_FdMax = 0;
	m_StrLen = 0;
	m_FdNum = 0;
	m_i = 0;
	m_nPacketSize = 0;
 
	m_SqlTypeRetValue = 0;
 
	UB2 m_ubMsgType = 0;
 
	bzero(m_szSqlText, sizeof(m_szSqlText));
	bzero(m_szTmp, sizeof(m_szTmp));
 
	m_pStr = NULL;
 
	m_pBuf = new char[2048];
	if(m_pBuf == NULL)
	{
		cout << "CNetwork Memomry Allocate fail" << endl;
		exit(1); //
	}
}
 
// 소멸자
CNetwork::~CNetwork()
{
	delete []m_pBuf; //
	close(m_nSock);
}
 
// 소켓 설정 및 연결
int CNetwork::CNetworkRelayInit()
{
 
	m_nSock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&m_ServAddr, 0, sizeof(m_ServAddr));
 
	m_ServAddr.sin_family = AF_INET;
	m_ServAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	m_ServAddr.sin_port = htons(8687);
 
	m_nSock = socket(PF_INET, SOCK_STREAM, 0);
 
	if(bind(m_nSock, (struct sockaddr *)&m_ServAddr, sizeof(m_ServAddr)) == -1)
	{
		perror("CNetworkRelayInit() Bind Error");
		return PROGRAM_EXIT;
	}
 
	if(listen(m_nSock, 5) == -1)
	{
		perror("CNetworkRelay Listen Error..");
		return PROGRAM_EXIT;
	}
 
	return SUCCESS;
}
 
// 멀티 플렉싱 서버 설정
void CNetwork::CNetworkRelayMultiplexing()
{
	int nIdx;
	int retValue;
	UB2 msgType;
 
	FD_ZERO(&m_reads);
	FD_SET(m_nDBSock, &m_reads);
	FD_SET(m_nSock, &m_reads);
 
	m_FdMax = m_nSock;
 
	cout << "Proxy Server Service Start" << endl;
	while(true)
	{
		m_cpy_reads = m_reads;
		m_timeout.tv_sec = 5;
		m_timeout.tv_usec = 5000;
 
		if((m_FdNum = select(m_FdMax + 1, &m_cpy_reads, 0, 0, &m_timeout)) == -1)
		{
			cout << "Gateway_Select() Select Error" << endl;
			break;
		}
 
		if(m_FdNum == 0)
		{
			cout << "Gateway_Select() Time Out.." << endl;
			continue;
		}
 
		for(nIdx = 0; nIdx < m_FdMax + 1; nIdx++)
		{
			// cout << "select for state" << endl;
			if(FD_ISSET(nIdx, &m_cpy_reads))
			{
				if(nIdx == m_nSock) // request connection.
				{
					m_adrSz = sizeof(m_ClntAddr);
					m_nClntSock = accept(m_nSock, (struct sockaddr *)&m_ClntAddr, &m_adrSz);
					FD_SET(m_nClntSock, &m_reads);
 
					if(m_FdMax < m_nClntSock)
					{
						m_FdMax = m_nClntSock;
						cout << "========== CONNECTED CLIENT ==========" << endl;
					}
				}
				else
				{
					// 리턴 값에 따른 처리 분기
					cout << "select error" << endl;
					retValue = CNetworkRelayRecvPacket((char *)m_pBuf, &msgType, &nIdx);
					CNetworkRelayCheckMsgService((char *)m_pBuf, msgType, nIdx);
				}
			}
		}
	}
}
 
// 메세지 타입 별 서비스 호출
void CNetwork::CNetworkRelayCheckMsgService(char * a_pBuf, UB2 a_ubMsgType, int nIdx)
{
	cout << "CNetworkRelayCheckMsgService" << a_ubMsgType << endl;
	// 로그인 요청 메세지, SQL 요청 메세지, 서버로부터 수신받은 SQL 응답 메세지, 종료 요청 메세지
	if(a_ubMsgType == AUTH_REQ_MSG) // 1
	{
		cout << "CNetworkRelayCheckMsgService AUTH_REQ_MSG ERROR" << endl;
		CNetworkRelayAuthService(nIdx);
	}
	else if(a_ubMsgType == AUTH_RES_MSG) // 2
	{
		cout << "CNetworkRelayCheckMsgService AUTH_RES_MSG ERROR" << endl;
		CNetworkRelayAuthResService();
	}
	else if(a_ubMsgType == SQL_REQ_MSG) // 3
	{
		CNetworkRelaySqlService(nIdx);
	}
	else if(a_ubMsgType == SQL_RES_MSG) // 4
	{
		CNetworkRelaySqlResService();
	}
	else if(a_ubMsgType == CLOSE_REQ_MSG) // 5
	{
		CNetworkRelayCloseService(nIdx);
	}
	else if(a_ubMsgType == CLOSE_RES_MSG) // 6
	{
		CNetworkRelayCloseResService();
	}
	else
	{
		// a_ubMsgType 이 잘 못 온 경우 구현
	}
}
 
void CNetwork::CNetworkRelayAuthService(int a_nIdx)
{
	// 로그인 요청 패킷 서버에 전송
	send(m_nDBSock, &m_LoginReqMsg, sizeof(dgt_auth_req_msg), 0);
 
	// 로그인 요청 패킷 출력 소스 작성
	m_nCsocket = a_nIdx;
}
 
// 로그인 응답 메세지 클라이언트에 전송
void CNetwork::CNetworkRelayAuthResService()
{
	send(m_nCsocket, &m_LoginResMsg, sizeof(dgt_auth_res_msg), 0);
 
}
 
void CNetwork::CNetworkRelaySqlService(int a_nIdx)
{
	// SQL 요청 메세지 출력 소스 작성
 
	// SQL 요청 메세지 서버로 전송
	send(m_nDBSock, &m_SqlReqMsg, sizeof(dgt_sql_req_msg), 0);
	m_nCsocket = a_nIdx;
}
 
void CNetwork::CNetworkRelaySqlResService()
{
	// SQL 응답 메세지 출력 소스 작성
 
	// 클라이언트에게 전송
	send(m_nCsocket, &m_SqlResMsg, sizeof(dgt_sql_res_msg), 0);
}
 
void CNetwork::CNetworkRelayCloseService(int a_nIdx)
{
	// CLOSE 요청 메세지 출력 소스 작성
 
	// 서버에 클로즈 요청 메세지 전송
	send(m_nDBSock, &m_CloseReqMsg, sizeof(dgt_close_req_msg), 0);
	m_nCsocket = a_nIdx;
}
 
void CNetwork::CNetworkRelayCloseResService()
{
	// CLOSE 응답 메세지 출력 소스 작성
 
	// 클라이언트에 클로즈 응답 메세지 전송
	send(m_nCsocket, &m_CloseReqMsg, sizeof(dgt_close_req_msg), 0);
}
 
int CNetwork::CNetworkRelayConnectDBServer()
{
	m_nDBSock = socket(PF_INET, SOCK_STREAM, 0);
	if(m_nDBSock == -1)
	{
		cout << "Gateway_Connect_DBServer() Socket Error!!" << endl;
		return PROGRAM_EXIT;
	}
 
	bzero(&m_DbAddr, sizeof(m_DbAddr));
	m_DbAddr.sin_family = AF_INET;
	m_DbAddr.sin_addr.s_addr = inet_addr("192.168.1.204");
	m_DbAddr.sin_port = htons(8688);
 
	if(connect(m_nDBSock, (struct sockaddr *)&m_DbAddr, sizeof(m_DbAddr)) == -1)
	{
		perror("Gateway_Connect_DBServer Connect Error!!");
		return PROGRAM_EXIT;
	}
	else
		perror("welcome..");
 
	return SUCCESS;
}
 
int CNetwork::CNetworkRelaySqlTypeCheck(char * chBuf)
{
	cout << "chBuf : " << chBuf << endl;
	if(!strcmp(chBuf, "select"))
			return SELECT;
	else if(!strcmp(chBuf, "update"))
			return UPDATE;
	else if(!strcmp(chBuf, "delete"))
			return DELETE;
	else
			return 0;
}
 
// private 함수
// 0 이면 프로그램 종료
// BROKEN_PACKET 리턴되면 재입력
// 정상 수신이면 메세지 타입 리턴
int CNetwork::CNetworkRelayRecvPacket(char * m_pBuf, UB2 * a_msgType, int *a_nIdx)
{
 
	ssize_t recvCnt = 0;
	int msgBytePos = 0;
	int recvPacketCnt = 0;
 
	// m_pBuf 메모리 공간 0으로 초기화
	bzero(m_pBuf, 0);
 
	cout << "CNetworkRelayRecvPacket Error" << endl;
	while(true)
	{
		cout << "CNetworkRelayRecvPacket Before Recv Error" << endl;
		// 2바이트만 받는다
		recvCnt = recv(*a_nIdx, m_pBuf + msgBytePos, BUFSIZE, MSG_WAITALL);
		// 2바이트 이상 받으면 루프 탈출
		if(recvCnt >= 2)
		{
			msgBytePos = recvCnt;
			break;
		}
 
		msgBytePos += recvCnt;
 
		// EOF 프로그램 종료
		if(recvCnt == 0)
			return 0;
 
		// 실패 시 다시 수신한다
		if(recvCnt == -1)
		{
			cout <<"CNetworkRecvPacket Recv Error" << endl;
			msgBytePos = recvCnt = 0;
			continue;
		}
		cout << "CNetworkRelayRecvPacket After Recv Error" << endl;
	}
 
	// 메세지 타입 식별 위해 2바이트 복사
	memcpy(a_msgType, m_pBuf, sizeof(UB2));
 
	if(*a_msgType == AUTH_RES_MSG)
		recvPacketCnt = sizeof(dgt_auth_res_msg) - msgBytePos;
	else if(*a_msgType == SQL_RES_MSG)
		recvPacketCnt = sizeof(dgt_sql_res_msg) - msgBytePos;
	else if(*a_msgType == CLOSE_RES_MSG)
		recvPacketCnt = sizeof(dgt_close_res_msg) - msgBytePos;
	else
		return BROKEN_PACKET;
 
	// 남은 구조체 길이 만큼 수신한다
	while(msgBytePos < recvPacketCnt)
	{
		recvCnt = recv(*a_nIdx, m_pBuf + msgBytePos, BUFSIZE, MSG_WAITALL);
		if(recvCnt == -1)
			return 0;
		if(recvCnt == 0)
			return 0;
 
		msgBytePos += recvCnt;
	}
 
	// 타입에 맞는 구조체로 변환한다
	if(*a_msgType == AUTH_RES_MSG)
		m_LoginResMsg = *(dgt_auth_res_msg*)m_pBuf;
	else if(*a_msgType == AUTH_REQ_MSG)
		m_LoginReqMsg = *(dgt_auth_req_msg *)m_pBuf;
	else if(*a_msgType == SQL_RES_MSG)
		m_SqlResMsg = *(dgt_sql_res_msg *)m_pBuf;
	else if(*a_msgType == SQL_REQ_MSG)
		m_SqlReqMsg = *(dgt_sql_req_msg *)m_pBuf;
	else if(*a_msgType == CLOSE_RES_MSG)
		m_CloseResMsg = *(dgt_close_res_msg *)m_pBuf;
	else if(*a_msgType == CLOSE_REQ_MSG)
		m_CloseReqMsg = *(dgt_close_req_msg *)m_pBuf;
 
	return *a_msgType;
}

이 함수 안에서 첫 번째 리시브에서 메세지를 수신 받지 못합니다...

yhsuk의 이미지

recvCnt = recv(*a_nIdx, m_pBuf + msgBytePos, BUFSIZE, MSG_WAITALL);

은 BUFSIZE 만큼 데이터를 받을 때까지 대기하게 됩니다.

Signature :) - "여유를 갖고 행동하되 게을러지지 말자"

balgarac1의 이미지

말씀하신대로 고쳐도 안되는 것 보니 다른 곳이 틀렸나 봅니다..

shint의 이미지

댓글 첨부 파일: 
첨부파일 크기
Package icon test select() recv(MSG_WAITALL).zip405.6 KB

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.