tcp에서 메시지 송수신 시 발생하는 문제 관련하여 질문드립니다.
글쓴이: balgarac1 / 작성시간: 목, 2015/11/19 - 2:08오전
아래와 같은 메세지 타입이 있습니다.
이 메세지를 서버와 클라이언트가 주고 받습니다.
메세지를 수신 할 때 어떤 메세지가 올 지 예측할 수 없으므로
recv 사용시 void * 형 버퍼를 사용했습니다.
수신을 다 받으면 메세지 타입에 맞도록 형변환 시켜서 대입했습니다.
문제는 수신 받을 때 메세지 타입을 알아야 하므로
2바이트를 먼저 읽는 코드를 짜면
2바이트 수신 후에는 메세지 타입을 알 수 있습니다.
메세지 타입 확인 후에는 읽어들일 메세지 크기를 알 수 있으므로
이것도 while 루프를 돌면서 저장 받을 수 있습니다.
이런 로직의 코드를 작성했는데 문제가 있는지 송수신이 안되고 있습니다.
다시 봐도 로직에 문제가 잘 깨달아지지 않아서
이곳에 질문 드립니다.. 가르침 주시면 감사하겠습니다...
#define UB2 unsigned short #define UB4 unsigned int #define SCHAR signed char #define AUTH_REQ_MSG 1 #define AUTH_RES_MSG 2 #define SQL_REQ_MSG 3 #define SQL_RES_MSG 4 #define CLOSE_REQ_MSG 5 #define CLOSE_RES_MSG 6 #define BROKEN_PACKET 7 #define PROGRAM_EXIT 8 #define SUCCESS 9 #define QUERY_EXIT 10 #define SELECT 1 #define UPDATE 2 #define DELETE 3 // msg type number 1 typedef struct _dgt_auth_req_msg { UB2 msg_type; SCHAR db_user[33]; SCHAR password[33]; SCHAR program_name[33]; SCHAR db_name[33]; }dgt_auth_req_msg; // msg type number 2 typedef struct _dgt_auth_res_msg { UB2 msg_type; UB2 rtn_len; SCHAR rtn_msg[257]; }dgt_auth_res_msg; // msg type number 3 typedef struct _dgt_sql_req_msg { UB2 msg_type; UB4 sql_len; SCHAR sql_text[1025]; UB2 sql_type; }dgt_sql_req_msg; // msg type number 4 typedef struct _dgt_sql_res_msg { UB2 msg_type; UB4 rtn_len; SCHAR rtn_data[1025]; UB2 sql_type; }dgt_sql_res_msg; // msg type number 5 typedef struct _dgt_close_req_msg { UB2 msg_type; }dgt_close_req_msg; // msg type number 6 typedef struct _dgt_close_res_msg { UB2 msg_type; UB2 rtn_len; SCHAR rtn_msg[257]; }dgt_close_res_msg;
int CNetwork::CNetworkRecvPacket(void * m_pBuf, UB2 * msgType) { ssize_t recvCnt = 0; int msgBytePos = 0; int recvPacketCnt = 0; // m_pBuf 메모리 공간 0으로 초기화 bzero(m_pBuf, 0); while(true) { // 2바이트만 받는다 recvCnt = recv(m_nSock, m_pBuf + msgBytePos, BUFSIZ, 0); // 2바이트 이상 받으면 루프 탈출 if(recvCnt >= 2) break; msgBytePos += recvCnt; // EOF 프로그램 종료 if(recvCnt == 0) return 0; // 실패 시 다시 수신한다 if(recvCnt == -1) { cout <<"CNetworkRecvPacket Recv Error" << endl; msgBytePos = recvCnt = 0; continue; } } // 메세지 타입 식별 위해 2바이트 복사 memcpy(msgType, m_pBuf, sizeof(UB2)); if(*msgType == AUTH_RES_MSG) recvPacketCnt = sizeof(dgt_auth_res_msg) - msgBytePos; else if(*msgType == SQL_RES_MSG) recvPacketCnt = sizeof(dgt_sql_res_msg) - msgBytePos; else if(*msgType == CLOSE_RES_MSG) recvPacketCnt = sizeof(dgt_close_res_msg) - msgBytePos; else return BROKEN_PACKET; int CNetwork::CNetworkRecvPacket(void * m_pBuf, UB2 * msgType) { ssize_t recvCnt = 0; int msgBytePos = 0; int recvPacketCnt = 0; // m_pBuf 메모리 공간 0으로 초기화 bzero(m_pBuf, 0); while(true) { // 2바이트만 받는다 recvCnt = recv(m_nSock, m_pBuf + msgBytePos, BUFSIZ, 0); // 2바이트 이상 받으면 루프 탈출 if(recvCnt >= 2) break; msgBytePos += recvCnt; // EOF 프로그램 종료 if(recvCnt == 0) return 0; // 실패 시 다시 수신한다 if(recvCnt == -1) { cout <<"CNetworkRecvPacket Recv Error" << endl; msgBytePos = recvCnt = 0; continue; } } // 메세지 타입 식별 위해 2바이트 복사 memcpy(msgType, m_pBuf, sizeof(UB2)); if(*msgType == AUTH_RES_MSG) recvPacketCnt = sizeof(dgt_auth_res_msg) - msgBytePos; else if(*msgType == SQL_RES_MSG) recvPacketCnt = sizeof(dgt_sql_res_msg) - msgBytePos; else if(*msgType == CLOSE_RES_MSG) recvPacketCnt = sizeof(dgt_close_res_msg) - msgBytePos; else return BROKEN_PACKET; // 남은 구조체 길이 만큼 수신한다 while(msgBytePos < recvPacketCnt) { recvCnt = recv(m_nSock, m_pBuf + msgBytePos, BUFSIZ, 0); if(recvCnt == -1) continue; if(recvCnt == 0) return 0; msgBytePos += recvCnt; } // 타입에 맞는 구조체로 변환한다 if(*msgType == AUTH_RES_MSG) m_LoginResMsg = *(dgt_auth_res_msg*)m_pBuf; else if(*msgType == SQL_RES_MSG) m_SqlResMsg = *(dgt_sql_res_msg *)m_pBuf; else if(*msgType == CLOSE_RES_MSG) m_CloseResMsg = *(dgt_close_res_msg *)m_pBuf; return *msgType; }
Forums:
참고해보세요.
저도 그런 문제가 있었습니다.
- m_pbuf 에 크기를 확인
- recv 의 BUFSIZ 크기를 확인
- 각 함수마다 인자값. 오류값. 리턴값을 확인한후. printf() 문으로 확인
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
감사드립니당ㅜ
답변 감사드립니다.
근데 버퍼값을 왜 확인하나요?
m_pbuf 버퍼 사이즈가 BUFSIZ보다 작아야 하는 건가요?
그런거 같은데요.
확인해봐야 알거 같습니다.
저도 거기서 멈췄던거 같습니다.
일단. 다 지우고. recv가 되는 상황만 만들어보시는것이 답입니다.
잘 되는 예제소스 따라해보시는것이 좋습니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
msgBytePos가 결정적인것 같은데요?
컴파일 되는 코드가 아니니 눈으로 쫓을 수 밖에 없는데요.
msgBytePos가 이상한듯 싶습니다.
첫 while에서 타입처리를 2바이트만 받는다고 했는데요.
받은 크기를 msgBytePos에 반영해주지를 않습니다.
그러니 m_pBuf + msgBytePos(0인상태)를 만나게 되니, 첫 while에서 받은 데이터는 덮어 씌워지게 되겠지요?
결국 남은 구조체 길이만큼 수신한다 했는데, 서버는 다 보냈는데, 클라이언트는 데이터를 더 내놓으라 기다리겠네요..;
코드는 자세히 안봤습니다. 그런데 htons or
코드는 자세히 안봤습니다. 그런데 htons or ntohs 와 같은 함수가 안보이는데
혹시 Byte Order 고려안하신건 아닌가요?
그리고 두번째, 고정길이의 헤더만큼 받고 나머지 받는 코드로 작성하는게 좋지 싶네요.
이 코드는 바이트오더가 고려되지 않았습니다.
댓글 달기