MFC中Socket网络通讯
- UDP通信:User Datagram Protocol 用户数据报协议。是一种无连接的简单的不可靠信息传送服务。OSI七层协议:www.cnblogs.com/wxgblogs/p/5641643.html
新建基于Dialog的MFC程序,在CxxxApp类的 InitInstance()中添加 AfxSocketInit();(初始化Socket)
新建一个类CSockU 基类为MFC中的CSocket,右键类名添加虚函数 OnReceive()
//////////// 头文件 SockU.h //////////////// #include <afxsock.h> ///////////////////////////////////////////////////////////////////////////// // CSockU command target class CSockU : public CSocket { // Attributes public: // Operations public: CSockU(); virtual ~CSockU(); // Overrides public: // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CSockU) public: virtual void OnReceive(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CSockU) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: };
/////////////// SockU.cpp文件 //////////////// CSockU::CSockU() { } CSockU::~CSockU() { } // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CSockU, CSocket) //{{AFX_MSG_MAP(CSockU) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ///////////////////////////////////////////////////////////////////////////// // CSockU member functions #include "15_1UDPDlg.h" void CSockU::OnReceive(int nErrorCode) {//socket接收消息 CString szIP; //存放消息来源的IP地址 UINT nPort; //存放消息来源的端口号 char buf[512] = {0}; //存消息 this->ReceiveFrom(buf, sizeof(buf), szIP, nPort);//UDP接收消息 CMy15_1UDPDlg* pDlg = (CMy15_1UDPDlg*)::AfxGetMainWnd(); pDlg->OnReceive(buf,szIP); CSocket::OnReceive(nErrorCode); }
在主对话框类添加:
void OnReceive(LPCSTR szText, LPCSTR szIP);
CSockU m_sock;
在OnInitDialog()中
BOOL CMy15_1UDPDlg::OnInitDialog() { CDialog::OnInitDialog(); // 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 //创建socket UDP:SOCK_DGRAM TCP:SOCK_STREAM BOOL b = m_sock.Create(8811, SOCK_DGRAM); SetDlgItemText(IDC_IP,"192.168.1.110"); SetDlgItemText(IDC_PORT, "8811"); DWORD nErr = GetLastError(); if(WSANOTINITIALISED == nErr) {//10093 error 表示socket未初始化 AfxMessageBox("A successful AfxSocketInit must occur before using this API."); } else if(WSAEADDRINUSE == nErr) {// 10048 error 表示端口被占用 AfxMessageBox("The specified address is already in use."); } return TRUE; // return TRUE unless you set the focus to a control }
{//发送按钮的消息响应函数 CString str; GetDlgItemText(IDC_INPUT, str); if(str.IsEmpty()) { AfxMessageBox("不能发送空文字。"); return; } CString szIP; GetDlgItemText(IDC_IP,szIP); //UDP发送消息给IP地址为szIP,端口号8811(接收时要一致) m_sock.SendTo(str,str.GetLength(),8811,szIP); }
void CMyUDPDlg::OnReceive(LPCSTR szText, LPCSTR szIP) { CString str = szIP; str += ":\r\n";//换行 str += szText; str += "\r\n"; CEdit* pwnd = (CEdit*)GetDlgItem(IDC_HIST); int len = pwnd->GetWindowTextLength(); pwnd->SetSel(len,-1); pwnd->ReplaceSel(str); }
- TCP通信:TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
1. Client 的程序
新建基于Dialog的MFC程序,在CxxxApp类的 InitInstance()中添加 AfxSocketInit();(初始化Socket)
新建一个基类为CSocket的类 CSockC
// SockC.h : header file class CSockC : public CSocket { // Attributes public: // Operations public: CSockC(); virtual ~CSockC(); // Overrides public: // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CSockC) public: virtual void OnReceive(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CSockC) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: }; ///////////////// CSockC.cpp文件 /////////////////// CSockC::CSockC() { } CSockC::~CSockC() { } // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CSockC, CSocket) //{{AFX_MSG_MAP(CSockC) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ///////////////////////////////////////////////////////////////////////////// // CSockC member functions void CSockC::OnReceive(int nErrorCode) { char s[2048] = {0}; CString szIP; UINT nPort; //TCP接收消息函数 Receive(s,sizeof(s)); //获取消息来源的IP地址和端口号 GetPeerName(szIP, nPort); TCP_ClientDlg* pDlg = (TCP_ClientDlg*)AfxGetMainWnd(); pDlg->OnReceive(s); CSocket::OnReceive(nErrorCode); }
在主对话框中添加成员函数和成员变量:
void OnReceive(CString szText);
CSockC m_sock;
在 OnInitDialog() 中:
BOOL TCP_ClientDlg::OnInitDialog() { CDialog::OnInitDialog(); // 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 if(!m_sock.Create())//创建TCP的socket { AfxMessageBox("网络创建失败!"); } if(!m_sock.Connect("192.168.1.118", 8881)) { int nErr = GetLastError();//10061连接不到服务器 AfxMessageBox("连接网络失败,请检查网络是否连接!"); } return TRUE; // return TRUE unless you set the focus to a control }
其他
void TCP_ClientDlg::OnOK() {//发送按钮的消息响应函数 CString str; GetDlgItemText(IDC_INPUT, str); if(str.IsEmpty()) { MessageBox("不能发送空文字!"); } //TCP的发送消息函数 m_sock.Send(str, str.GetLength()); // CDialog::OnOK(); } void TCP_ClientDlg::OnReceive(CString szText) { int nLen = m_hist.GetWindowTextLength(); m_hist.SetSel(nLen,-1); m_hist.ReplaceSel(szText); }
- Server 的编程
首先,在CxxxApp中的InitInstance()中初始化Socket 添加 AfxSocketInit();。在CxxxApp中添加一个成员变量 存放socket类指针的链表, List<CClientSocket*,CClientSocket*> m_list;
建立 侦听(接待)Socket类 —— CListenSocket ,和 具体的Socket类(用来接收客户端的消息)——CClientSocket
1. CListenSocket类
// ListenSocket.h : header file class CListenSocket : public CSocket { // Attributes public: // Operations public: CListenSocket(); virtual ~CListenSocket(); // Overrides public: // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CListenSocket) public: virtual void OnAccept(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CListenSocket) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: }; //////////////// 实现文件 ListenSocket.cpp //////////////// CListenSocket::CListenSocket() { } CListenSocket::~CListenSocket() { } // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CListenSocket, CSocket) //{{AFX_MSG_MAP(CListenSocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ///////////////////////////////////////////////////////////////////////////// // CListenSocket member functions void CListenSocket::OnAccept(int nErrorCode) {//等待客户连接 CClientSocket* p = new CClientSocket; if(!Accept(*p))//是否能接收成功 { delete p; return; } CString szIP; UINT nPort; p->GetPeerName(szIP,nPort);//获取IP和端口 ServerDlg* pDlg = (ServerDlg*)::AfxGetMainWnd(); pDlg->OnAccept(szIP,nPort); theApp.m_list.AddTail(p);//把指针添加到链表m_list的尾部 CSocket::OnAccept(nErrorCode); }
2. CClientSocket类
//////////// 头文件 /////////// class CClientSocket : public CSocket { // Attributes public: // Operations public: CClientSocket(); virtual ~CClientSocket(); // Overrides public: // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CClientSocket) public: virtual void OnReceive(int nErrorCode); virtual void OnClose(int nErrorCode); //}}AFX_VIRTUAL // Generated message map functions //{{AFX_MSG(CClientSocket) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG // Implementation protected: }; ////////////////// 实现文件 ////////////// CClientSocket::CClientSocket() { } CClientSocket::~CClientSocket() { } // Do not edit the following lines, which are needed by ClassWizard. #if 0 BEGIN_MESSAGE_MAP(CClientSocket, CSocket) //{{AFX_MSG_MAP(CClientSocket) //}}AFX_MSG_MAP END_MESSAGE_MAP() #endif // 0 ///////////////////////////////////////////////////////////////////////////// // CClientSocket member functions void CClientSocket::OnReceive(int nErrorCode) {//有客户发送 char s[2048] = {0}; CString szIP; UINT nPort; int nLen = this->Receive(s, sizeof(s));//接收消息 this->GetPeerName(szIP,nPort);//获取IP和端口 ServerDlg* p = (ServerDlg*)::AfxGetMainWnd(); p->OnReceive(s,szIP,nPort); //给所有的客户转发消息 POSITION pos = theApp.m_list.GetHeadPosition(); CString str; COleDateTime time = COleDateTime::GetCurrentTime(); str.Format("%s-%d:(%s)\r\n%s\r\n",szIP,nPort,time.Format("%H:%M:%S"),s); while(pos) { CClientSocket* pSock = theApp.m_list.GetNext(pos); pSock->Send(str,str.GetLength()); } CSocket::OnReceive(nErrorCode); } void CClientSocket::OnClose(int nErrorCode) { // TODO: Add your specialized code here and/or call the base class POSITION pos = theApp.m_list.GetHeadPosition(); while(pos) { if(theApp.m_list.GetAt(pos) == this) { theApp.m_list.RemoveAt(pos); break; } theApp.m_list.GetNext(pos); } delete this; CSocket::OnClose(nErrorCode); }
主对话框类添加:
void OnAccept(CString szIP,UINT nPort);
void OnReceive(CString szText,CString szIP,UINT nPort);
CListenSocket m_socket;
主对话框的实现文件
BOOL ServerDlg::OnInitDialog() { CDialog::OnInitDialog(); // 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 if(!m_socket.Create(8881))//端口为8881 { int nErr = GetLastError();//nErr=10048端口冲突 ::AfxMessageBox("网络创建失败!"); } m_socket.Listen();//开始侦听 return TRUE; // return TRUE unless you set the focus to a control } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void ServerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR ServerDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void ServerDlg::OnOK() { // TODO: Add extra validation here // CDialog::OnOK(); } void ServerDlg::OnReceive(CString szText, CString szIP, UINT nPort) { CString str; str.Format("%s-%d:\r\n%s\r\n",szIP,nPort,szText); int nLen = m_txt.GetWindowTextLength(); m_txt.SetSel(nLen,-1); m_txt.ReplaceSel(str); // MessageBox("有消息"); } void ServerDlg::OnAccept(CString szIP, UINT nPort) { CString str; str.Format("%s-%d已连接\r\n",szIP,nPort); int nLen = m_txt.GetWindowTextLength(); m_txt.SetSel(nLen,-1); m_txt.ReplaceSel(str); // MessageBox("有客户"+ str + "连接"); }
可以看看:www.cnblogs.com/happykoukou/p/8038701.html
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。