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

前言

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

界面效果

MFC:Socket编程—TCP服务端和多个客户端通信_第1张图片

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 
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 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::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);
}


完整代码

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

你可能感兴趣的:(【Language_C++】,【Windows编程】)