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


完整代码

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

  • 20
    点赞
  • 145
    收藏
    觉得还不错? 一键收藏
  • 36
    评论
### 回答1: MFC(Microsoft Foundation Classes)是微软公司开发的一套面向对象的C++类库,用于开发Windows应用程序。在MFC中,客户端服务端socket是用来进行网络通信的重要组件。 客户端socket指的是在网络中发起连接的一方。在MFC中,可以使用CSocket类来创建和管理客户端socket。通过CSocket类的成员函数,可以实现与服务器的连接、发送和接收数据等操作。客户端socket可以向服务器发送请求,获取相应的数据或服务。 服务端socket则是接受客户端连接的一方。也是通过CSocket类来创建和管理服务端socket服务端socket可以监听端口,接受客户端的连接请求,并与客户端建立通信服务端socket可以处理多个客户端的请求,提供相应的服务。 在使用MFC开发网络应用程序时,客户端服务端socket通常需要配合使用。客户端socket负责与服务端建立连接,并发送请求。服务端socket则负责接受客户端的连接请求,并处理客户端的请求。通过socket编程,可以实现客户端服务端的数据交互,实现网络通信功能。 总结来说,MFC中的客户端服务端socket是实现网络通信的重要组件。通过客户端socket可以向服务器发送请求,获取相应的数据或服务。而服务端socket则接受客户端的连接请求,并提供相应的服务。通过MFC提供的CSocket类,我们可以方便地创建、管理和控制这些socket,实现客户端服务端之间的数据交互。 ### 回答2: MFC是Microsoft Foundation Classes的缩写,它是微软公司为了简化Windows应用程序的开发而开发的一个类库。客户端服务端socket则是在网络编程中使用的两种角色。 在MFC中,我们可以使用MFC类库提供的相关类来实现客户端服务端socket通信客户端socket通常用于向服务器发送请求并接收服务器的响应。我们可以使用MFCCAsyncSocket类来创建一个客户端socket对象,然后通过对象的方法来连接服务器、发送数据和接收数据。 服务端socket则是用于接收客户端的请求并提供相应的服务。我们可以使用MFC的CSocket类来创建一个服务端socket对象,通过对象的方法来绑定本地地址和端口、监听客户端的连接请求、接收客户端发送的数据以及向客户端发送数据等操作。 在实际应用中,客户端服务端socket可以通过网络进行通信,比如TCP/IP协议。客户端通过连接服务端socket来发送请求和接收响应,而服务端socket则通过接收客户端连接来处理客户端的请求并提供相应的服务。 总之,MFC提供了方便易用的类库来实现客户端服务端socket通信,开发人员可以使用这些类库来快速开发网络应用程序。 ### 回答3: MFC是微软基于Windows操作系统的应用程序开发框架,提供了许多方便的类和函数,用于开发Windows图形用户界面应用程序。MFC中提供了用于创建和管理客户端服务端socket的类。 客户端socket用于建立与服务器的连接,并向服务器发送请求。在MFC中,可以使用CSocket类创建和管理客户端socket。CSocket类提供了一组方法,如Create、Connect、Send等,可以方便地创建一个客户端socket,并与服务器建立连接,发送数据到服务器。 服务端socket用于接受客户端的连接请求,并处理客户端发送的数据。在MFC中,可以使用CSocketCAsyncSocket类来创建和管理服务端socket。CSocket类提供了一个Accept方法,用于接受客户端的连接请求,当有新的客户端连接时,会触发一个Accept事件,开发者可以重写该事件处理函数来处理新的连接。CAsyncSocket类是一个异步的socket类,在服务端应用程序中常用于处理多个客户端的连接和数据交互。 在MFC中,客户端服务端socket之间的通信可以通过发送和接收数据来实现。客户端可以使用Send方法发送数据到服务器,而服务端可以使用Send方法将数据发送给已连接的客户端客户端服务端之间的数据交换可以使用字节流,也可以使用特定的通信协议,如HTTP、TCP/IP等。 总之,使用MFC的CSocket类和CAsyncSocket类可以方便地创建和管理客户端服务端socket,实现客户端与服务器之间的通信。通过发送和接收数据,可以实现数据的传输和交换。
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值