MFC-TCP网络编程服务端-Socket

目录

1、通过Socket建立服务端:

2、UI设计:

3、代码的实现:

(1)、CListenSocket类

(2)、CConnectSocket类

(3)、CTcpServerDlg类


1、通过Socket建立服务端:

(1)、创建一个Socket对象并绑定一个端口:CListenSocket 监听Socket

(2)、通过Listen()函数,监听来自客户端的连接请求

(3)、连接请求到来之后,建立一个通信用的Socket,CConnectSocket,并且加入数组中

(4)、使用Send()、Receive()函数,接收客户端发送的数据,并遍历数组,一次转发消息

2、UI设计:

3、代码的实现:

(1)、CListenSocket类

CListenSocket的目的是等待客户端的连接请求,继承Socket类,重写Socket的OnAccept函数,创建Socket对象,连接的初始化和等待客户端连接。

CListenSocket.h中

CListenSocket(CTcpServerDlg * pdlg);//传递对话框的指针

~CListenSocket();

virtual void OnAccept(int nErrorCode);//重写父类

CTcpServerDlg *m_pMainDlg;//接收传递的对话框指针

CListenSocket.cpp中

CListenSocket::CListenSocket(CTcpServerDlg * pdlg)

{

m_pMainDlg = pdlg; //初始化接收的对话框指针

}

void CListenSocket::OnAccept(int nErrorCode)

{

// TODO: 在此添加专用代码和/或调用基类

CSocket::OnAccept(nErrorCode);

m_pMainDlg->ProcessPendingAccept();//对于连接函数的处理放在对话框函数中处理

}

(2)、CConnectSocket类

CConnectSocket的目的是通讯用的Socket,继承Socket类,重写Socket的OnReceive函数,数据的接收和处理以及数据的解析。

CConnectSocket.h中

CConnectSocket(CTcpServerDlg *pdlg);

~CConnectSocket();

virtual void OnReceive(int nErrorCode);

CTcpServerDlg *m_pMainDlg;

CConnectSocket.cpp中

CConnectSocket::CConnectSocket(CTcpServerDlg *pdlg)

{

m_pMainDlg = pdlg;

}

void CConnectSocket::OnReceive(int nErrorCode)

{

// TODO: 在此添加专用代码和/或调用基类

CSocket::OnReceive(nErrorCode);

m_pMainDlg->ProcessPendingRead(this);//接收消息必须要传递指针进去,调用接收函数

}

(3)、CTcpServerDlg类

1)、声明服务端用于监听的socket

//服务端声明的用于监听的socket

CListenSocket *m_pListenSocket;

2)、声明一个CArray的对象,里面存放的CConectSocket指针

CArray<CConnectSocket*, CConnectSocket*&>m_ConnectSocketList;

//m_ConnectSocketList是CArray的一个对象,里面放着CConnectSocket的指针,并且可以对里面的数据进行访问和修改。

// CConnectSocket*&当数组元素被传递给函数时,使用引用方式传递元素,可以有效避免不必要的拷贝和内存开销。

3)、定义一个结构体,保存客户端的IP和Port

struct ClientAddr

{

CString strIp;

UINT uiPort;

};

4)、框架类的入口函数初始化监听Socket和端口号

m_pListenSocket = new CListenSocket(this);

//m_pListenSocket用来监听服务器的连接所以要分配内存

m_pListenSocket->Create(8080);

//初始化端口号

if (!m_pListenSocket->Listen())

{

MessageBox(L"监听失败!");

return FALSE;

}

5)、实现ProcessPendingAccept()函数

主要实现监听服务器的连接,监听到了就加到列表中

CConnectSocket *pConnectSocket = new CConnectSocket(this);

if (m_pListenSocket->Accept(*pConnectSocket))

{

m_ConnectSocketList.Add(pConnectSocket);

}

else {

delete pConnectSocket;

}

6)、实现ProcessPendingRead()函数

数据的接收,并且存放在buff中

TCHAR buff[4096];//存放接收到的数据

//接收数据

int nRead = connectSocket->Receive(buff, 4096);

if (nRead == SOCKET_ERROR)

{

return;

}

buff[nRead] = L'\0';//接收到的数据末尾加上结束符

CString strTemp(buff);//格式化buff

