MFC:Socket编程—TCP服务端和多个客户端通信

前言

MFC是微软基础类库,于 C++ 对于 C语言来说,MFC对于window API ,MFC 就相当于C++,window API 相当于C。MFC 封装了 window API 使用起来更加的方便。MFC中封装的socket 直接就有事件回调,就不需要我们自己去轮询 自己去处理,我们只需要写好对于的事件回调函数即可,系统帮我们进行调用 方便了很多,而且 不需要多线程就可以实现 单个TCP服务器和多个TCP客户端的通信

界面效果

在这里插入图片描述

MFC Socket套接字介绍

CAsyncSocket对象表示一个Windows Socket–一个网络通信的末端。CAsyncSocket类封闭了Windows套接字API,对想使用与MFC连接的Windows套接字的程序员提供了一个面向对象的抽象化概念。
常用函数

Accept 接受套接字上的连接
Bind 与套接字有关的本地地址
Close 关闭套接字
Connect 对对等套接字建立连接
Listen 建立套接字,侦听即将到来的连接请求
Receive 从套接字接收数据 (TCP)
ReceiveFrom 恢复数据报并且存储资源地址 (UDP)
Send 给连接套接字发送数据 (TCP)
SendTo 给特定目的地发送数据 (UDP)

常用回调函数

OnAccept 通知侦听套接字,它可以通过调用Accept,接受挂起连接请求
OnClose 通知套接字,关闭对它的套接字连接
OnConnect 通知连接套接字,连接尝试已经完成,无论成功或失败
OnReceive 通知侦听套接字,通过调用Receive恢复数据
OnSend 通知套接字,通过调用Send,它可以发送数据

代码

TCP服务端

CServerSocket

TCP服务端 监听套接字类CServerSocket 重写OnAccept函数
头文件

#pragma once
//#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#include  "ConnSocket.h"

#include <list>
using namespace std;
// CServerSocket 命令目标
class CMy02_TCPServerDlg;
class CServerSocket : public CSocket
{
public:
	CServerSocket(CMy02_TCPServerDlg* dlg = NULL);
	virtual ~CServerSocket();
	// 接受到客户端连接的 回调函数
	virtual void OnAccept(int nErrorCode);
	// 关闭所有连接套接字
	void CloseAllConn();
private:
	CMy02_TCPServerDlg* m_dlg;
	list<CConnSocket*> m_clientList;
public:
};

cpp文件

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

#include "stdafx.h"
#include "02_TCPServer.h"
#include "ServerSocket.h"

#include "02_TCPServerDlg.h"

// CServerSocket

CServerSocket::CServerSocket(CMy02_TCPServerDlg* dlg)
{
	m_dlg = dlg;
}

CServerSocket::~CServerSocket()
{
}


// CServerSocket 成员函数

// 新的连接请求来了,该函数将被回调
void CServerSocket::OnAccept(int nErrorCode)
{
	// 由框架调用,通知监听套接字现在可以调用Accept成员函数来接收悬挂的(pending)连接请求。
	CConnSocket * client = new CConnSocket(m_dlg);
	SOCKADDR_IN addr;
	memset(&addr, 0, sizeof(addr));
	int addrLen = sizeof(addr);

	// 获取通信套接字
	Accept(*client,(SOCKADDR*)&addr,&addrLen);
	char* ip = inet_ntoa(addr.sin_addr);
	client->SetClientAddr(CString(ip), addr.sin_port);
	m_clientList.push_back(client);

	// 界面添加连接消息
	CString msg;
	SYSTEMTIME t;
	GetLocalTime(&t);
	msg.Format(_T("[%d:%d:%d] %s:%d: connect success!"),t.wHour,t.wMinute,t.wSecond,CString(ip),addr.sin_port);
	m_dlg->AddMsg(msg);

	CSocket::OnAccept(nErrorCode);
}

void CServerSocket::CloseAllConn()
{
	// 关闭监听套接字,先关闭 连接的套接字
	list<CConnSocket*>::iterator it = m_clientList.begin();
	for (; it != m_clientList.end(); )
	{
		(*it)->Close();
		delete (*it);
		it = m_clientList.erase(it);
	}
	this->Close();
}

CConnSocket

TCP服务端 通信套接字CConnSocket
头文件

#pragma once

// CConnSocket 命令目标
class CMy02_TCPServerDlg;

class CConnSocket : public CSocket
{
public:
	CConnSocket(CMy02_TCPServerDlg* dlg = NULL);
	virtual ~CConnSocket();
	virtual void OnSend(int nErrorCode);
	virtual void OnReceive(int nErrorCode);
	virtual void OnClose(int nErrorCode);
	// 设置连接的客户端的IP和端口
	void SetClientAddr(CString ip, USHORT port);
private:
	CString m_ip;
	USHORT m_port;
	CMy02_TCPServerDlg* m_dlg;
};

对应的CPP文件

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

#include "stdafx.h"
#include "02_TCPServer.h"
#include "ConnSocket.h"

