MFC WinSock类编程

MFC WinSock类编程

目录:

1.CAsyncSocket类

2.CSocket类

3.CArchive类与对象串行化

4.使用CSocket及对象串行化方法编写网络程序


MFC WinSock类:简化套接字编程过程、利用Windows的消息驱动机制

MFC提供了两个套接字类-CAsyncSocket、CSocket这两个类在不同层次上对WinSock API函数进行了封装、并利用Winodows的消息驱动机制提供了各种网络事件的处理函数。


CAsyncSocket是CObject类的派生类,实现了对WinSock API较低层次的封装。通过该类中预定义的网络事件处理函数的重载,应用程序可以方便地对套接字的各种网络事件进行处理。

扫描二维码关注公众号,回复: 1859330 查看本文章

使用CAsyncSocket类需要对网络通信细节有较多的了解,但简化了利用Windows消息驱动机制处理网络I/O事件的编程过程。


CSocket类是CAsyncSocket的派生类。是对WinSock API更进一步的封装。

CSocket帮助完成了字节顺序转换 和字符转换等问题,用户编程时可以不必再考虑。

CSocket类结合CArchive类和CSocketFile类一起使用,大大简化了数据的收发处理过程,减少编程的复杂性。


例子1:使用CAsyncSocket类编写简单的点对点聊天程序:

首先要从CAsyncSocket类派生自己的异步套接字通信类,并对需要处理的网络事件的处理函数进行重载。

在需要进行网络通信的类中(一般指一个对话框,主界面类),将上面自己派生的类作为该需要通信的类的一个成员!

即:一般在主对话框的定义中添加派生套接字类的对象作为其成员变量。如果程序有其他窗口需要通信,则必须在其他窗口对应的类中添加想要的的派生套接字类对象作为其成员变量。

这里有一个成员变量怎么与主类进行交互的问题!

在对话框应用程序中,由于响应网络事件所需要的数据缓冲区(套接字编程的程序缓冲区)等资源大都是对话框类的成员,

因此,CAsyncSocket派生类中重载的事件处理函数不可避免的要访问对话框对象的成员。为此,需要在CAsyncSocket的派生类对象与用于资源的对话框对象之间建立一沟通的桥梁:在CAsyncSocket派生类对象中添加其主对话框类型的指针变量。通过这个指针,事件处理函数就可以访问对话框类对象的成员了!(这里的成员要是公有成员)

面向对象编程,搞清楚这几个类直接的关系就OK!


这里还有个问题就是程序代码字符集:项目属性->配置属性->常规->项目默认值->字符集:选择使用多字节字符集。

不然发送后,接收端会乱码。

还有个问题是接收函数recv()返回的实际接收的字节数,有时候并不是发送端实际发送的字节数。而等于接收缓冲区的长度(字节数)。这一的话在字符串后面加'\0’结尾符就会错误!(数据越界)。



服务器界面:


客户端界面:



CAsyncSocket项目:

服务器端监听套接字类(CAsyncSocket的派生类)定义:

ServerSocket.h:

#pragma once
#include "afxsock.h"
class CCAsyncSocketDlg;
class CServerSocket :
	public CAsyncSocket
{
public:
	CServerSocket();
	~CServerSocket();
	CCAsyncSocketDlg* pDlg;
	virtual void OnAccept(int nErrorCode);
};



ServerSocket.cpp:

#include "stdafx.h"
#include "ServerSocket.h"
#include"CAsyncSocketDlg.h"




CServerSocket::CServerSocket()
{
	pDlg = NULL;
}




CServerSocket::~CServerSocket()
{
	pDlg = NULL;
}




void CServerSocket::OnAccept(int nErrorCode)
{
	// TODO:  在此添加专用代码和/或调用基类
	pDlg->OnAccept();
	CAsyncSocket::OnAccept(nErrorCode);
}

有监听套接字返回的已连接套接字:用于和对端通信的套接字:

ClientSocket.h:

#pragma once
#include "afxsock.h"
class CCAsyncSocketDlg;
class CClientSocket :
	public CAsyncSocket
{
public:
	CClientSocket();
	~CClientSocket();
	CCAsyncSocketDlg* pDlg;
	virtual void OnReceive(int nErrorCode);
};

ClientSocket.cpp:

#include "stdafx.h"
#include "ClientSocket.h"
#include"CAsyncSocketDlg.h"



CClientSocket::CClientSocket()
{
	pDlg = NULL;
}


