-
MFCPlatform/소켓 2009. 2. 13. 19:03CInternetSession
INTERNET_OPEN_TYPE_DIRECT.SetOption()
INTERNET_OPTION_CONNECT_TIMEOUT
.GetFtpConnection()
.OpenURL()
CInternetFile -> CStdioFile
.Close().Read()
.SetReadBufferSize()
.GetLength()
주의: 파일 크기가 아니다.
.ReadString()
.Read()
요청한 크기보다 작을 수 있다. // ???
.Seek()
로컬 PC의 캐시에 적용되기 때문에 큰 파일에는 사용하면 안될 것 같음 // ???
CInternetException
// html, image를 가지고 오는 예제
#include <afxinet.h>
void CGetHtmlTestDlgDlg::OnButton1()
{
GetHtml("http://simple21.egloos.com", "test.htm");
GetImage("http://pds.egloos.com/logo/1/200504/20/80/c0010380.jpg", "test.jpg") ;
AfxMessageBox("done");
}
bool GetHtml(const char* strURL, const char* strSavePath)
{
CInternetSession session;
CInternetFile* pInternetFile = NULL;
try {
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 1000);
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 3);
pInternetFile = (CInternetFile*) session.OpenURL(strURL);
} catch (CInternetException* m_pException) {
char szError[1024];
m_pException->GetErrorMessage(szError, 1024);
AfxMessageBox(szError);
pInternetFile = NULL;
m_pException->Delete();
return false;
}
if(pInternetFile == NULL) return false;
CString strLine, strHtml;
while(pInternetFile->ReadString(strLine) != NULL) {
strHtml += strLine;
strHtml += "
";
strLine.Empty();
}
FILE* fp = fopen(strSavePath, "w+t");
fprintf(fp, "%s", strHtml);
fclose(fp);
pInternetFile->Close();
delete pInternetFile; pInternetFile = NULL;
return true;
}
bool GetImage(const char* strURL, const char* strSavePath)
{
CInternetSession session;
CInternetFile* pInternetFile = NULL;
try {
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 1000);
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 3);
pInternetFile = (CInternetFile*) session.OpenURL(strURL);
} catch (CInternetException* m_pException) {
char szError[1024];
m_pException->GetErrorMessage(szError, 1024);
AfxMessageBox(szError);
pInternetFile = NULL;
m_pException->Delete();
return false;
}
if(pInternetFile == NULL) return false;
unsigned char data[500];
int data_size = 0;
FILE* fp = fopen(strSavePath, "w+b");
while((data_size = pInternetFile->Read(data, 500)) != 0)
fwrite(data, sizeof(unsigned char), data_size, fp);
fclose(fp);
pInternetFile->Close();
delete pInternetFile; pInternetFile = NULL;
return true;
}
AfxSocketInit()
CSocket
OnAccept
OnClose
OnReceive
OnMessagePending
.Create()
.Listen()
.Accept()
.Close()
.Connect()
.Send() // 모든 데이터를 보낸다.
.Receive() // 소켓 버퍼에서 임의(?)량의 데이터를 가져오거나 EOF
int CXXXSocket::Receive(LPVOID lpBuf, int nBufLen, int nFlags)
{
int nRead;
int nLeft = nBufLen;
PBYTE pBuf = (PBYTE)lpBuf;
while(nLeft > 0)
{
nRead = CSocket::Receive(pBuf, nLeft);
if (nRead == SOCKET_ERROR)
{
return nRead;
}
else
if (nRead == 0)
{
return nBufLen - nLeft;
}
nLeft -= nRead;
pBuf += nRead;
}
return nBufLen - nLeft;
}.CancelBlockingCall()
#include <afxsock.h> // MFC socket extensions
BOOL CTcpServer2App::InitInstance()
{
// {
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
// }
AfxEnableControlContainer();
...
}
class CClientSocket : public CSocket
{
...
virtual ~CClientSocket();
// Overrides
public:
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CClientSocket)
public:
virtual void OnClose(int nErrorCode);
virtual void OnReceive(int nErrorCode);
//}}AFX_VIRTUAL
...
};
void CClientSocket::OnClose(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
Close();
AfxMessageBox( "접속이 종료되었음" );
// }
CSocket::OnClose(nErrorCode);
// {
delete this;
// }
}
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
char buf[100];
ZeroMemory( buf, 100 );
Receive( buf, 100 );
AfxMessageBox( buf );
Send( "world", 6 );
// }
CSocket::OnReceive(nErrorCode);
}
class CListenSocket : public CSocket
{
...
virtual ~CListenSocket();
// Overrides
public:
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CListenSocket)
public:
virtual void OnAccept(int nErrorCode);
//}}AFX_VIRTUAL
...
};
void CListenSocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
if( Accept( *(new CClientSocket()) ) )
AfxMessageBox( _T("억셉트 성공") );
else
AfxMessageBox( _T("억셉트 실패") );
// }
CSocket::OnAccept(nErrorCode);
}
class CTcpServer2Dlg : public CDialog
{
// {
CListenSocket m_Listen;
// }
// Construction
public:
CTcpServer2Dlg(CWnd* pParent = NULL); // standard constructor
...
// Generated message map functions
//{{AFX_MSG(CTcpServer2Dlg)
...
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnListen();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
BOOL CTcpServer2Dlg::OnInitDialog()
{
...
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
// {
if( !m_Listen.Create(6565) )
{
AfxMessageBox( _T("리슨 소켓 생성 실패") );
// return TRUE;
}
// }
return TRUE; // return TRUE unless you set the focus to a control
}
...
void CTcpServer2Dlg::OnListen()
{
// TODO: Add your control notification handler code here
if( !m_Listen.Listen() )
{
AfxMessageBox( _T("리슨 실패") );
return;
}
}
#include <afxsock.h> // MFC socket extensions
BOOL CTcpClientApp::InitInstance()
{
// {
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
// }
AfxEnableControlContainer();
...
}
class CClientSocket : public CSocket
{
...
virtual ~CClientSocket();
// Overrides
public:
// {
BOOL ConnectTimeout(LPCTSTR lpszHostAddress, UINT nHostPort, DWORD dwTimeout);
// }
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CClientSocket)
public:
virtual void OnClose(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual BOOL OnMessagePending();
//}}AFX_VIRTUAL
...
};
void CClientSocket::OnClose(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
Close();
AfxMessageBox( "접속이 종료되었음" );
// }
CSocket::OnClose(nErrorCode);
}
void CClientSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
char buf[10];
ZeroMemory( buf, 10 );
Receive( buf, 10 );
...
// }
CSocket::OnReceive(nErrorCode);
}
BOOL CClientSocket::ConnectTimeout(LPCTSTR lpszHostAddress, UINT nHostPort, DWORD dwTimeout)
{
BOOL ret;
AfxGetMainWnd()->SetTimer(65, dwTimeout, NULL);
ret = Connect(lpszHostAddress, nHostPort);
AfxGetMainWnd()->KillTimer(65);
return ret;
}
BOOL CClientSocket::OnMessagePending()
{
// TODO: Add your specialized code here and/or call the base class
// {
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
if (msg.message==WM_TIMER && 65 == msg.wParam) {
CancelBlockingCall();
} else if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return FALSE; // usually return TRUE, but OnIdle usually causes WM_PAINTs
// }
// return CSocket::OnMessagePending();
}
class CTcpClientDlg : public CDialog
{
// {
CClientSocket m_Socket;
// }
// Construction
public:
CTcpClientDlg(CWnd* pParent = NULL); // standard constructor
...
// Generated message map functions
//{{AFX_MSG(CTcpClientDlg)
...
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnConnect();
afx_msg void OnClose();
afx_msg void OnSend();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CTcpClientDlg, CDialog)
//{{AFX_MSG_MAP(CTcpClientDlg)
...
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CONNECT, OnConnect)
ON_BN_CLICKED(IDC_CLOSE, OnClose)
ON_BN_CLICKED(IDC_SEND, OnSend)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
...
void CTcpClient2Dlg::OnConnect()
{
// TODO: Add your control notification handler code here
m_Socket.Close();
if( m_Socket.Create() == FALSE )
{
AfxMessageBox( "소켓 생성 실패" );
return;
}
if( m_Socket.ConnectTimeout( "...", 6565, 2000) == FALSE ) {
m_Socket.Close();
AfxMessageBox( "접속 실패!" );
return;
}
AfxMessageBox( "접속 성공!" );
}
void CTcpClientDlg::OnClose()
{
// TODO: Add your control notification handler code here
m_Socket.Close();
}
void CTcpClientDlg::OnSend()
{
// TODO: Add your control notification handler code here
m_Socket.Send( "hello", 6 );
}
Receive 함수로 읽을 때나 Send 함수로 보낼 때는 가능한 큰 버퍼로 받거나 보내면 성능에 큰 도움
4096 or 8192
OnConnect
OnClose
OnSend
OnReceive
.Create()
.Close()
.Connect()
.ShutDown()
.Send()
.Receive()
BOOL CTcpCAsyncClientApp::InitInstance()
{
// {
if (!AfxSocketInit())
{
...
return FALSE;
}
// }
AfxEnableControlContainer();
...
}
#include <afxsock.h> // MFC socket extensions
class CMyAsyncSocket : public CAsyncSocket
{
// {
void DoSendBuf();
char m_SendBuf[4096]; // 보낼 데이터 버퍼
char* m_pSendCurBuf; // 보내야할 버퍼 현재 위치
int m_nSendLeft; // 보내기 위해 남은 길이
// }
// Attributes
public:
// Operations
public:
CMyAsyncSocket();
virtual ~CMyAsyncSocket();
// {
BOOL AsyncSend( char* pBuf, int nLen );
// }
// Overrides
public:
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyAsyncSocket)
public:
virtual void OnConnect(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnSend(int nErrorCode);
virtual void OnReceive(int nErrorCode);
//}}AFX_VIRTUAL
...
};
CMyAsyncSocket::CMyAsyncSocket()
{
// {
m_nSendLeft = 0;
m_pSendCurBuf = m_SendBuf;
// }
}
...
void CMyAsyncSocket::OnConnect(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
if( nErrorCode == 0 )
{
AfxMessageBox( "접속 성공" );
}
else
{
int err = GetLastError();
AfxMessageBox( "접속 실패" );
}
// }
CAsyncSocket::OnConnect(nErrorCode);
}
void CMyAsyncSocket::OnClose(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
Close();
AfxMessageBox( "접속 종료" );
// }
CAsyncSocket::OnClose(nErrorCode);
}
void CMyAsyncSocket::OnSend(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
DoSendBuf();
// }
CAsyncSocket::OnSend(nErrorCode);
}
void CMyAsyncSocket::OnReceive(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
// {
char buf[4096];
ZeroMemory( buf, 4096 );
int nRead = Receive( buf, 4096 );
if( nRead == 0 ) { // 연결이 끊어졌다.
Close();
} else if( nRead == SOCKET_ERROR ) {
int nErr = GetLastError();
// 네트워크 리소스를 잠시 사용 못하는 경우가 아닌 모든 오류시 연결 끊음
if( nErr != WSAEWOULDBLOCK )
Close();
} else {
// 데이터를 받았다.
AfxMessageBox( buf );
}
// }
CAsyncSocket::OnReceive(nErrorCode);
}
BOOL CMyAsyncSocket::AsyncSend( char* pBuf, int nLen )
{
// 현재 이 버전은 보낼 데이터를 버퍼 큐로 쌓아 놓지 않는다.
if( m_nSendLeft != 0 )
{
AfxMessageBox( "아직 보내야할 데이터를 다 보내지 못했습니다." );
return FALSE;
}
// 현재 버전은 고정 크기의 버퍼에 담아 보내기 때문에 버퍼 크기보다
// 큰 데이터를 한번에 보낼 수 없다.
if( nLen > 4096 )
{
AfxMessageBox( "버퍼 크기보다 큰 데이터를 보낼 수 없습니다." );
return FALSE;
}
// 보낼 데이터를 보내기버퍼에 복사한다.
memcpy( m_SendBuf, pBuf, nLen );
m_pSendCurBuf = m_SendBuf;
m_nSendLeft = nLen;
// 버퍼 보내기를 시도한다.
DoSendBuf();
return TRUE;
}
void CMyAsyncSocket::DoSendBuf()
{
while( m_nSendLeft > 0 ) {
int nSend;
nSend = Send( m_pSendCurBuf, m_nSendLeft );
if( nSend == SOCKET_ERROR ) {
int nErr = GetLastError();
if( nErr == WSAEWOULDBLOCK ) {
break;
} else {
Close();
m_nSendLeft = 0;
AfxMessageBox( "보내기에 실패하여 연결을 끊습니다." );
return;
}
} else {
// 보내기 성공으로 현재 보내야 할 위치와 남은 양을 변경
m_pSendCurBuf += nSend;
m_nSendLeft -= nSend;
}
}
}
BEGIN_MESSAGE_MAP(CTcpCAsyncClientDlg, CDialog)
//{{AFX_MSG_MAP(CTcpCAsyncClientDlg)
...
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CONNECT, OnConnect)
ON_BN_CLICKED(IDC_CLOSE, OnClose)
ON_BN_CLICKED(IDC_SEND, OnSend)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
...
void CTcpCAsyncClientDlg::OnConnect()
{
// TODO: Add your control notification handler code here
if( !m_Client.Create() )
{
AfxMessageBox("소켓 생성 실패!");
return;
}
if( m_Client.Connect( "localhost", 6565 ) == 0 )
{
if( m_Client.GetLastError() != WSAEWOULDBLOCK )
{
AfxMessageBox("소켓 접속 실패!");
return;
}
}
}
void CTcpCAsyncClientDlg::OnClose()
{
// TODO: Add your control notification handler code here
m_Client.ShutDown();
}
void CTcpCAsyncClientDlg::OnSend()
{
// TODO: Add your control notification handler code here
char buf[1024];
ZeroMemory( buf, 1024 );
strcpy( buf, "[client] CMyAsyncSocket: AsyncSending..." );
m_Client.AsyncSend( buf, strlen(buf) + 1 );
}
참조 사이트:
http://simple21.egloos.com/310792
http://jjjryu.tistory.com/entry/Windows-1
http://jjjryu.tistory.com/entry/Win32-1