WSAAsyncSelect模型

来源:互联网 发布:floydwarshall算法 编辑:程序博客网 时间:2024/05/17 03:21



TCPServer.cpp

#include "TCPServer.h"#include "resource.h"#define WM_SOCKET WM_USER+1CMyApp theApp;BOOL CMyApp::InitInstance(){//初始化套接字WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2,0);::WSAStartup(wVersionRequested, &wsaData);//显示对话框CMainDialog dlg;m_pMainWnd = &dlg;dlg.DoModal();//释放套接字::WSACleanup();return FALSE;}//CMainDialogCMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd){}BEGIN_MESSAGE_MAP(CMainDialog, CDialog)ON_BN_CLICKED(IDC_START, OnStart)ON_BN_CLICKED(IDC_CLEAR, OnClear)ON_MESSAGE(WM_SOCKET, OnSocket)END_MESSAGE_MAP()void CMainDialog::OnCancel(){this->CloseAllSocket();CDialog::OnCancel();}BOOL CMainDialog::OnInitDialog(){CDialog::OnInitDialog();//设置图标SetIcon(theApp.LoadIconA(IDI_MAIN), FALSE);//创建状态栏并设置其属性m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0,0,0,0), this, 101);m_bar.SetBkColor(RGB(0xa6, 0xca, 0xfa));int arWidth[]={200,-1};m_bar.SetParts(2, arWidth);m_bar.SetText("windows程序设计", 1, 0);m_bar.SetText("空闲", 0, 0);//关联列表控件m_listInfo.SubclassDlgItem(IDC_LIST, this);//初始化套接字和连接列表m_socket = INVALID_SOCKET;m_nClient = 0;//取得本机IP,在状态栏中显示char szHostName[MAX_PATH] = {0};::gethostname(szHostName, MAX_PATH);hostent *pHost = gethostbyname(szHostName);if (pHost != NULL){CString strIP;in_addr* addr = (in_addr*)*pHost->h_addr_list;strIP.Format("本机IP:%s",inet_ntoa(addr[0]));m_bar.SetText(strIP, 0, 0);}return TRUE;}BOOL CMainDialog::CreateAndListen(int nPort){if (m_socket == INVALID_SOCKET){::closesocket(m_socket);}//创建套接字m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (m_socket == INVALID_SOCKET){return FALSE;}//绑定端口sockaddr_insin;sin.sin_family = AF_INET;sin.sin_port = htons(nPort);//sin.sin_addr.S_un.S_addr = INADDR_ANY;sin.sin_addr.s_addr = INADDR_ANY;int nErr = GetLastError();if (::bind(m_socket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){nErr = GetLastError();return FALSE;}::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE|FD_READ);//进入监听模式::listen(m_socket, 5);return TRUE;}BOOL CMainDialog::AddClient(SOCKET s){if (m_nClient < MAX_SOCKET){m_arClient[m_nClient++] = s;return TRUE;}return FALSE;}void CMainDialog::RemoveClient(SOCKET s){BOOL bFound = FALSE;int i;for (i=0;i<m_nClient;i++){if (m_arClient[i] == s){bFound = TRUE;break;}}//找到if (bFound){m_nClient--;for (int j=i;j<m_nClient;j++){m_arClient[j] = m_arClient[j+1];}}}void CMainDialog::CloseAllSocket(){if (m_socket != INVALID_SOCKET){::closesocket(m_socket);m_socket = INVALID_SOCKET;}for (int i=0;i<m_nClient;i++){::closesocket(m_arClient[i]);}m_nClient = 0;}void CMainDialog::OnStart(){if (m_socket == INVALID_SOCKET) //开启服务{CString strPort;GetDlgItem(IDC_PORT)->GetWindowText(strPort);int nPort = atoi(strPort);if (nPort < 1 || nPort >65535){MessageBox("port error");return;}//创建套接字if (!this->CreateAndListen(nPort)){MessageBox("create socket error");return;}//设置控件状态GetDlgItem(IDC_START)->SetWindowTextA("停止服务");m_bar.SetText("正在监听...", 0, 0);GetDlgItem(IDC_PORT)->EnableWindow(FALSE);}else //关闭服务{CloseAllSocket();GetDlgItem(IDC_START)->SetWindowTextA("开启服务");m_bar.SetText("空闲", 0, 0);GetDlgItem(IDC_PORT)->EnableWindow(TRUE);}return ;}void CMainDialog::OnClear(){m_listInfo.ResetContent();return ;}long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam){//得到句柄 SOCKET s = wParam;//查看是否出错if (WSAGETSELECTERROR(lParam)){RemoveClient(s);::closesocket(s);return 0;}//处理发生的事件switch (WSAGETSELECTEVENT(lParam)){case FD_ACCEPT: //监听到有套接字中有连接进入{MessageBox("server:accept");if (m_nClient < MAX_SOCKET){SOCKET client = ::accept(s, NULL, NULL);this->AddClient(client);}else{MessageBox("too many connection");}}break;case FD_CLOSE:{MessageBox("server:close");RemoveClient(s);closesocket(s);}break;case FD_READ: //接收到对方发来的数据包{MessageBox("server:read");//得到对方的地址sockaddr_in sockAddr;memset(&sockAddr, 0, sizeof(sockAddr));int nSockAddrLength = sizeof(sockAddr);::getpeername(s, (sockaddr*)&sockAddr, &nSockAddrLength);int nPeerPort = ntohs(sockAddr.sin_port);CString strIP = inet_ntoa(sockAddr.sin_addr);  // strIP//获得主机名称DWORD dwIP = ::inet_addr(strIP);hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);char szHostName[256]={0};strncpy(szHostName, pHost->h_name, 256);//得到网络数据char szContent[1024]={0};::recv(s, szContent, 1024, 0);//显示CString strItem = CString(szHostName) + "[" + strIP + "]:" + CString(szContent);m_listInfo.InsertString(0, strItem);}break;}return 0;}

