使用CAsyncSocket类进行网络编程
来源:互联网 发布:php开源电商系统源码 编辑:程序博客网 时间:2024/06/06 07:04
1 服务器端
由先得专门为服务器端做一个Socket通信类CNewSocket类,此类继承CAsyncSocket类,专门负责服务器端socket通信事情:
NewSocket.h:
[cpp] view plain copy
- #pragma once
- #include "afxsock.h"
- //此类专门用来与客户端进行socket通信
- class CNewSocket :
- public CAsyncSocket
- {
- public:
- CNewSocket(void);
- ~CNewSocket(void);
- virtual void OnReceive(int nErrorCode);
- virtual void OnSend(int nErrorCode);
- // 消息长度
- UINT m_nLength;
- //消息缓冲区
- char m_szBuffer[4096];
- };
对应实现代码如下:
NewSocket.cpp:
[cpp] view plain copy
- #include "StdAfx.h"
- #include "NewSocket.h"
- CNewSocket::CNewSocket(void)
- : m_nLength(0)
- {
- memset(m_szBuffer,0,sizeof(m_szBuffer));
- }
- CNewSocket::~CNewSocket(void)
- {
- if(m_hSocket !=INVALID_SOCKET)
- {
- Close();
- }
- }
- void CNewSocket::OnReceive(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- m_nLength =Receive(m_szBuffer,sizeof(m_szBuffer),0); //接收数据
- m_szBuffer[m_nLength] ='\0';
- //接收消息后就开始给客户端发相同的消息
- AsyncSelect(FD_WRITE); //触发OnSend函数
- CAsyncSocket::OnReceive(nErrorCode);
- }
- void CNewSocket::OnSend(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- char m_sendBuf[4096]; //消息缓冲区
- strcpy(m_sendBuf,"server send:");
- strcat(m_sendBuf,m_szBuffer);
- Send(m_sendBuf,strlen(m_sendBuf));
- //触发OnReceive函数
- AsyncSelect(FD_READ);
- CAsyncSocket::OnSend(nErrorCode);
- }
如上,NewSocket类重载了CAsyncSocket类的接收与发送事件处理例程,一旦被触发了发送或接收事件,将调用此对应函数.
接下来服务器端在做一个专门类CListenSocket类,用来监听来自客户端的连接请求,如下:
ListenSocket.h:
[cpp] view plain copy
- #pragma once
- #include "afxsock.h"
- #include "NewSocket.h"
- class CListenSocket :
- public CAsyncSocket
- {
- public:
- CListenSocket(void);
- ~CListenSocket(void);
- CNewSocket *m_pSocket; //指向一个连接的socket对象
- virtual void OnAccept(int nErrorCode);
- };
其实现代码如下:
ListenSocket.cpp:
[cpp] view plain copy
- #include "StdAfx.h"
- #include "ListenSocket.h"
- CListenSocket::CListenSocket(void)
- {
- }
- CListenSocket::~CListenSocket(void)
- {
- }
- void CListenSocket::OnAccept(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- CNewSocket *pSocket =new CNewSocket();
- if(Accept(*pSocket))
- {
- pSocket->AsyncSelect(FD_READ); //触发通信socket的Read函数读数据
- m_pSocket =pSocket;
- }
- else
- {
- delete pSocket;
- }
- CAsyncSocket::OnAccept(nErrorCode);
- }
这个OnAccept事件触发是在Listen之后,如果有客户端尝试连接时触发,且先看后续内容.
接下来就是对话框的代码了:
SocketServerDlg.h:
[cpp] view plain copy
- // SocketServerDlg.h : header file
- //
- #pragma once
- #include "ListenSocket.h"
- // CSocketServerDlg dialog
- class CSocketServerDlg : public CDialogEx
- {
- // Construction
- public:
- CSocketServerDlg(CWnd* pParent = NULL); // standard constructor
- // Dialog Data
- enum { IDD = IDD_SOCKETSERVER_DIALOG };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- CListenSocket m_srvrSocket; //监听套接字
- // Implementation
- protected:
- HICON m_hIcon;
- // Generated message map functions
- virtual BOOL OnInitDialog();
- afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
- afx_msg void OnPaint();
- afx_msg HCURSOR OnQueryDragIcon();
- DECLARE_MESSAGE_MAP()
- public:
- afx_msg void OnBnClickedBtStart();
- };
[cpp] view plain copy
- // SocketServerDlg.cpp : implementation file
- //
- #include "stdafx.h"
- #include "SocketServer.h"
- #include "SocketServerDlg.h"
- #include "afxdialogex.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // CAboutDlg dialog used for App About
- class CAboutDlg : public CDialogEx
- {
- public:
- CAboutDlg();
- // Dialog Data
- enum { IDD = IDD_ABOUTBOX };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- // Implementation
- protected:
- DECLARE_MESSAGE_MAP()
- };
- CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
- {
- }
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
- END_MESSAGE_MAP()
- // CSocketServerDlg dialog
- CSocketServerDlg::CSocketServerDlg(CWnd* pParent /*=NULL*/)
- : CDialogEx(CSocketServerDlg::IDD, pParent)
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
- void CSocketServerDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CSocketServerDlg, CDialogEx)
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_BN_CLICKED(IDC_BT_START, &CSocketServerDlg::OnBnClickedBtStart)
- END_MESSAGE_MAP()
- // CSocketServerDlg message handlers
- BOOL CSocketServerDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // Add "About..." menu item to system menu.
- // IDM_ABOUTBOX must be in the system command range.
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 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
- return TRUE; // return TRUE unless you set the focus to a control
- }
- void CSocketServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialogEx::OnSysCommand(nID, lParam);
- }
- }
- // 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 CSocketServerDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // device context for painting
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<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
- {
- CDialogEx::OnPaint();
- }
- }
- // The system calls this function to obtain the cursor to display while the user drags
- // the minimized window.
- HCURSOR CSocketServerDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- void CSocketServerDlg::OnBnClickedBtStart()
- {
- // TODO: Add your control notification handler code here
- if(m_srvrSocket.m_hSocket ==INVALID_SOCKET)
- {
- //创建监听套接字,激发FD_ACCEPT事件,默认端口7190
- BOOL bFlag =m_srvrSocket.Create(7190,SOCK_STREAM,FD_ACCEPT); //第三个参数表示m_srvrSocket只对FD_ACCEPT事件感兴趣
- if(!bFlag)
- {
- AfxMessageBox(_T("Socket创建失败!"));
- m_srvrSocket.Close();
- PostQuitMessage(0);
- return;
- }
- GetDlgItem(IDC_BT_START)->EnableWindow(FALSE);
- //监听成功,等待连接请求
- if(!m_srvrSocket.Listen())//如果监听失败
- {
- int nErrorCode =m_srvrSocket.GetLastError(); //检测错误信息
- if(nErrorCode !=WSAEWOULDBLOCK) //如果不是线程阻塞
- {
- AfxMessageBox(_T("Socket错误!"));
- m_srvrSocket.Close();
- PostQuitMessage(0);
- return;
- }
- }
- }
- }
当用户按下start按键时,程序首先调用m_srvrSocket的Create函数创建一个socket,然后调用它的Listen函数监听客户端的连接请求,一旦客户端尝试连接服务器,那将触发m_srvrSocket的FD_ACCEPT事件.接着在m_srvrSocket的OnAccept函数内,将创建一个CNewSocket对象,并利用此对象来操作socket收发,到此,服务器端的代码完.
2 客户端
这里的客户端的功能就是与服务器建立连接,交用户的数据发送给服务器,并显示来自服务器的接收数据.
与服务器类似,首先做一个专门用于socket通信的类ClientSocket类:
ClientSocket.h:
[cpp] view plain copy
- #pragma once
- #include "afxsock.h"
- class ClientSocket :
- public CAsyncSocket
- {
- public:
- ClientSocket(void);
- ~ClientSocket(void);
- // 是否连接
- bool m_bConnected;
- // 消息长度
- UINT m_nLength;
- //消息缓冲区
- char m_szBuffer[5096];
- virtual void OnConnect(int nErrorCode);
- virtual void OnReceive(int nErrorCode);
- virtual void OnSend(int nErrorCode);
- };
[cpp] view plain copy
- #include "StdAfx.h"
- #include "ClientSocket.h"
- #include "SocketTest.h"
- #include "SocketTestDlg.h"
- ClientSocket::ClientSocket(void)
- : m_bConnected(false)
- , m_nLength(0)
- {
- memset(m_szBuffer,0,sizeof(m_szBuffer));
- }
- ClientSocket::~ClientSocket(void)
- {
- if(m_hSocket !=INVALID_SOCKET)
- {
- Close();
- }
- }
- void ClientSocket::OnConnect(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- //连接成功
- if(nErrorCode ==0)
- {
- m_bConnected =TRUE;
- //获取主程序句柄
- CSocketTestApp *pApp =(CSocketTestApp *)AfxGetApp();
- //获取主窗口
- CSocketTestDlg *pDlg =(CSocketTestDlg *)pApp->m_pMainWnd;
- //在主窗口输出区显示结果
- CString strTextOut;
- strTextOut.Format(_T("already connect to "));
- strTextOut +=pDlg->m_Address;
- strTextOut += _T(" 端口号:");
- CString str;
- str.Format(_T("%d"),pDlg->m_Port);
- strTextOut +=str;
- pDlg->m_MsgR.InsertString(0,strTextOut);
- //激活一个网络读取事件,准备接收
- AsyncSelect(FD_READ);
- }
- CAsyncSocket::OnConnect(nErrorCode);
- }
- void ClientSocket::OnReceive(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- //获取socket数据
- m_nLength =Receive(m_szBuffer,sizeof(m_szBuffer));
- //获取主程序句柄
- CSocketTestApp *pApp =(CSocketTestApp *)AfxGetApp();
- //获取主窗口
- CSocketTestDlg *pDlg =(CSocketTestDlg *)pApp->m_pMainWnd;
- CString strTextOut(m_szBuffer);
- //在主窗口的显示区显示接收到的socket数据
- pDlg->m_MsgR.InsertString(0,strTextOut);
- memset(m_szBuffer,0,sizeof(m_szBuffer));
- CAsyncSocket::OnReceive(nErrorCode);
- }
- void ClientSocket::OnSend(int nErrorCode)
- {
- // TODO: Add your specialized code here and/or call the base class
- //发送数据
- Send(m_szBuffer,m_nLength,0);
- m_nLength =0;
- memset(m_szBuffer,0,sizeof(m_szBuffer));
- //继续提请一个读的网络事件,接收socket消息
- AsyncSelect(FD_READ);
- CAsyncSocket::OnSend(nErrorCode);
- }
接下来就是对话框代码了:
SocketTestDlg.h:
[cpp] view plain copy
- // SocketTestDlg.h : header file
- //
- #pragma once
- #include "afxwin.h"
- #include "ClientSocket.h"
- // CSocketTestDlg dialog
- class CSocketTestDlg : public CDialogEx
- {
- // Construction
- public:
- CSocketTestDlg(CWnd* pParent = NULL); // standard constructor
- // Dialog Data
- enum { IDD = IDD_SOCKETTEST_DIALOG };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- // Implementation
- protected:
- HICON m_hIcon;
- // Generated message map functions
- virtual BOOL OnInitDialog();
- afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
- afx_msg void OnPaint();
- afx_msg HCURSOR OnQueryDragIcon();
- DECLARE_MESSAGE_MAP()
- public:
- // 服务器IP地址
- CString m_Address;
- // 服务器端口号
- int m_Port;
- // 消息接收显示控件
- CListBox m_MsgR;
- afx_msg void OnBnClickedBtClear();
- afx_msg void OnBnClickedOk();
- // 用户输入的即将发送的内容
- CString m_MsgS;
- afx_msg void OnBnClickedBtConnect();
- afx_msg void OnTimer(UINT_PTR nIDEvent);
- // 连接服务器次数
- int m_nTryTimes;
- ClientSocket m_ClientSocket;
- afx_msg void OnBnClickedBtSend();
- afx_msg void OnBnClickedBtClose();
- };
其实现代码如下:
[cpp] view plain copy
- // SocketTestDlg.cpp : implementation file
- //
- #include "stdafx.h"
- #include "SocketTest.h"
- #include "SocketTestDlg.h"
- #include "afxdialogex.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // CAboutDlg dialog used for App About
- class CAboutDlg : public CDialogEx
- {
- public:
- CAboutDlg();
- // Dialog Data
- enum { IDD = IDD_ABOUTBOX };
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- // Implementation
- protected:
- DECLARE_MESSAGE_MAP()
- };
- CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
- {
- }
- void CAboutDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
- BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
- END_MESSAGE_MAP()
- // CSocketTestDlg dialog
- CSocketTestDlg::CSocketTestDlg(CWnd* pParent /*=NULL*/)
- : CDialogEx(CSocketTestDlg::IDD, pParent)
- , m_Address(_T("127.0.0.1"))
- , m_Port(0)
- , m_MsgS(_T(""))
- , m_nTryTimes(0)
- {
- m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
- }
- void CSocketTestDlg::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- DDX_Text(pDX, IDC_ET_IPADDRESS, m_Address);
- DDX_Text(pDX, IDC_ET_PORT, m_Port);
- DDX_Control(pDX, IDC_LIST_R, m_MsgR);
- DDX_Text(pDX, IDC_ET_SEND, m_MsgS);
- }
- BEGIN_MESSAGE_MAP(CSocketTestDlg, CDialogEx)
- ON_WM_SYSCOMMAND()
- ON_WM_PAINT()
- ON_WM_QUERYDRAGICON()
- ON_BN_CLICKED(IDC_BT_CLEAR, &CSocketTestDlg::OnBnClickedBtClear)
- ON_BN_CLICKED(IDOK, &CSocketTestDlg::OnBnClickedOk)
- ON_BN_CLICKED(IDC_BT_CONNECT, &CSocketTestDlg::OnBnClickedBtConnect)
- ON_WM_TIMER()
- ON_BN_CLICKED(IDC_BT_SEND, &CSocketTestDlg::OnBnClickedBtSend)
- ON_BN_CLICKED(IDC_BT_CLOSE, &CSocketTestDlg::OnBnClickedBtClose)
- END_MESSAGE_MAP()
- // CSocketTestDlg message handlers
- BOOL CSocketTestDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // Add "About..." menu item to system menu.
- // IDM_ABOUTBOX must be in the system command range.
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // 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
- return TRUE; // return TRUE unless you set the focus to a control
- }
- void CSocketTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- }
- else
- {
- CDialogEx::OnSysCommand(nID, lParam);
- }
- }
- // 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 CSocketTestDlg::OnPaint()
- {
- if (IsIconic())
- {
- CPaintDC dc(this); // device context for painting
- SendMessage(WM_ICONERASEBKGND, reinterpret_cast<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
- {
- CDialogEx::OnPaint();
- }
- }
- // The system calls this function to obtain the cursor to display while the user drags
- // the minimized window.
- HCURSOR CSocketTestDlg::OnQueryDragIcon()
- {
- return static_cast<HCURSOR>(m_hIcon);
- }
- void CSocketTestDlg::OnBnClickedBtClear()
- {
- // TODO: Add your control notification handler code here
- m_MsgR.ResetContent();
- }
- void CSocketTestDlg::OnBnClickedOk()
- {
- // TODO: Add your control notification handler code here
- /*CDialogEx::OnOK();*/
- UpdateData(TRUE);
- if(m_MsgS.IsEmpty())
- {
- AfxMessageBox(_T("please type the message you want to send!"));
- return;
- }
- }
- void CSocketTestDlg::OnBnClickedBtConnect()
- {
- // TODO: Add your control notification handler code here
- //如果当前已经与服务器建立了连接,则直接返回
- if(m_ClientSocket.m_bConnected)
- {
- AfxMessageBox(_T("当前已经与服务器建立连接"));
- return;
- }
- UpdateData(TRUE);
- if(m_Address.IsEmpty())
- {
- AfxMessageBox(_T("服务器的IP地址不能为空!"));
- return;
- }
- if(m_Port <=1024)
- {
- AfxMessageBox(_T("服务器的端口设置非法!"));
- return;
- }
- //使Connect按键失能
- GetDlgItem(IDC_BT_CONNECT)->EnableWindow(FALSE);
- //启动连接定时器,每1秒中尝试一次连接
- SetTimer(1,1000,NULL);
- }
- void CSocketTestDlg::OnTimer(UINT_PTR nIDEvent)
- {
- // TODO: Add your message handler code here and/or call default
- if(m_ClientSocket.m_hSocket ==INVALID_SOCKET)
- {
- BOOL bFlag =m_ClientSocket.Create(0,SOCK_STREAM,FD_CONNECT); //创建套接字
- if(!bFlag)
- {
- AfxMessageBox(_T("Socket创建失败!"));
- m_ClientSocket.Close();
- PostQuitMessage(0);//退出
- return;
- }
- }
- m_ClientSocket.Connect(m_Address,m_Port); //连接服务器
- if(m_nTryTimes >=10)
- {
- KillTimer(1);
- AfxMessageBox(_T("连接失败!"));
- GetDlgItem(IDC_BT_CONNECT)->EnableWindow(TRUE);
- return;
- }
- else if(m_ClientSocket.m_bConnected)
- {
- KillTimer(1);
- GetDlgItem(IDC_BT_CONNECT)->EnableWindow(TRUE);
- return;
- }
- CString strTextOut =_T("尝试连接服务器第");
- m_nTryTimes ++;
- CString str;
- str.Format(_T("%d"),m_nTryTimes);
- strTextOut +=str;
- strTextOut +=_T("次...");
- m_MsgR.InsertString(0,strTextOut);
- CDialogEx::OnTimer(nIDEvent);
- }
- void CSocketTestDlg::OnBnClickedBtSend()
- {
- // TODO: Add your control notification handler code here
- UpdateData(TRUE);
- if(m_ClientSocket.m_bConnected)
- {
- //将用户输入的数据从CString转化为char *字符串,即Unicode-->ANSI,并保存到m_ClientSocket.m_szBuffer中
- int len =WideCharToMultiByte(CP_ACP,0,m_MsgS,-1,NULL,0,NULL,NULL);
- WideCharToMultiByte(CP_ACP,0,m_MsgS,-1,m_ClientSocket.m_szBuffer,len,NULL,NULL );
- m_ClientSocket.m_nLength =strlen(m_ClientSocket.m_szBuffer);
- m_ClientSocket.AsyncSelect(FD_WRITE);//触发写事件
- m_MsgS =_T("");
- UpdateData(FALSE);
- }
- }
- void CSocketTestDlg::OnBnClickedBtClose()
- {
- // TODO: Add your control notification handler code here
- m_ClientSocket.ShutDown();
- EndDialog(0);
- }
OK,完!
阅读全文
0 0
- 使用CAsyncSocket类进行网络编程
- 使用CAsyncSocket类进行网络编程
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- 使用MFC快速实现网络编程 CAsyncSocket
- MFC快速实现网络编程CAsyncSocket类
- 网络编程 CAsyncSocket
- [转]使用MFC快速实现网络编程 CAsyncSocket
- 网络编程 套接字类CAsyncSocket的用法
- MFC下的网络编程(1)CAsyncSocket进行无连接(UDP)通信
- .bat文件执行java程序
- python xml parse and modify node
- 链表的复制
- ListView的优化1
- 未能找到类型或命名空间XXXXXXX
- 使用CAsyncSocket类进行网络编程
- 使用Python模拟登录知乎
- 数据库系统概念 读书笔记(二)
- MFC消息映射BEGIN_MESSAGE_MAP详解
- java虚拟机---类加载机制
- gcc中scanf的使用及返回值问题
- Oracle+VS2015+C++使用记录
- 循环链表
- webpack前段构建性能优化策略小结