问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

掌握网络编程基础,从零开始构建你的第一个MFC应用!

创作时间:
作者:
@小白创作中心

掌握网络编程基础,从零开始构建你的第一个MFC应用!

引用
CSDN
12
来源
1.
https://blog.csdn.net/qq_56262516/article/details/139937164
2.
https://blog.csdn.net/qq_42945868/article/details/139929657
3.
https://blog.csdn.net/weixin_42530684/article/details/139012091
4.
https://blog.csdn.net/z1076233241/article/details/135956400
5.
https://blog.csdn.net/m0_51830537/article/details/139760401
6.
https://blog.csdn.net/qq_35716085/article/details/136206445
7.
https://cloud.baidu.com/article/3017059
8.
https://blog.csdn.net/weixin_42175752/article/details/139924959
9.
https://docs.python.org/zh-cn/3.11/howto/sockets.html
10.
https://www.cnblogs.com/DSCL-ing/p/18038556
11.
https://jaminzhang.github.io/python/Python-Socket-Programming-Get-Started-and-Demo/
12.
https://www.xuedaoniu.com/news/detail247.html

在网络时代,掌握网络编程已经成为每个程序员的必备技能。从简单的数据传输到复杂的分布式系统,网络编程无处不在。本文将带你从零开始,逐步掌握网络编程的基础知识,并通过实际项目加深理解。

01

网络编程基础概念

在开始编程之前,我们需要了解一些基本概念。这些概念看似抽象,但它们是网络编程的基石。

TCP/IP模型

TCP/IP模型是网络通信的基础框架,它将网络通信分为四层:

  1. 应用层:负责处理特定的应用程序细节,如HTTP、FTP等协议。
  2. 传输层:提供端到端的数据传输服务,主要协议有TCP和UDP。
  3. 网络层:负责数据包的路由选择,核心协议是IP。
  4. 链路层:负责在同一网络中传输数据帧。

套接字(Socket)

套接字是网络编程中的基本构建块,用于实现进程间的通信。它是一个端点,可以是客户端或服务器端。在TCP/IP模型中,套接字位于传输层和应用层之间。

IP地址和端口号

IP地址用于标识网络中的设备,而端口号用于标识设备上的具体服务。一台设备可以有多个服务运行,每个服务通过不同的端口号来区分。

客户端/服务器架构

这是最常见的网络应用架构,其中服务器提供服务,客户端请求服务。例如,当你访问一个网站时,你的浏览器就是客户端,而网站的服务器就是服务端。

02

Python套接字编程入门

Python提供了强大的网络编程支持,让我们通过一个简单的例子来理解套接字编程。

创建一个TCP服务器

import socket

# 创建一个TCP/IP套接字
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定套接字到地址和端口
serversocket.bind(('localhost', 8080))

# 开始监听传入连接
serversocket.listen(5)

print("服务器已启动,等待连接...")

while True:
    # 接受客户端连接
    (clientsocket, address) = serversocket.accept()
    print(f"连接来自:{address}")

    # 发送数据到客户端
    clientsocket.send(b"Hello, World!")

    # 关闭连接
    clientsocket.close()

创建一个TCP客户端

import socket

# 创建一个TCP/IP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接到服务器
s.connect(('localhost', 8080))

# 接收服务器发送的数据
data = s.recv(1024)
print(data.decode())

# 关闭连接
s.close()

通过这个简单的例子,你可以看到服务器和客户端是如何通过套接字进行通信的。

03

MFC网络编程实战

MFC(Microsoft Foundation Classes)是微软提供的一个C++类库,用于封装Windows API。让我们看看如何使用MFC实现一个简单的FTP客户端。

使用CSocket类

MFC提供了CSocket类来简化网络编程。下面是一个使用CSocket类实现TCP客户端的例子:

#include <afxsock.h>

void CMyApp::InitInstance()
{
    // 初始化Winsock
    AfxSocketInit();

    // 创建一个CSocket对象
    CSocket socket;

    // 创建一个套接字
    if (!socket.Create(0, SOCK_STREAM, NULL))
    {
        AfxMessageBox(_T("无法创建套接字"));
        return;
    }

    // 连接到服务器
    SOCKADDR_IN serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(26); // 服务器端口号
    serveraddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.20"); // 服务器IP

    if (socket.Connect((SOCKADDR*)&serveraddr, sizeof(serveraddr)))
    {
        BYTE sendarray[8];
        socket.Send((char*)sendarray, sizeof(sendarray));

        // 接收数据
        char rec[1024];
        socket.Receive(rec, 1024);

        // 关闭连接
        socket.Close();
    }
}

实现FTP客户端