TCPServer.h

#include <afxwin.h>#include <afxext.h>  //CStatusBar#include <WinSock2.h>#include <afxcmn.h>#pragma comment(lib, "WS2_32.lib")#define  MAX_SOCKET 56 //最大客户量class CMyApp:public CWinApp{public:BOOL InitInstance();};//CMainDialogclass CMainDialog:public CDialog{public:CMainDialog(CWnd* pParentWnd=NULL);protected:virtual BOOL OnInitDialog();virtual void OnCancel();//开启或停止服务afx_msg void OnStart();afx_msg void OnClear();afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);BOOL CreateAndListen(int nPort);//向客户连接列表中加一个客户BOOL AddClient(SOCKET s);//从客户连接列表中移除一个客户void RemoveClient(SOCKET s);//关闭所有连接void CloseAllSocket();protected:SOCKET m_socket;//两个子窗口控件CListBox m_listInfo;CStatusBarCtrl m_bar;//客户连接列表SOCKET m_arClient[MAX_SOCKET]; //套接字列表int m_nClient; //上述数组的大小DECLARE_MESSAGE_MAP()};


TCPClient.cpp

#include "TCPClient.h"#include "resource.h"#define WM_SOCKET WM_USER+1CMyApp theApp;BOOL CMyApp::InitInstance(){//初始化套接字WSADATA wsaData;WORD wVersionRequested = MAKEWORD(2,0);::WSAStartup(wVersionRequested, &wsaData);//显示对话框CMainDialog dlg;m_pMainWnd = &dlg;dlg.DoModal();//释放套接字::WSACleanup();return FALSE;}//CMainDialogCMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG,pParentWnd){}BEGIN_MESSAGE_MAP(CMainDialog, CDialog)ON_BN_CLICKED(IDC_CONNECT, OnConnect)ON_BN_CLICKED(IDC_SEND, OnSend)ON_MESSAGE(WM_SOCKET, OnSocket)END_MESSAGE_MAP()void CMainDialog::OnCancel(){CDialog::OnCancel();}BOOL CMainDialog::OnInitDialog(){CDialog::OnInitDialog();//设置图标SetIcon(theApp.LoadIconA(IDI_MAIN), FALSE);//关联控件m_edit_text.SubclassDlgItem(IDC_EDIT_CONTENT, this);//状态栏m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0,0), this, NULL);int nWidth[]={100,-1};m_bar.SetParts(2, nWidth);m_bar.SetText("windows程序设计", 1, 0);m_bar.SetText("空闲", 0, 0);GetDlgItem(IDC_ADDR)->SetWindowTextA("192.168.19.143");GetDlgItem(IDC_PORT)->SetWindowTextA("9999");//m_socket = INVALID_SOCKET;return TRUE;}void CMainDialog::AddStringToList(CString strText){CString strContent;GetDlgItem(IDC_EDIT_CONTENT)->GetWindowText(strContent);GetDlgItem(IDC_EDIT_CONTENT)->SetWindowText(strContent+strText);}long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam){SOCKETs = wParam;if (WSAGETSELECTERROR(lParam)){::closesocket(m_socket);m_socket = INVALID_SOCKET;return 0;}switch (WSAGETSELECTEVENT(lParam)){case FD_READ:{MessageBox("client:read");char szText[1024]={0};::recv(s, szText, 1024, 0);AddStringToList(CString(szText)+"\r\n");}break;case FD_CONNECT:{MessageBox("client:connect");GetDlgItem(IDC_CONNECT)->SetWindowTextA("断开连接");GetDlgItem(IDC_ADDR)->EnableWindow(FALSE);GetDlgItem(IDC_PORT)->EnableWindow(FALSE);GetDlgItem(IDC_TEXT)->EnableWindow(TRUE);GetDlgItem(IDC_SEND)->EnableWindow(TRUE);m_bar.SetText("已经连接到服务器", 0, 0);}break;case FD_CLOSE:{MessageBox("client:close");OnConnect();}break;}return 0;}BOOL CMainDialog::Connect(LPCTSTR pszRemoteAddr, u_short nPort){//创建套接字m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == m_socket){return FALSE;}::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE);ULONG uAddr = ::inet_addr(pszRemoteAddr);if (uAddr == INADDR_NONE){//不是IP地址,就认为是主机名称//从主机名得到IPhostent* pHost = ::gethostbyname(pszRemoteAddr);if (pHost == NULL){::closesocket(m_socket);m_socket = INVALID_SOCKET;return FALSE;}uAddr = ((struct in_addr*)*(pHost->h_addr_list))->s_addr;}//填写服务器信息sockaddr_in remote;remote.sin_family = AF_INET;remote.sin_addr.S_un.S_addr = uAddr;remote.sin_port = ::htons(nPort);//连接::connect(m_socket, (sockaddr*)&remote, sizeof(sockaddr));return TRUE;}void CMainDialog::OnConnect(){if (INVALID_SOCKET == m_socket) //连接服务器{CString strAddr;GetDlgItem(IDC_ADDR)->GetWindowText(strAddr);if (strAddr.IsEmpty()){MessageBox("the servers IP is empty");return;}CString strPort;GetDlgItem(IDC_PORT)->GetWindowTextA(strPort);int nPort = atoi(strPort);if (nPort < 1 || nPort > 65535){MessageBox("port error");return;}if (Connect(strAddr, nPort) == FALSE){MessageBox("connect to servers error...");return;}//设置用户界面GetDlgItem(IDC_CONNECT)->SetWindowText("取消");m_bar.SetText("正在连接..", 0, 0);}else //断开服务器{::closesocket(m_socket);m_socket = INVALID_SOCKET;//设置用户界面GetDlgItem(IDC_CONNECT)->SetWindowTextA("连接服务器");m_bar.SetText("空闲", 0, 0);GetDlgItem(IDC_ADDR)->EnableWindow(TRUE);GetDlgItem(IDC_PORT)->EnableWindow(TRUE);GetDlgItem(IDC_SEND)->EnableWindow(FALSE);GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);}//this->Connect(szAddr, )}void CMainDialog::OnSend(){CString strSendContent;GetDlgItem(IDC_TEXT)->GetWindowTextA(strSendContent);::send(m_socket, strSendContent, strSendContent.GetLength(), 0);GetDlgItem(IDC_TEXT)->SetWindowTextA("");}

TCPClient.h

#include <afxwin.h>#include <afxext.h>  //CStatusBar#include <WinSock2.h>#include <afxcmn.h>#pragma comment(lib, "WS2_32.lib")#define  MAX_SOCKET 56 //最大客户量class CMyApp:public CWinApp{public:BOOL InitInstance();};//CMainDialogclass CMainDialog:public CDialog{public:CMainDialog(CWnd* pParentWnd=NULL);protected:virtual BOOL OnInitDialog();virtual void OnCancel();////开启或停止服务//afx_msg void OnStart();afx_msg void OnSend();afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);void OnConnect();BOOL Connect(LPCTSTR pszRemoteAddr, u_short nPort);SOCKET m_socket;// 控件CStatusBarCtrl m_bar;CEdit m_edit_text;void AddStringToList(CString strText);//BOOL CreateAndListen(int nPort);////向客户连接列表中加一个客户//BOOL AddClient(SOCKET s);////从客户连接列表中移除一个客户//void RemoveClient(SOCKET s);////关闭所有连接//void CloseAllSocket();DECLARE_MESSAGE_MAP()};