今天,我们看看如何使用异步套接字.我们这里用的是一个基于对话框应用程序.(UDP) .
首先,我们在对话框里添加一个SOCKET变量:(构造函数中:m_SrvSocket = INVALID_SOCKET)
SOCKET m_SrvSocket;
然后,我们在对话框的OnInitDialog中创建套接字:
BOOL CMFCSocketDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
char buffer[MAX_PATH] = {0};
m_SrvSocket = socket( AF_INET, SOCK_DGRAM, 0 ); //创建套接字
SOCKADDR_IN server;
server.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server.sin_family = AF_INET;
server.sin_port = htons(4443);
if( SOCKET_ERROR == bind( m_SrvSocket, (SOCKADDR*)&server, sizeof(SOCKADDR) ) )
{
sprintf( buffer, "绑定套接字失败!错误原因:%d", WSAGetLastError() );
MessageBox( buffer );
closesocket( m_SrvSocket );
PostQuitMessage(0);
}
if( SOCKET_ERROR == WSAAsyncSelect( m_SrvSocket, m_hWnd, WM_SOCKET_MSG, FD_READ |FD_WRITE ) )
{
sprintf( buffer, "选择非阻塞模式失败!错误原因:%d", WSAGetLastError() );
MessageBox( buffer );
closesocket( m_SrvSocket );
PostQuitMessage(0);
}
return TRUE; // return TRUE unless you set the focus to a control
}
接着,我们在响应WM_DESTROY消息:
void CMFCSocketDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
if ( m_SrvSocket != INVALID_SOCKET )
{
closesocket( m_SrvSocket );
m_SrvSocket = INVALID_SOCKET;
}
}
最后,自定义消息,如果你不会的话.我就狂晕了.这里是自定义消息的实现.
void CMFCSocketDlg::OnSocketMsg( WPARAM wParam,LPARAM lParam )
{
UpdateData();
CString strString = _T("");
char buffer[MAX_PATH] = {0};
SOCKADDR_IN addr;
HOSTENT * pHost = NULL;
int nLen;
int nRet;
nLen = sizeof(SOCKADDR);
switch( LOWORD( lParam ) )
{
case FD_READ:
do
{
memset( buffer, 0, MAX_PATH );
nRet = recvfrom( m_SrvSocket , buffer, MAX_PATH - 1, 0, (SOCKADDR*)&addr, &nLen );
if( SOCKET_ERROR == nRet )
{
sprintf( buffer, "接收数据失败!错误原因:%d", WSAGetLastError() );
MessageBox( buffer );
return ;
}
strString += buffer;
if ( strstr( buffer, "/t/t/t/t" ) != NULL )
{
strString.Replace( _T("/t/t/t/t"), _T("/r/n" ) );
break;
}
} while( TRUE );
memset( buffer, 0, MAX_PATH );
pHost = gethostbyaddr( (char*)&addr.sin_addr.S_un.S_addr, 4, AF_INET );
sprintf( buffer, "%s:/r/n", pHost->h_name );
m_strString = m_strString + buffer + strString;
break;
case FD_WRITE:
if ( m_strHost.GetLength() <= 0 )
{
MessageBox( _T("请填写主机地址!") );
return ;
}
if ( m_strSend.GetLength() <= 0 )
{
MessageBox( _T("发送消息不能为空!") );
return ;
}
pHost = gethostbyname( m_strHost );
if ( !pHost )
{
sprintf( buffer, "无法解析服务器地址!错误原因:%d", WSAGetLastError() );
MessageBox( buffer );
return ;
}
addr.sin_addr.S_un.S_addr = *((DWORD*)pHost->h_addr_list[0]);
addr.sin_family = AF_INET;
addr.sin_port = htons(4443);
memset( addr.sin_zero, 0, sizeof(addr.sin_zero) );
m_strSend += "/t/t/t/t";
nRet = sendto( m_SrvSocket, m_strSend, m_strSend.GetLength() + 1, 0, (SOCKADDR*)&addr, nLen );
if( SOCKET_ERROR == nRet )
{
sprintf( buffer, "发送数据失败!错误原因:%d", WSAGetLastError() );
MessageBox( buffer );
return;
}
m_strSend = _T("");
break;
}
GetDlgItem(IDC_EDIT_SEND)->SetFocus();
UpdateData(FALSE);
}
好了,一切搞定.