FTP(文件传输协议)使用两个端口:21端口用于控制连接,20端口用于数据传输。我们可以基于CSocket类来实现一个简单的FTP客户端。

#include <afxsock.h>

class CFtpClient : public CObject
{
public:
    CFtpClient()
    {
        // 初始化Winsock
        AfxSocketInit();
    }

    BOOL Connect(const CString& strServer, int nPort = 21)
    {
        // 创建控制连接套接字
        if (!m_controlSocket.Create())
            return FALSE;

        // 连接到FTP服务器
        if (!m_controlSocket.Connect(strServer, nPort))
            return FALSE;

        // 登录FTP服务器
        if (!Login())
            return FALSE;

        return TRUE;
    }

    BOOL Login(const CString& strUser = _T("anonymous"), const CString& strPass = _T(""))
    {
        // 发送USER命令
        CString strCmd;
        strCmd.Format(_T("USER %s\r\n"), strUser);
        m_controlSocket.Send(strCmd);

        // 接收服务器响应
        CString strResponse;
        if (!ReceiveResponse(strResponse))
            return FALSE;

        // 发送PASS命令
        strCmd.Format(_T("PASS %s\r\n"), strPass);
        m_controlSocket.Send(strCmd);

        // 接收服务器响应
        if (!ReceiveResponse(strResponse))
            return FALSE;

        return TRUE;
    }

    BOOL DownloadFile(const CString& strRemoteFile, const CString& strLocalFile)
    {
        // 发送PASV命令
        CString strCmd(_T("PASV\r\n"));
        m_controlSocket.Send(strCmd);

        // 接收服务器响应
        CString strResponse;
        if (!ReceiveResponse(strResponse))
            return FALSE;

        // 解析数据端口
        int nDataPort = ParsePasvResponse(strResponse);
        if (nDataPort == 0)
            return FALSE;

        // 创建数据连接套接字
        if (!m_dataSocket.Create())
            return FALSE;

        // 连接到数据端口
        if (!m_dataSocket.Connect(m_strServer, nDataPort))
            return FALSE;

        // 发送RETR命令
        strCmd.Format(_T("RETR %s\r\n"), strRemoteFile);
        m_controlSocket.Send(strCmd);

        // 接收文件数据
        CFile file;
        if (!file.Open(strLocalFile, CFile::modeCreate | CFile::modeWrite))
            return FALSE;

        char buffer[4096];
        int nBytesRead;
        while ((nBytesRead = m_dataSocket.Receive(buffer, sizeof(buffer))) > 0)
        {
            file.Write(buffer, nBytesRead);
        }

        // 关闭文件和数据连接
        file.Close();
        m_dataSocket.Close();

        return TRUE;
    }

private:
    CSocket m_controlSocket;
    CSocket m_dataSocket;
    CString m_strServer;

    BOOL ReceiveResponse(CString& strResponse)
    {
        char buffer[1024];
        int nBytesRead = m_controlSocket.Receive(buffer, sizeof(buffer) - 1);
        if (nBytesRead <= 0)
            return FALSE;

        buffer[nBytesRead] = '\0';
        strResponse = buffer;
        return TRUE;
    }

    int ParsePasvResponse(const CString& strResponse)
    {
        // 解析PASV响应中的IP和端口信息
        // 格式为:h1,h2,h3,h4,p1,p2
        int nPos = strResponse.Find(_T("("));
        if (nPos == -1)
            return 0;

        CString strIpPort = strResponse.Mid(nPos + 1);
        nPos = strIpPort.Find(_T(")"));
        if (nPos == -1)
            return 0;

        strIpPort = strIpPort.Left(nPos);
        CStringArray arrParts;
        strIpPort.Split(_T(","), arrParts);

        if (arrParts.GetSize() != 6)
            return 0;

        int nIp1 = _ttoi(arrParts[0]);
        int nIp2 = _ttoi(arrParts[1]);
        int nIp3 = _ttoi(arrParts[2]);
        int nIp4 = _ttoi(arrParts[3]);
        int nPort1 = _ttoi(arrParts[4]);
        int nPort2 = _ttoi(arrParts[5]);

        m_strServer.Format(_T("%d.%d.%d.%d"), nIp1, nIp2, nIp3, nIp4);
        return (nPort1 << 8) + nPort2;
    }
};

通过这个例子,你可以看到如何使用MFC的CSocket类来实现一个完整的FTP客户端。虽然这只是一个简单的实现,但它涵盖了FTP客户端的核心功能。

04

总结

网络编程虽然看起来复杂,但通过Python和MFC这样的工具,我们可以轻松上手。从理解基本概念到编写实际代码,每一步都是在为成为一名优秀的网络程序员打基础。希望这篇文章能帮助你开启网络编程之旅。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号