把连接到的客户端IP和Port存放在结构体中

ClientAddr clientAddr;//用来存放客户端的IP和Port

//获取连接上来的客户端的IP和端口

connectSocket->GetPeerName(clientAddr.strIp, clientAddr.uiPort);

解析数据:加入房间enter

int i = 0;

//解析数据

if (strTemp.CompareNoCase(L"enter") == 0)

{

//通知其他客户端有人进入房间

CString strEnterMsg;

strEnterMsg.Format(L"系统消息:%s(%d)进入了房间", clientAddr.strIp, clientAddr.uiPort);

for ( i;i<m_ConnectSocketList.GetSize();i++)

{//遍历每一个客户端,并且发送消息给每个客户端。

CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);

tempClient->Send(strEnterMsg, strEnterMsg.GetLength() + 100);

}

显示到界面

//更新界面

SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());//显示当前客户端人数

CString ALmSG;

GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);//EDIT上显示的之前的消息

SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strEnterMsg);

//显示的现在的消息加上之前的消息

解析数据:离开房间leave

//从列表中移除

for (i;i<m_ConnectSocketList.GetSize();i++)

{

CConnectSocket *&temClient = m_ConnectSocketList.ElementAt(i);

ClientAddr temClientAddr;

temClient->GetPeerName(temClientAddr.strIp, temClientAddr.uiPort);

if (temClientAddr.uiPort == clientAddr.uiPort && temClientAddr.strIp.Compare(clientAddr.strIp) == 0)

{//当前移除的IP和Port如果和加入的时候存放在结构体的一样直接跳出循环删除

break;

}

if (i<m_ConnectSocketList.GetSize())

{

m_ConnectSocketList.RemoveAt(i);

}

发送给每一个客户端消息

//通知所有人

CString strleaveMsg;

strleaveMsg.Format(L"系统消息:%s(%d)进入了房间", clientAddr.strIp, clientAddr.uiPort);

for (i; i < m_ConnectSocketList.GetSize(); i++)

{

CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);

tempClient->Send(strleaveMsg, strleaveMsg.GetLength() + 100);

}

更新界面

//更新界面

SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());

CString ALmSG;

GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);

SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strleaveMsg);

发送的是普通消息

//遍历每一个客户端发出,然后更新界面即可

CString strMsg;

strMsg.Format(L"%s(%d):%s", clientAddr.strIp, clientAddr.uiPort,strTemp);

for (i; i < m_ConnectSocketList.GetSize(); i++)

{

CConnectSocket *& tempClient = m_ConnectSocketList.ElementAt(i);

tempClient->Send(strMsg, strMsg.GetLength() + 100);

}

//更新界面

SetDlgItemInt(IDC_EDIT_NUMBER, m_ConnectSocketList.GetSize());

CString ALmSG;

GetDlgItemText(IDC_EDIT_MESSAGE, ALmSG);

SetDlgItemText(IDC_EDIT_MESSAGE, ALmSG + L"\r\n" + strMsg);

相关推荐
2301_780789663 小时前
UDP和TCP的主要区别是什么
服务器·网络协议·web安全·网络安全·udp
_丿丨丨_4 小时前
XSS(跨站脚本攻击)
前端·网络·xss
古月-一个C++方向的小白4 小时前
C++11之lambda表达式与包装器
开发语言·c++
一只栖枝5 小时前
HCIA-Security 认证精讲!网络安全理论与实战全掌握
网络·web安全·网络安全·智能路由器·hcia·it·hcia-security
FileLink跨网文件交换5 小时前
文件摆渡系统十大软件|文件摆渡系统如何构建网络安全呢?
网络
rainbow_lucky01066 小时前
MFC UI控件CheckBox从专家到小白
mfc·checkbox
tanyongxi666 小时前
C++ AVL树实现详解:平衡二叉搜索树的原理与代码实现
开发语言·c++
斯是 陋室8 小时前
在CentOS7.9服务器上安装.NET 8.0 SDK
运维·服务器·开发语言·c++·c#·云计算·.net
晨欣8 小时前
大型语言模型(LLM)在网络安全中最具商业价值的应用场景(Grok3 回答 DeepSearch模式)
网络·web安全·语言模型
有书Show9 小时前
个人IP的塑造方向有哪些?
网络·网络协议·tcp/ip