异步socket TCP 通信
使用 WSAAsyncSelect 可实现异步 socket 通信,原型:
WSAAsyncSelect(
SOCKET s, //套接字
HWND hWnd, //接收网络事件的窗口句柄
unsigned int wMsg,//网络事件通知消息
long lWvent //套接字需要的通知码
);
long lWvent 有:
- FD_READ :接收到对方发送的数据包
- FD_WRITE :可以写入数据
- FD_ACCEPT :接收到链接请求
- FD_CONNECT :socket成功链接到对方
- FD_CLOSE :链接关闭
代码:
server:
BEGIN_MESSAGE_MAP(CAsyncSocketDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDOK, &CAsyncSocketDlg::OnBnClickedOk)
ON_MESSAGE(WM_SOCKET_MSG, &CAsyncSocketDlg::OnSockMsg)
END_MESSAGE_MAP()
// CAsyncSocketDlg 消息处理程序
BOOL CAsyncSocketDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
m_listenSock = socket(PF_INET, SOCK_STREAM, 0);
WSAAsyncSelect(m_listenSock, GetSafeHwnd(), WM_SOCKET_MSG, FD_ACCEPT);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = ADDR_ANY;
addr.sin_port = htons(9999);
bind(m_listenSock, (SOCKADDR*)&addr, sizeof(addr));
listen(m_listenSock, 5);
m_edit.ShowScrollBar(SB_VERT, TRUE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CAsyncSocketDlg::OnBnClickedOk()
{
closesocket(m_clientSock);
closesocket(m_listenSock);
WSACleanup();
CDialogEx::OnOK();
}
LRESULT CAsyncSocketDlg::OnSockMsg(WPARAM wParam, LPARAM lParam)
{
if (WSAGETSELECTERROR(lParam))
return 0;
CString msg;
m_edit.GetWindowText(msg);
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
SOCKADDR_IN addr;
int size = sizeof(addr);
m_clientSock = accept(m_listenSock, (SOCKADDR*)&addr, &size);
WSAAsyncSelect(m_clientSock, GetSafeHwnd(), WM_SOCKET_MSG, FD_READ | FD_CLOSE);
CString s;
s.Format(_T("客户端地址:%s:%d\r\n"), inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
msg += s;
}
break;
case FD_READ:
{
ZeroMemory(m_buf, sizeof(m_buf));
recv(m_clientSock, m_buf, sizeof(m_buf), 0);
msg = msg + "接收到:" + CString(m_buf) + "\r\n";
CString s = CString("server send:") + CString(m_buf);
send(m_clientSock, s, s.GetLength(), 0);
}
break;
case FD_CLOSE:
{
closesocket(m_clientSock);
msg += "客户端关闭连接\r\n";
}
break;
default:
break;
}
m_edit.SetWindowText(msg);
m_edit.LineScroll(m_edit.GetLineCount() - 1, 0);
return 0;
}
client:
BEGIN_MESSAGE_MAP(CAsyncSocketClientDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDOK, &CAsyncSocketClientDlg::OnBnClickedOk)
ON_BN_CLICKED(IDC_CONNECT, &CAsyncSocketClientDlg::OnBnClickedConnect)
ON_BN_CLICKED(IDC_SEND, &CAsyncSocketClientDlg::OnBnClickedSend)
ON_MESSAGE(WM_SOCKET_MSG, &CAsyncSocketClientDlg::OnSockMsg)
END_MESSAGE_MAP()
// CAsyncSocketClientDlg 消息处理程序
BOOL CAsyncSocketClientDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
m_sock = socket(PF_INET, SOCK_STREAM, 0);
m_edit.ShowScrollBar(SB_VERT, TRUE);
m_editSend.ShowScrollBar(SB_VERT, TRUE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CAsyncSocketClientDlg::OnBnClickedOk()
{
closesocket(m_sock);
WSACleanup();
CDialogEx::OnOK();
}
void CAsyncSocketClientDlg::OnBnClickedConnect()
{
CString s;
GetDlgItemText(IDC_CONNECT, s);
if (s == "链接")
{
m_sock = socket(PF_INET, SOCK_STREAM, 0);
WSAAsyncSelect(m_sock, GetSafeHwnd(), WM_SOCKET_MSG, FD_CONNECT | FD_CLOSE | FD_READ);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(9999);
connect(m_sock,(SOCKADDR*)&addr, (sizeof(addr)));
CString msg;
m_edit.GetWindowText(msg);
msg += "链接服务端\r\n";
m_edit.SetWindowText(msg);
SetDlgItemText(IDC_CONNECT, "断开");
}
else if (s == "断开")
{
closesocket(m_sock);
SetDlgItemText(IDC_CONNECT, "链接");
CString msg;
m_edit.GetWindowText(msg);
msg += "断开链接\r\n";
m_edit.SetWindowText(msg);
}
}
void CAsyncSocketClientDlg::OnBnClickedSend()
{
CString s;
m_editSend.GetWindowText(s);
send(m_sock, s, s.GetLength(), 0);
}
LRESULT CAsyncSocketClientDlg::OnSockMsg(WPARAM wParam, LPARAM lParam)
{
if (WSAGETSELECTERROR(lParam))
return 0;
CString msg;
m_edit.GetWindowText(msg);
switch (WSAGETSELECTEVENT(lParam))
{
case FD_CONNECT:
{
msg += "链接成功\r\n";
}
break;
case FD_READ:
{
ZeroMemory(m_buf, sizeof(m_buf));
recv(m_sock, m_buf, sizeof(m_buf), 0);
msg = msg + "接收到:" + CString(m_buf) + "\r\n";
}
break;
case FD_CLOSE:
{
closesocket(m_sock);
msg += "服务端关闭连接\r\n";
}
break;
default:
break;
}
m_edit.SetWindowText(msg);
m_edit.LineScroll(m_edit.GetLineCount() - 1, 0);
return 0;
}
效果:
代码链接:
VS2015工程:http://download.csdn.net/detail/yangyang031213/9893803
https://github.com/yangyang0312/cpp/tree/master/windows/AsyncSocket