WSAAsyncSelect模型

来源:互联网 发布:sql 教程 编辑:程序博客网 时间:2024/05/16 13:49

这个模型跟窗口有关,它使用消息来进行通知的。如下是对话框客户端关键代码,连接的是一个echo服务端。

测试文件的传输,将文件发送出去,然后将读取的数据写入文件。

读写文件类WinFile参考:http://blog.csdn.net/tujiaw/article/details/17840823

Buffer类参考:http://blog.csdn.net/tujiaw/article/details/8872865

1.自定义消息:

#define WM_ASYNC_SELECT (WM_USER + 103)

2.消息映射:

ON_MESSAGE(WM_ASYNC_SELECT, &CSmallFileDlg::OnAsyncSelect)

afx_msg LRESULT CSmallFileDlg::OnAsyncSelect(WPARAM wParam, LPARAM lParam){switch (WSAGETSELECTEVENT(lParam)){case FD_CONNECT:if (WSAGETSELECTERROR(lParam)){MessageBox(GetErrorString(WSAGETSELECTERROR(lParam), L"FD_CONNECT"));}else{MessageBox(L"连接成功");}break;case FD_READ:{recvBuffer();static WinFile fr(L"C:\\Users\\jiaw\\Desktop\\2.flv", false);static size_t totalWritten = 0;size_t currentWritten;int ret = fr.write(m_input.peek(), m_input.readableBytes(), ¤tWritten);if (0 != ret) {MessageBox(GetErrorString(ret, L"FD_READ"));::shutdown(m_socket, SD_BOTH);::closesocket(wParam);} else {totalWritten += currentWritten;m_input.retrieve(currentWritten);fr.seek(totalWritten);}}break;case FD_WRITE:sendBuffer(); // send当网络缓冲区满的时候会产生WSAEWOULDBLOCK错误码,此时触发写事件继续写入break;case FD_CLOSE:if (WSAGETSELECTERROR(lParam)){MessageBox(GetErrorString(WSAGetLastError(), L"FD_CLOSE"));}::shutdown(m_socket, SD_BOTH);::closesocket(wParam);MessageBox(L"close");break;}return 0;}void CSmallFileDlg::OnBnClickedConnect(){const char *ip = "192.168.239.150";unsigned short port = 5000;struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_addr.S_un.S_addr = inet_addr(ip);sin.sin_port = htons(port);m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == m_socket) {MessageBox(GetErrorString(WSAGetLastError(), L"socket"));return;}// 会自动将socket设为非阻塞if (SOCKET_ERROR == WSAAsyncSelect(m_socket, m_hWnd, WM_ASYNC_SELECT, FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) {MessageBox(GetErrorString(WSAGetLastError(), L"WSAAsyncSelect"));::closesocket(m_socket);}if (SOCKET_ERROR == ::connect(m_socket, (sockaddr*)&sin, sizeof(sin))) {int errCode = WSAGetLastError();if (WSAEWOULDBLOCK != errCode) { // 非阻塞连接处理WSAEWOULDBLOCKMessageBox(GetErrorString(WSAGetLastError(), L"connect"));::closesocket(m_socket);return;}}}void CSmallFileDlg::OnBnClickedDisconnect(){::shutdown(m_socket, SD_BOTH);::closesocket(m_socket);}void CSmallFileDlg::OnBnClickedSend(){WinFile fr(L"C:\\Users\\jiaw\\Desktop\\1.flv", true);char buf[65536];size_t result;DWORD total = fr.size();DWORD nread = 0;while (nread != total) {int ret = fr.read(buf, sizeof(buf), &result);if (0 != ret) {MessageBox(GetErrorString(ret));break;}nread += result;fr.seek(nread); // 设置下次的读取位置,从0开始偏移m_output.append(buf, result);sendBuffer();}}void CSmallFileDlg::sendBuffer(){int ret = ::send(m_socket, m_output.peek(), m_output.readableBytes(), 0);if (ret > 0){m_output.retrieve(ret);m_sendNum += ret; // 发送消息计数UpdateData(FALSE);}else if (SOCKET_ERROR == ret){int errCode = WSAGetLastError();if (WSAEWOULDBLOCK != errCode){MessageBox(GetErrorString(errCode), L"send");}}}void CSmallFileDlg::recvBuffer(){char buf[65536] = {0};int ret = ::recv(m_socket, buf, sizeof(buf) - 1, 0);if (ret > 0){m_recvNum += ret; // 接收消息计数UpdateData(FALSE);m_input.append(buf, ret);}else if (0 == ret){MessageBox(L"连接优雅的关闭");}else{MessageBox(GetErrorString(WSAGetLastError(), L"recv"));}}

// 产生随机字符串std::string BuildRandString(int num){static unsigned int s_add = 0;std::string ret;srand((unsigned int)time(NULL) + (s_add++));for (int i=0; i<num; ){char buf[17] = {0};_itoa_s(rand(), buf, 0x10);ret += buf;i += strlen(buf);}return ret.substr(0, num);}void DebugLog(const char *fmt, ...){va_list ap;va_start(ap, fmt);char buf[1024] = {0};vsnprintf_s(buf, sizeof(buf), fmt, ap);MessageBoxA(NULL, buf, "debug log", MB_OK);va_end(ap);}