新建一个MFC对话框程序
服务器与客户端的对话框基本一致,以服务器为例:
将左右两个编辑框设置为多行显示. 编辑框属性:
CEdit 的属性进行设置:Auto HScroll 设置为 False;
MultiLine 设置为 True;Want Return 设置为 True
分别将其定义一个变量 CString m_strSend;CString m_strRecv;
将服务器与客户端的对话框内重写消息处理函数
LRESULT CWSAAsyncSelectDlgDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
return CDialogEx::WindowProc(message, wParam, lParam);
}
定义
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define WM_SOCKET (WM_USER+100)// 消息定义
#define BUF_SIZE 1024// 缓冲区大小
SOCKET socketListen;// 监听SOCKET
SOCKET socketAccept;// 连接SOCKET
typedef struct _SOCKET_INFO// SOCKET结构体
{
SOCKET socket;
WSABUF wsaBuf;
char chBuf[BUF_SIZE];
_SOCKET_INFO *pNext;
}SOCKET_INFO, *P_SOCKET_INFO;
P_SOCKET_INFO pInfoTemp;
void CreateSocketInfo(SOCKET socket);
P_SOCKET_INFO GetSocketInfo(SOCKET socket);
char chBuf[BUF_SIZE];
// 消息循环
LRESULT CWSAAsyncSelectServDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_SYSCOMMAND:
if (SC_CLOSE == wParam)
{
closesocket(socketAccept);
closesocket(socketListen);
WSACleanup();
}
break;
case WM_SOCKET:
if (WSAGETSELECTERROR(wParam))// 错误检查
{
AfxMessageBox(_T("ERROR!"));
}
else
{
int nRecv = 0;
switch (WSAGETSELECTEVENT(lParam))// 事件判断
{
case FD_ACCEPT:// 连接通知
socketAccept = accept((SOCKET)socketListen, NULL, NULL);
if (INVALID_SOCKET != socketAccept)
{
CreateSocketInfo(socketAccept);
WSAAsyncSelect(socketAccept, m_hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
}
break;
case FD_READ:// 接收通知
P_SOCKET_INFO pInfo;
pInfo = GetSocketInfo(wParam);
nRecv = recv(pInfo->socket, chBuf, BUF_SIZE, 0);
if (nRecv>0)
{
m_strRecv += chBuf;
m_strRecv += _T("\r\n");
UpdateData(FALSE);
}
break;
case FD_WRITE:// 发送通知
break;
case FD_CLOSE:
pInfo = GetSocketInfo(wParam);
{
CString strTemp;
strTemp.Format(_T("客户端 %d 已关闭"), pInfo->socket);
AfxMessageBox(strTemp);
}
break;
default:
break;
}
}
}
return CDialogEx::WindowProc(message, wParam, lParam);
}
// 消息发送按钮
void CWSAAsyncSelectServDlg::OnBnClickedBtnRecvSend()
{
UpdateData(true);
//CString 转 char[]
CStringA strSend;
strSend = m_strSend;
strncpy_s(chBuf, strSend, strSend.GetLength()+1);
int err = send(socketAccept, chBuf, strlen(chBuf), 0);
if (SOCKET_ERROR == err)
{
MessageBox(_T("send error!"));
}
m_strSend = _T("");// 编辑框清空
UpdateData(false);
}
// 获取SOCKET信息
void CreateSocketInfo(SOCKET socket)
{
P_SOCKET_INFO pInfo;
if (NULL == (pInfo = (P_SOCKET_INFO)GlobalAlloc(GPTR, sizeof(SOCKET_INFO) )))
{
return;
}
pInfo->socket = socket;
pInfo->pNext = pInfoTemp;
pInfoTemp = pInfo; // 把pInfo放到pInfoTemp的第1位
int m = 8;
}
P_SOCKET_INFO GetSocketInfo(SOCKET socket)
{
P_SOCKET_INFO pInfo = pInfoTemp;
while (pInfo)
{
if (socket == pInfo->socket)
{
return pInfo;
}
pInfo = pInfo->pNext;
}
return NULL;
}
客户端
定义:
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#define WM_SOCKET (WM_USER+101)
SOCKET socketAccept;
#define BUF_SIZE 1024
char chBuf[BUF_SIZE];
在OnInitDialog()中,将客户端与服务器进行连接
BOOL CWSAAsyncSelectClientDlg::OnInitDialog()
{
int nErrorCode = 0;
WSADATA wsaData;
nErrorCode = WSAStartup(0x0202, &wsaData);
socketAccept = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == socketAccept)
{
return FALSE;
}
//nErrorCode = WSAAsyncSelect(socketAccept, m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE|FD_CONNECT);
nErrorCode = WSAAsyncSelect(socketAccept, m_hWnd, WM_SOCKET, FD_READ|FD_CLOSE);
// 连接
#if 1
sockaddr_in addrAccept;
addrAccept.sin_family = AF_INET;
addrAccept.sin_port = htons(8088);
addrAccept.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
while (1) // 因为WSAAsyncSelect 将 socketAccept 置为非阻塞模式
{
nErrorCode = connect(socketAccept, (sockaddr*)&addrAccept, sizeof(sockaddr));
if (SOCKET_ERROR == nErrorCode)
{
nErrorCode = WSAGetLastError();
if (WSAEWOULDBLOCK == nErrorCode || WSAEINVAL == nErrorCode)
{
Sleep(300);
continue;
}
else if (WSAEISCONN == nErrorCode)// 连接成功
{
break;
}
else
{
AfxMessageBox(_T("连接失败"));
return -1;
}
}
}
if (SOCKET_ERROR == nErrorCode)
{
AfxMessageBox(_T("连接失败"));
return FALSE;
}
#endif
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
return TRUE;
}
// 消息发送按钮
void CWSAAsyncSelectClientDlg::OnBnClickedBtnRecvSend()
{
UpdateData(TRUE);
CStringA strInput;
strInput = m_strSend;
memset(chBuf, ' ', sizeof(char)*1024);
strncpy_s(chBuf, strInput, strInput.GetLength()+1);
int nErrorCode = 0;
nErrorCode = send(socketAccept, chBuf, 1024, 0);
if (SOCKET_ERROR == nErrorCode)
{
nErrorCode = WSAGetLastError();
return;
}
m_strSend = _T("");// 置空
UpdateData(FALSE);
GetDlgItem(IDC_EDT_SEND)->SetFocus();
}
// 消息循环
LRESULT CWSAAsyncSelectClientDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (WM_SOCKET == message)
{
if (WSAGETSELECTERROR(wParam))
{
AfxMessageBox(_T("ERROR"));
}
else
{
CString strMsg;
switch (WSAGETSELECTEVENT(lParam))
{
case FD_READ:// 接收通知
recv((SOCKET)wParam, chBuf, BUF_SIZE, 0);
m_strRecv += chBuf;
m_strRecv += _T("\r\n");
UpdateData(FALSE);
break;
case FD_CLOSE:// 关闭通知
strMsg.Format(_T("服务器已关闭 %d"), socketAccept);
AfxMessageBox(strMsg);
break;
case FD_ACCEPT:
case FD_CONNECT:
case FD_WRITE:
break;
}
}
}
return CDialogEx::WindowProc(message, wParam, lParam);
}
源码下载
http://download.csdn.net/detail/yulinxx/7426575