013 网络模块的调试和完善

调试

服务端在执行命令接口,新增了一个测试接口函数

1 服务端测试代码:

int TestConnect()
{
    CPacket packet(2000, NULL, 0);
    CServerSocket::getInstance()->Send(packet);
    return 0;
}

2 客户端调试代码:

void CRemoteClientDlg::OnBnClickedBtnTest()
{
    CClientSocket* pClient = CClientSocket::getInstance();
    bool ret = pClient->InitSocket("127.0.0.1"); 
    if (!ret)
    {
        AfxMessageBox("网络初始化失败");
        return;
    }
    CPacket packet(2000, NULL, 0);
    pClient->Send(packet);
    int cmd = pClient->DealCommand();
    TRACE("ack:%d\r\n", cmd);
    pClient->CloseSocket();
}

完善:

3 存在的问题

3.1 客户端初始化套接字存在问题

问题:第一次测试连接正常,后面就无法连接

原因:服务器套接字是在构造函数里面初始话的,当第一次连接后对方关闭了套接字,我们这边的套接字就是个无效套接字了,再在上面进行connect就会失败

解决方案:在connect之间就重新初始化套接字

// 初始化套接字,true成功,false失败
    bool InitSocket(const std::string& ipAddress)
    {
        if (m_socket_server != INVALID_SOCKET)CloseSocket();
        m_socket_server = socket(AF_INET, SOCK_STREAM, 0);
        
        SOCKADDR_IN addr_server;
        addr_server.sin_family = AF_INET;
        // htons 主机字节序转为网络字节序
        addr_server.sin_port = htons(60000);
        // inet_addr 函数将包含 IPv4 点十进制地址的字符串转换为IN_ADDR结构的正确地址。
        addr_server.sin_addr.S_un.S_addr = inet_addr(ipAddress.c_str());
        // 服务器地址是否成功设置
        if (addr_server.sin_addr.S_un.S_addr == NULL)
        {
            AfxMessageBox("指定ip地址无效\r\n");
            TRACE("连接失败,:%d %s", GetLastError(), GetErrorInfo(GetLastError()).c_str());
            return false;
        }
        // 发起三次握手,连接成功后服务器就阻塞在recv等待对方发送数据
        int ret = connect(m_socket_server, (sockaddr*)&addr_server, sizeof(SOCKADDR_IN));
        if (ret == -1)
        {
            AfxMessageBox("连接失败\r\n");
            TRACE("连接失败,:%d %s", GetLastError(), GetErrorInfo(GetLastError()).c_str());
            return false;
        }
        return true;
    }

3.2 服务器接收缓冲区内存泄漏

由于buffer是new出来的,再加上我们可知我们这是个短连接,客户端一次只发送一个命令

原因:buffer是new出来的,没有delete

解决方案:在结束函数之前delete掉buffer

// 循环接收处理数据,存放在m_packet里面
    int DealCommand()
    {
        if (m_socket_client == INVALID_SOCKET)
        {
            return false;
        }
        // 存在内存泄漏bug
        char* buffer = new char[BUFFER_SIZE];
        if (buffer == NULL)
        {
            TRACE("内存不足\r\n");
            return -2;
        }
        memset(buffer, 0, BUFFER_SIZE);
        // 缓冲区当前所有数据长度
        static int index = 0;
        while (true)
        {
            size_t len = recv(m_socket_client, buffer + index, BUFFER_SIZE - index, 0);
            if (len <= 0)
            {
                // 短连接每次处理完数据需要delete掉buffer
                delete[] buffer;
                return -1;
            }
            // 每次接收数据后,index加上这个长度
            index += len;
            // 让每次解析都是全部的数据长度,如果直接传index进去解析,会导致index值被修改
            len = index;
            // len是个引用 本次解析的数据长度
            m_packet = CPacket((BYTE*)buffer, len);
            if (len > 0)
            {
                // 解析完了后,把buffer往前移
                memmove(buffer, buffer + len, BUFFER_SIZE - len);
                // index 减去用掉的长度
                index -= len;
                delete[] buffer;
                return m_packet.sCmd;
            }
        }
        delete[] buffer;
    }

4 代码优化

4.1 客户端接收缓冲区代码优化

因为客户端一次可能接收多个数据包,所以这个缓冲区需要一直能存在

所以定义一个成员变量来保存

std::vector<char> m_buffer;

在构造函数里面初始化大小

CClientSocket()
    {
        if (InitSocketEnv() == FALSE)
        {
            MessageBox(NULL, _T("无法初始化套接字环境,请检查网络环境"), _T("初始化错误"), MB_OK | MB_ICONERROR);
            exit(0);
        }
        // buffer大小初始化
        m_buffer.resize(BUFFER_SIZE);
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值