CClientSocket::~CClientSocket()
{
	pDlg = NULL;
}


void CClientSocket::OnReceive(int nErrorCode)
{
	// TODO:  在此添加专用代码和/或调用基类
	pDlg->OnReceive();
	CAsyncSocket::OnReceive(nErrorCode);
}

主对话框类:

CAsyncSocketDlg.h:

// CAsyncSocketDlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include"ClientSocket.h"
#include"ServerSocket.h"
#include"Resource.h"

// CCAsyncSocketDlg 对话框
class CCAsyncSocketDlg : public CDialogEx
{
// 构造
public:
	CCAsyncSocketDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_CASYNCSOCKET_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持

	char recvBuff[1000];
	CServerSocket serversocket;
	CClientSocket clientsocket;

// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CListBox m_ListBox;
	CString m_Text;

	void OnAccept();
	void OnReceive();


public:
	afx_msg void OnBnClickedOk();
};

CAsyncSocketDlg.cpp:

// CAsyncSocketDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "CAsyncSocket.h"
#include "CAsyncSocketDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
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()


// CCAsyncSocketDlg 对话框



CCAsyncSocketDlg::CCAsyncSocketDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCAsyncSocketDlg::IDD, pParent)
	, m_Text(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCAsyncSocketDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_ListBox);
	DDX_Text(pDX, IDC_EDIT1, m_Text);
}

BEGIN_MESSAGE_MAP(CCAsyncSocketDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//ON_MESSAGE(Accept, &CCAsyncSocketDlg::OnAccept)
	//ON_MESSAGE(Receive, &CCAsyncSocketDlg::OnReceive)
	ON_BN_CLICKED(IDOK, &CCAsyncSocketDlg::OnBnClickedOk)
END_MESSAGE_MAP()


// CCAsyncSocketDlg 消息处理程序

BOOL CCAsyncSocketDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	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);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:  在此添加额外的初始化代码

	serversocket.pDlg = this;
	clientsocket.pDlg = this;
	serversocket.Create(65432, SOCK_STREAM, FD_ACCEPT | FD_READ,_T("127.0.0.1"));
	serversocket.Listen();

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCAsyncSocketDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCAsyncSocketDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		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;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCAsyncSocketDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CCAsyncSocketDlg::OnAccept()
{
	serversocket.Accept(clientsocket);
	
}


void CCAsyncSocketDlg::OnReceive()
{
	int size = clientsocket.Receive(recvBuff, sizeof(recvBuff));
	if (size > 0)
	{
		recvBuff[size] = '\0';
		m_ListBox.AddString((LPCTSTR)recvBuff);
	}
	
}


void CCAsyncSocketDlg::OnBnClickedOk()
{
	// TODO:  在此添加控件通知处理程序代码
	UpdateData(TRUE);
	CString m = _T("");
	m_ListBox.AddString(m+"I said" + m_Text);
	clientsocket.Send(m_Text, m_Text.GetLength(), 0);
	
}


客户端项目:

首先同样派生字节的套接字类:ClientSocket.h:

#pragma once
#include "afxsock.h"
class CCAsyncSockClientDlg;

class CClientSocket :
	public CAsyncSocket
{
public:
	CClientSocket();
	~CClientSocket();
	CCAsyncSockClientDlg* pDlg;



	virtual void OnConnect(int nErrorCode);
	virtual void OnReceive(int nErrorCode);
	virtual void OnSend(int nErrorCode);
};

ClientSocket.cpp:

#include "stdafx.h"
#include "ClientSocket.h"
#include"CAsyncSockClientDlg.h"

CClientSocket::CClientSocket()
{
}


CClientSocket::~CClientSocket()
{
}


void CClientSocket::OnConnect(int nErrorCode)
{
	// TODO:  在此添加专用代码和/或调用基类
	pDlg->OnConnect();
	CAsyncSocket::OnConnect(nErrorCode);
}


void CClientSocket::OnReceive(int nErrorCode)
{
	// TODO:  在此添加专用代码和/或调用基类
	pDlg->OnReceive();
	CAsyncSocket::OnReceive(nErrorCode);
}


void CClientSocket::OnSend(int nErrorCode)
{
	// TODO:  在此添加专用代码和/或调用基类
	
	CAsyncSocket::OnSend(nErrorCode);
}

主对话框类:

CAsyncSockClientDlg.h:

// CAsyncSockClientDlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include"ClientSocket.h"
#include"resource.h"


