tcp recv 함수에서 문자열 수신 받지 못하는 문제 질문입니다.
글쓴이: balgarac1 / 작성시간: 목, 2015/11/19 - 10:39오전
각기 다른 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; }
이 함수 안에서 첫 번째 리시브에서 메세지를 수신 받지 못합니다...
Forums:
recvCnt = recv(*a_nIdx,
은 BUFSIZE 만큼 데이터를 받을 때까지 대기하게 됩니다.
Signature :) - "여유를 갖고 행동하되 게을러지지 말자"
아,, 답변 감사드립니다.
말씀하신대로 고쳐도 안되는 것 보니 다른 곳이 틀렸나 봅니다..
MSG_WAITALL 에서 멈추네요.
DevC++과 telnet 127.0.0.1 5555 로 테스트했습니다.
http://kldp.org/node/153857
MSG_WAITALL
http://www.google.co.kr/search?hl=ko&source=hp&biw=&bih=&q=MSG_WAITALL&gbv=2&oq=MSG_WAITALL&gs_l=heirloom-hp.12..0l2j0i30l8.302.302.0.2045.1.1.0.0.0.0.205.205.2-1.1.0....0...1ac.1.34.heirloom-hp..0.1.204.hdRHzK_-_jY
Using select() for non-blocking sockets
http://stackoverflow.com/questions/6715736/using-select-for-non-blocking-sockets
Non-Blocking I/O, Part II
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=270
select function
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
댓글 달기