#include "02_TCPServerDlg.h"

// CConnSocket

CConnSocket::CConnSocket(CMy02_TCPServerDlg* dlg)
{
	m_dlg = dlg;
}

CConnSocket::~CConnSocket()
{
}


// CConnSocket 成员函数

// 当服务器和客户端成功建立好连接,服务器端自动调用此函数
void CConnSocket::OnSend(int nErrorCode)
{
	// 本函数由框架调用,通知套接字现在可以调用Send成员函数发送数据了。
	char buf[] = "your connect success";
	Send(buf, strlen(buf)); //给客户端发送信息
	CSocket::OnSend(nErrorCode);
}

// 当对方发送消息,自动调用此函数
// 可以在函数内容做接收处理
void CConnSocket::OnReceive(int nErrorCode)
{
	// 本函数由框架调用,通知套接字缓冲中有数据,可以调用Receive成员函数取出
	char recvBuf[512] = { 0 };
	int recvLen = this->Receive(recvBuf, sizeof(recvBuf));
	CString msg;
	SYSTEMTIME t;
	GetLocalTime(&t);
	msg.Format(_T("[%d:%d:%d] %s:%d: %s"),t.wHour,t.wMinute,t.wSecond, m_ip, m_port,CString(recvBuf));
	m_dlg->AddMsg(msg);
	// 回射信息
	CharUpperA(recvBuf);
	this->Send(recvBuf, strlen(recvBuf));
}

// 对方主动断开连接,自动调用此函数
void CConnSocket::OnClose(int nErrorCode)
{
	CString msg;
	SYSTEMTIME t;
	GetLocalTime(&t);
	msg.Format(_T("[%d:%d:%d] %s:%d: already close!"), t.wHour,t.wMinute,t.wSecond,m_ip, m_port);
	m_dlg->AddMsg(msg);
	CSocket::OnClose(nErrorCode);
}

void CConnSocket::SetClientAddr(CString ip, USHORT port)
{
	m_ip = ip;
	m_port = port;
}

TCP客户端

CConnSocket

TCP客户端 通信套接字
头文件

#pragma once

class CMy02_TCPClientDlg;
// CConnSocket 命令目标

class CConnSocket : public CSocket
{
public:
	CConnSocket(CMy02_TCPClientDlg* dlg = NULL);
	virtual ~CConnSocket();
	BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort);

	virtual void OnConnect(int nErrorCode);
	virtual void OnClose(int nErrorCode);
private:
	CMy02_TCPClientDlg* m_dlg;
	CString m_ip;
	UINT m_port;
public:
	virtual void OnReceive(int nErrorCode);
};




cpp文件

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

#include "stdafx.h"
#include "02_TCPClient.h"
#include "ConnSocket.h"
#include "02_TCPClientDlg.h"

// CConnSocket

CConnSocket::CConnSocket(CMy02_TCPClientDlg* dlg)
{
	m_dlg = dlg;
}

CConnSocket::~CConnSocket()
{
}

BOOL CConnSocket::Connect(LPCTSTR lpszHostAddress, UINT nHostPort)
{
	m_ip = lpszHostAddress;
	m_port = nHostPort;
	return CAsyncSocket::Connect(lpszHostAddress, nHostPort);
}


// CConnSocket 成员函数

// 连接服务器成功,该函数会被调用
void CConnSocket::OnConnect(int nErrorCode)
{
	// 本函数由框架调用,通知该套接字连接操作已经完成,并且说明连接是成功还是失败了。

	CSocket::OnConnect(nErrorCode);
}


void CConnSocket::OnClose(int nErrorCode)
{
	// 由框架调用通知该套接字,它连接上的对应套接字已经被相关进程终止了
	CString msg;
	SYSTEMTIME t;
	GetLocalTime(&t);
	msg.Format(_T("[%d:%d:%d] %s:%d: already close!"), t.wHour, t.wMinute, t.wSecond, m_ip, m_port);
	m_dlg->AddMsg(msg);
	m_dlg->MyEnableBtn();

	this->Close();
	CSocket::OnClose(nErrorCode);
}


void CConnSocket::OnReceive(int nErrorCode)
{
	// 本函数由框架调用,通知套接字缓冲中有数据,可以调用Receive成员函数取出
	char recvBuf[512] = { 0 };
	int recvLen = this->Receive(recvBuf, sizeof(recvBuf));
	CString msg;
	SYSTEMTIME t;
	GetLocalTime(&t);
	msg.Format(_T("[%d:%d:%d] %s:%d: %s"), t.wHour,t.wMinute, t.wSecond, m_ip, m_port, CString(recvBuf));
	m_dlg->AddMsg(msg);

	CSocket::OnReceive(nErrorCode);
}


完整代码

如果有需要 这里下载完整工程

一个服务器对多个客户端MFC Socket编程示例(实现简单的即时通讯功能) 环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个是SocketServer一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端socket对象 ,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值