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设计:

MFC-TCP网络编程服务端-Socket_第1张图片

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指针

CArraym_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         {//遍历每一个客户端,并且发送消息给每个客户端。
            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         {
            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.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);

你可能感兴趣的:(MFC开发,网络,tcp/ip,网络协议,mfc,c++)