// CCAsyncSockClientDlg 对话框
class CCAsyncSockClientDlg : public CDialogEx
{
// 构造
public:
	CCAsyncSockClientDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_CASYNCSOCKCLIENT_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持

	char recvBuff[1000];
	CClientSocket clientsocket;
public:
	void OnReceive();
	
	void OnConnect();

// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CListBox m_ListBox;
	CString m_Text;
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedButton1();
};

CAsyncSockClientDlg.cpp:

// CAsyncSockClientDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "CAsyncSockClient.h"
#include "CAsyncSockClientDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
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()


// CCAsyncSockClientDlg 对话框



CCAsyncSockClientDlg::CCAsyncSockClientDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCAsyncSockClientDlg::IDD, pParent)
	, m_Text(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCAsyncSockClientDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_ListBox);
	DDX_Text(pDX, IDC_EDIT1, m_Text);
}

BEGIN_MESSAGE_MAP(CCAsyncSockClientDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDOK, &CCAsyncSockClientDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BUTTON1, &CCAsyncSockClientDlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CCAsyncSockClientDlg 消息处理程序

BOOL CCAsyncSockClientDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	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);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:  在此添加额外的初始化代码

	clientsocket.pDlg = this;
	clientsocket.Create(65431, SOCK_STREAM, FD_READ|FD_CONNECT);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CCAsyncSockClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CCAsyncSockClientDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		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;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCAsyncSockClientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CCAsyncSockClientDlg::OnReceive()
{
	int size = clientsocket.Receive(recvBuff, sizeof(recvBuff));
	if (size > 0)
	{
		recvBuff[size] = '\0';
		m_ListBox.AddString((LPCTSTR)recvBuff);
	}
}




void CCAsyncSockClientDlg::OnConnect()
{
	MessageBox(_T("已经连接成功!"));
}

void CCAsyncSockClientDlg::OnBnClickedOk()
{
	// TODO:  在此添加控件通知处理程序代码
	UpdateData(TRUE);
	CString m = _T("");

	m_ListBox.AddString(m + "I said" + m_Text);

	USES_CONVERSION;
	char* keyChar = T2A(m_Text.GetBuffer(0));
	m_Text.ReleaseBuffer();

	clientsocket.Send(keyChar, m_Text.GetLength(), 0);
	
}


void CCAsyncSockClientDlg::OnBnClickedButton1()
{
	// TODO:  在此添加控件通知处理程序代码
	//SOCKADDR clientAddr;

	//clientAddr.sa_family = AF_INET;
	//clientAddr.sa_data = { "192.168.2.116" };
	//strcpy(clientAddr.sa_data, "192.168.2.116");

	clientsocket.Connect(_T("127.0.0.1"), 65432);

	//if (!clientsocket.Connect(_T("127.0.0.1"), 65432))
	//{
	//	DWORD errCode=GetLastError();
	//	CString str2;
	//	str2.Format(_T("%d"), errCode);

	//	CString str1(_T("连接失败!错误代码:"));
	//	MessageBox(str1+str2);
	//	return;
	//}

}

3。CArchive类与对象串行化

实现类成员变量状态对硬盘存储介质的串行化存储和读取重构类对象。

Student类有三个成员变量:学生姓名,性别,成绩。实现其串行化。

首先定义支持串行化的类:(必须继承自CObject)

student.h:

#include<afx.h>
/*******定义一个可串行化的类********/
class CStudent : public CObject  
{  
DECLARE_SERIAL(CStudent)     //串行化宏
private:  
    CString name;  
    bool gender;  
    int score;  
public:  
    CStudent();  //默认构造函数,是串行化所必需的
    CStudent(CString name, bool gender = true, int score=0);  //构造函数
    CString getName();  
	void setName(CString name);
    int getScore();  
	void setScore(int parscore);
	void setGender(bool pargender);
    bool isMale();
    virtual void Serialize(CArchive& ar);  //重载串行化函数
};

CStudent.cpp:

#include "stdafx.h"
#include "student.h"
IMPLEMENT_SERIAL(CStudent, CObject, 1)   
CStudent::CStudent()    //默认构造函数的实现
{  
    name = _T("无名氏");  
    score = 0;  
    gender = true;  
}  
CStudent::CStudent(CString parname, bool pargender, int parscore)  //构造函数
{  
    name = parname;  
    gender = pargender; 
	score=parscore;
}  
CString CStudent::getName() { return name; }  
void CStudent::setName(CString parname) { name=parname; }  
int CStudent::getScore() { return score; }  
void CStudent::setScore(int parscore) { score = parscore;}  
bool CStudent::isMale() { return gender; } 
void CStudent::setGender(bool pargender){ gender=pargender; }
void CStudent::Serialize(CArchive& ar)  //串行化函数的实现
{  
    if (ar.IsStoring())  
    {  
        ar << this->name<<this->gender << this->score;  
    }  
    else 
    {  
        ar >> this->name>>this->gender >> this->score;  
    }  
}

main.cpp:

// Example92.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include "student.h"
int main()  
{  
    CStudent zhang("张三", false, 68);  //创建两个待写入的对象
    CStudent li( "李四", true, 97);  
    CFile oFile("student.achv",CFile::modeCreate|CFile::modeWrite); //以创建和写的方式打开文件student.achv
    CArchive oar(&oFile, CArchive::store);  //创建CArchive对象 
    oar << &zhang << &li;  //串行化(写入文件)  
	oar. Flush(); 
	oar.Close(); //关闭CArchive对象
    oFile.Close();  //关闭文件
    
	CFile iFile("student.achv", CFile::modeRead);  //以读方式打开文件
    CArchive iar(&iFile, CArchive::load);  //创建CArchive对象
    CStudent *p1, * p2;  //定义指针变量,用于指向载入的CStudent对象
    iar >> p1 >> p2;  //载入对象(反串行化,读文件并创建对象),注意这里是创建了对象了的
    
	/****显示新载入对象的成员变量值****/
    CString gen;
	if(p1->isMale()) gen="男"; else gen="女";
	printf("%s, %s, %d\n",p1->getName(),gen,p1->getScore());
    if(p2->isMale())gen="男"; else gen="女";
	printf("%s,  %s,   %d\n",p2->getName(),gen,p2->getScore());
    /***删除新载入对象***/
	delete p1;  
    delete p2;  
	system("pause");
	return 0;
}

4.使用CSocket类、CFileSocket类和CArchive类的串行化方法编写一个简单的点对点聊天程序:





服务器端:

首先定于支持串行化的类,用于保存要传输的数据(服务器端和客户端的该类完全相同)

myData.h:

#pragma once

// myData 命令目标

class myData : public CObject  
{  
DECLARE_SERIAL(myData)		//串行化宏
private:  
public:  
	CString str;
    myData();	//默认构造函数,是串行化所必须的
    myData(CString str);  
    virtual void Serialize(CArchive& ar);  //重载串行化函数
}; 

CmyData.cpp:

// myData.cpp : 实现文件
//

#include "stdafx.h"
#include "Server93.h"
#include "myData.h"

/**********类的实现**********/
IMPLEMENT_SERIAL(myData, CObject, 1|VERSIONABLE_SCHEMA)  
 
myData::myData()  
{  
    str="";  

}  
 
myData::myData(CString str1)  
{  
   str=str1;
}  
 

void myData::Serialize(CArchive& ar)  
{  
    if (ar.IsStoring())  
    {  
        ar << this->str;  
    }  
    else 
    {  
        ar >> this->str;  
    }  
} 

监听套(服务端)接字:

Server93.h:

// Server93.h : PROJECT_NAME 应用程序的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"		// 主符号


// CServer93App:
// 有关此类的实现,请参阅 Server93.cpp
//

class CServer93App : public CWinApp
{
public:
	CServer93App();

// 重写
public:
	virtual BOOL InitInstance();

// 实现

	DECLARE_MESSAGE_MAP()
};

extern CServer93App theApp;

Server93.cpp:

// Server93.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "Server93.h"
#include "Server93Dlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CServer93App

BEGIN_MESSAGE_MAP(CServer93App, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CServer93App 构造

CServer93App::CServer93App()
{
	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: 在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CServer93App 对象

CServer93App theApp;


// CServer93App 初始化

BOOL CServer93App::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();

	if (!AfxSocketInit())
	{
		AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
		return FALSE;
	}


	AfxEnableControlContainer();

	// 创建 shell 管理器,以防对话框包含
	// 任何 shell 树视图控件或 shell 列表视图控件。
	CShellManager *pShellManager = new CShellManager;

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

	CServer93Dlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: 在此放置处理何时用
		//  “确定”来关闭对话框的代码
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: 在此放置处理何时用
		//  “取消”来关闭对话框的代码
	}

	// 删除上面创建的 shell 管理器。
	if (pShellManager != NULL)
	{
		delete pShellManager;
	}

	// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
	//  而不是启动应用程序的消息泵。
	return FALSE;
}


