본문 바로가기
Programming/Tips(C++,C#)

02/03 - TCP/IP를 이용한 파일 송/수신

by 곰네Zip 2009. 2. 3.

*스크립트도 패킷에 함께 날라온다.!

*패킷구조체 (file송/수신용)
typedef struct _packet{
   WORD MajorVer, MinVer; //버전을 담아두면 하위호환시에 유리하다.
   char szCommand[16]; //명령용(int size두면 좋음.. 패킷의크기를알도록)
   int sizefile; //수신파일사이즈
   char file; //파일임
}

*서버짤때 고려할 사항 안정성 > 성능향상 > 서비스의 질

*파일 송수신시 ::TransmitFile()메소드 사용하자. 다해준다. ㅋㅋㅋ

*IOCP는 처음에 등록하기가 어렵지만, 한번 등록해두고나면 무진장 편하다.

*TCP Echo Server잘 보자. ㅋ

*IOCP에서 중요한것을 스레드가 할일을 잘게 쪼개라 그렇지않다면 문제생길수 있다.

*IOCP서버만들기.

//ClientData class
typedef struct _IO_DATA{
   WSAOVERLAPPED OverLapped;
   BYTE byBuffer[150000]; //송수신 저장버퍼
   WSABUF WsaBuffer;
   LPVOID CClientData //클라이언트정보
} IO_DATA;
class CClientData{
 Public:
   생성자(); 소멸자();
 public:
   IO_DATA m_IODATA;
   Socket  m_hSocket;
   SOCK_ADDR m_Address;
}

//서버 리슨부분
HANDLE hIOCPHancle = ::CreateIOCompletionPort(FileHandle(INVALID_HANDLE_VALUE),NULL,0,0); //소켓에엮기위해
if( hIOCPHandle == NULL){ To do Error handling; }
loop(i to n){
    AfxBeginThread(CompletionThread(함수명),(LPVOID)hIOCPHandle(IOCP핸들)); //이거는알아서호출되는함수다.
}
g_hSockServer = ::WSASocket(PF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
           //window에서 사용될 winsock2함수이다.
if( g_hSockServer == NULL){ To do Error; }
SOCKADDR 처리
그외에는 일반서버와 동일
//bind
//listen
//accept후
while(TRUE){
  hClientSocket = ::accept(g_hSockServer,(SOCKADDR*)&CliAddr,&nAddrSize);
  if(hClientSocket == INVALID_SOCKET){ break;}
  CClientData pNewClientData = new CClientData;
  소켓정보를 저장(ClientData에)
  ::CreateIOCompletionPort((HANDLE)pNewClientData->m_hSocket,
                                         hIOCPHandle, (DWORD)&pNewClientdata->m_IOData, 0);
  g_ptrList.AddTail();
  dwRecvSize=  0;
  ::WSARecv(pNewClientData->m_hSocket,
                 &pNewClientData->m_IOData.WsaBuffer,1,&dwRecvSize,&dwFlag,
                 &pNewClientData->m_IOData.Overlapped,NULL); //큐에 걸어놓는작업임
  if(WSAGetLastError() != WSA_IO_PENDING){ to do error; }
}
CloseHandle(hHandle);

/////////////////////////////////////////////////////////////////////////////
넘어온함수(스레드함수)
while(TRUE){
::GetQueuedCompletionStatus(hIOCPHandle, &dwTransize,&IODATA,,INFINITE);
//todo something
::WSASend(...)
!주목할것
(DWORD)&pClientData->m_IODATA == (DWORD)pIOData) //수신한 곳에서생성한것과 큐에서꺼낸것의주소가같다. 비동기IO와 관련해서 데이터찾아갈 수 있다.
(DWORD)&pClientData->m_IOData.byBuffer == (DWORD)pClientData->m_IOData.WsaBuffer.buf
//데이터를 빼야하는 이유. 접속한 사용자별로 버퍼를 따로 두어야한다.
BufferCLEAR
::WSARecv를 이용다시 슬립상태로 들어간다.
}
반응형

댓글