已连接套接字(用于与对端通信):

ClientSocket.h:

#pragma once

// CClientSocket 命令目标
class CServer93Dlg;
class CClientSocket : public CSocket
{
public:
	CClientSocket();
	virtual ~CClientSocket();
	CServer93Dlg *m_pDlg;
	
	virtual void OnReceive(int nErrorCode);
};


ClientSocket.cpp:

// ClientSocket.cpp : 实现文件
//

#include "stdafx.h"
#include "Server93.h"
#include "ClientSocket.h"
#include "Server93Dlg.h"

// CClientSocket

CClientSocket::CClientSocket()
{
	m_pDlg=NULL;

}

CClientSocket::~CClientSocket()
{
	m_pDlg=NULL;
	
}


// CClientSocket 成员函数


void CClientSocket::OnReceive(int nErrorCode)
{
	// TODO: 在此添加专用代码和/或调用基类
	m_pDlg->OnReceive(); 
	CSocket::OnReceive(nErrorCode);
	
}

主对话框类:

Server93Dlg.h:

// Server93Dlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include "ClientSocket.h"
#include "ServerSocket.h"


// CServer93Dlg 对话框
class CServer93Dlg : public CDialogEx
{
// 构造
public:
	CServer93Dlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_SERVER93_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CListBox m_ListBox;
	CString m_Text;
	CServerSocket  serversocket;//定义监听套接字对象
	CClientSocket  clientsocket;//定义已连接套接字对象
CSocketFile *psFile;//定义CSocketFile指针;
	CArchive *arIn, *arOut; //定义用于数据收发的串行化对象指针
	void OnAccept(void);
	void OnReceive(void);
	afx_msg void OnBnClickedOk();
	afx_msg void OnBnClickedButton1();
};

Server93Dlg.cpp:

// Server93Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "Server93.h"
#include "Server93Dlg.h"
#include "afxdialogex.h"
#include "myData.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
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()


// CServer93Dlg 对话框


CServer93Dlg::CServer93Dlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CServer93Dlg::IDD, pParent)
	, m_Text(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CServer93Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_ListBox);
	DDX_Text(pDX, IDC_EDIT1, m_Text);
}

BEGIN_MESSAGE_MAP(CServer93Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDOK, &CServer93Dlg::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BUTTON1, &CServer93Dlg::OnBnClickedButton1)
END_MESSAGE_MAP()


// CServer93Dlg 消息处理程序

BOOL CServer93Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	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);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	serversocket.m_pDlg=this;
	clientsocket.m_pDlg=this; 
	serversocket.Create(65432,SOCK_STREAM);
	serversocket.Listen(); 

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CServer93Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CServer93Dlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		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;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CServer93Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CServer93Dlg::OnAccept(void)
{
	//调用Accept()方法接收连接请求
	if(serversocket.Accept(clientsocket))
	{
		psFile= new CSocketFile(&clientsocket) ;  //创建CSockFile对象
		arIn=new CArchive(psFile, CArchive::load); //创建用于接收数据的CArchive对象
		arOut=new CArchive(psFile, CArchive::store); //创建用于发送数据的CArchive对象
		m_ListBox.AddString("客户已连接!");
	}
	else
		MessageBox("接收连接失败!");
	
}

void CServer93Dlg::OnReceive(void)
{
	//接收数据并在列表框空间中显示收到数据
   	myData *pStr;
	*arIn>>pStr;
	arIn->Flush(); 
	m_ListBox.AddString(pStr->str);  //将收到内容添加到ListBox控件
	
}


void CServer93Dlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	serversocket.Close();
	clientsocket.Close();

	CDialogEx::OnOK();
}


void CServer93Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(true);  //将数据由控件传向控件变量
	m_ListBox.AddString("I said:"+m_Text); //将要发送的内容添加到ListBox控件上显示
	  //发送数据到客户端
	myData pStr;
	pStr.str=m_Text;
	*arOut<<&pStr;//mstr;
	arOut->Flush();
}

参考文献:[1]Windows网络编程基础教程

[2]链接:https://pan.baidu.com/s/1cSO5EF_u1-7YxBj5p2T61A 密码:6xlj



猜你喜欢

转载自blog.csdn.net/m0_37357063/article/details/80809848
今日推荐