为了账号安全,请及时绑定邮箱和手机立即绑定

C++11服务器学习:从入门到实践

标签:
Linux C++
概述

本文详细介绍了C++11服务器学习的相关内容,包括C++11语言的新特性、开发环境搭建、服务器基础概念以及网络编程入门知识。此外,还通过实战创建了一个简单的C++11服务器,并探讨了性能优化和安全性的考虑。通过这些内容,读者可以全面了解和掌握C++11服务器的开发与优化技巧。

C++11简介与安装

C++11是C++编程语言的一个重要版本,于2011年正式发布。这个版本引入了许多新特性,旨在提高语言的现代性、易用性以及性能。C++11不仅为编程提供了更强大的工具,还大大简化了某些任务,提高了代码的可读性和可维护性。

C++11语言特性简介

C++11语言中引入了许多重要的新特性。以下是一些关键特性:

自动类型推断(auto关键字)

使用auto关键字可以自动推断变量的类型,这使得代码更加简洁。例如:

auto x = 5;  // x 被自动推断为 int 类型
auto y = 3.0;  // y 被自动推断为 double 类型
auto z = "Hello";  // z 被自动推断为 const char* 类型

常量表达式(constexpr

constexpr可以用于声明常量表达式,这意味着这些表达式的计算可以在编译时完成。这可以用于常量的声明和函数的定义,以提高性能和代码的可读性。

constexpr int max_size = 100;
constexpr int add(int a, int b) {
    return a + b;
}

字符串字面量(R"..."

C++11引入了原始字符串字面量,允许字符串中包含特殊字符而无需转义。例如:

std::string s1 = R"Hello\nWorld)";
std::string s2 = R"(Hello\nWorld)";

智能指针(std::unique_ptr, std::shared_ptr

智能指针管理内存,有助于防止内存泄漏。std::unique_ptr拥有独占所有权,std::shared_ptr允许多个对象共享所有权。

#include <memory>

std::unique_ptr<int> ptr1(new int(42));
std::shared_ptr<int> ptr2 = std::make_shared<int>(42);

Lambda表达式

Lambda表达式是一种定义内联匿名函数的方式,适用于短小精悍的操作。

auto func = [](int a, int b) {
    return a + b;
};
int result = func(3, 5);  // result 是 8

range-based for循环

C++11引入了基于范围的for循环,用于迭代容器中的元素:

std::vector<int> vec = {1, 2, 3};
for (int value : vec) {
    std::cout << value << " ";
}

空值合并运算符(? :

C++11引入了空值合并运算符?:,用于在变量为nullptr时提供默认值。

std::string str = nullptr ? "Not Available" : "Available";

移动语义(std::move

移动语义允许将资源从一个对象转移至另一个对象,而无需进行深复制,从而提升性能:

std::vector<int> vec1 = {1};
std::vector<int> vec2 = std::move(vec1);  // vec1 资源被移动至 vec2
开发环境搭建与C++11支持确认

搭建C++11开发环境通常需要安装支持C++11的编译器,如GCC或Clang。以下是一个基于Ubuntu的示例安装过程:

安装GCC(版本4.9或更高)

首先,确保你的系统中安装了最新版本的GCC。如果未安装,可以使用如下命令安装:

sudo apt-get update
sudo apt-get install g++-7

确认C++11支持

安装完成后,你可以通过下面的代码测试C++11特性是否可用:

#include <iostream>
#include <string>

int main() {
    auto today = std::string("Today is ") + __TIME__;
    std::cout << today << std::endl;
    return 0;
}

编译并运行此代码:

g++ -std=c++11 -o test test.cpp
./test

如果编译成功并且程序运行正常,说明你的环境已经支持C++11。

服务器基础概念

服务器在网络中扮演着关键角色,它们提供各种服务并响应客户端的请求。理解服务器的基础概念和架构有助于开发更高效、更安全的服务器应用。

服务器类型介绍

服务器可以分为多种类型,每种类型都有其特定的功能和应用场景。常见的服务器类型包括:

文件服务器

文件服务器专门用于文件的存储和管理。它支持文件的创建、读取、修改和删除等操作。文件服务器通常用于集中存储共享文件,例如公司内部文档、图片等。

Web服务器

Web服务器负责托管和分发网页内容。它通过HTTP或HTTPS协议接收和响应客户端(如浏览器)的请求,返回网页和其他内容。常见的Web服务器有Apache、Nginx、Microsoft IIS等。

数据库服务器

数据库服务器负责管理和提供数据库服务。它支持数据的存储、查询、更新和删除等操作。数据库服务器通常用于数据的集中存储和管理,例如MySQL、PostgreSQL、Oracle等。

应用服务器

应用服务器提供运行和管理应用程序的环境。它可以托管和执行应用程序代码,提供各种服务如会话管理、事务处理、安全性等。常见的应用服务器有Tomcat、Jetty、WildFly等。

网络协议基础

网络协议是计算机之间通信的基础规则。以下是几种常用的网络协议:

TCP/IP

TCP/IP(传输控制协议/互联网协议)是最常用的网络协议之一,用于在不同的网络之间传输数据。它定义了数据如何在网络中传输和路由,确保数据包的正确传输和接收。

HTTP

HTTP(超文本传输协议)是用于在客户端和服务器之间传输网页的标准协议。它定义了请求和响应的格式,使得客户端可以请求网页资源,服务器可以返回响应。

HTTPS

HTTPS是HTTP的安全版本,通过加密传输确保数据的安全性。它利用SSL/TLS协议在客户端和服务器之间建立加密连接,防止数据被窃听或篡改。

DNS

DNS(域名系统)用于将域名转换为IP地址,使得客户端可以找到正确的服务器。当客户端输入一个网址时,DNS服务器会解析出对应的IP地址,以便客户端连接到正确的服务器。

FTP

FTP(文件传输协议)用于在网络上进行文件传输。它支持文件的上传、下载、删除等操作,常用于文件的共享和备份。

SMTP

SMTP(简单邮件传输协议)用于传输电子邮件。它定义了邮件服务器如何发送和接收邮件,确保邮件的正确传输。

C++11网络编程入门

网络编程涉及在不同的计算机之间传输数据。C++11提供了强大的库支持,使得网络编程更加简单高效。本节将介绍C++11中的基本网络库以及TCP/UDP编程示例。

基础网络库介绍

C++11提供了多种网络库,可以满足不同的需求。以下是一些常用的网络库:

POSIX Socket API

POSIX Socket API是基于BSD socket的网络编程接口,广泛应用于各种操作系统,包括Linux和Mac OS。它提供了低级的网络编程功能,支持TCP和UDP通信,适用于需要深入控制网络操作的应用程序。

Boost.Asio

Boost.Asio是一个强大的异步网络库,支持多种协议,如TCP、UDP、HTTP等。它提供了丰富的异步I/O功能,使得网络编程更加高效和灵活。Boost.Asio的异步编程模型非常适合处理并发请求和长时间连接。

Poco Net

Poco Net是Poco库中的网络子库,提供了多种网络编程功能。它支持TCP、UDP、HTTP等协议,提供了一致的接口和强大的功能,适用于需要跨平台支持的应用程序。

OpenSSL

OpenSSL是一个强大的加密库,支持多种加密算法和协议。它可以与POSIX Socket API和Boost.Asio等网络库结合使用,实现安全的网络通信。

Qt Network

Qt Network是Qt库中的网络子库,提供了多种网络编程功能。它支持TCP、UDP、HTTP等协议,提供了一致的接口和强大的功能,适用于需要跨平台支持的应用程序。

TCP/UDP编程实例

本节将通过示例代码展示如何使用POSIX Socket API实现TCP和UDP通信。

TCP客户端示例

TCP客户端代码如下:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to connect to server" << std::endl;
        return 1;
    }

    std::string message = "Hello from TCP client";
    send(sock, message.c_str(), message.size(), 0);

    close(sock);
    return 0;
}

TCP服务器示例

TCP服务器代码如下:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to bind" << std::endl;
        return 1;
    }

    if (listen(sock, 5) < 0) {
        std::cerr << "Failed to listen" << std::endl;
        return 1;
    }

    int client_sock = accept(sock, nullptr, nullptr);
    if (client_sock < 0) {
        std::cerr << "Failed to accept client" << std::endl;
        return 1;
    }

    char buffer[1024];
    read(client_sock, buffer, 1024);
    std::cout << "Received message: " << buffer << std::endl;

    close(client_sock);
    close(sock);
    return 0;
}

UDP客户端示例

UDP客户端代码如下:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    std::string message = "Hello from UDP client";
    sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));

    close(sock);
    return 0;
}

UDP服务器示例

UDP服务器代码如下:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

    char buffer[1024];
    socklen_t client_addr_len = sizeof(struct sockaddr_in);
    struct sockaddr_in client_addr;
    int bytes_received = recvfrom(sock, buffer, 1024, 0, (struct sockaddr *)&client_addr, &client_addr_len);
    if (bytes_received > 0) {
        std::cout << "Received message: " << buffer << std::endl;
    }

    close(sock);
    return 0;
}

通过以上示例代码,可以更好地理解如何使用C++11进行TCP和UDP编程。这些示例展示了客户端和服务器的基本通信过程,为开发更复杂的网络应用打下基础。

实战:创建简单的C++11服务器

本节将通过一个简单的C++11服务器示例,演示如何设计和实现一个基本的网络服务器。这个服务器将支持TCP连接,并能够接收客户端的消息和发送响应。

设计思路与架构

设计一个简单的服务器需要考虑以下几个关键点:

服务器基本功能

  1. 监听端口:服务器需要监听一个端口,等待客户端连接。
  2. 接收消息:从客户端接收数据。
  3. 处理消息:根据接收到的消息执行相应操作。
  4. 发送响应:将处理后的响应发送回客户端。
  5. 关闭连接:完成通信后关闭与客户端的连接。

多线程或异步处理

为了处理多个客户端请求,服务器需要支持多线程或异步处理。多线程可以帮助服务器同时处理多个客户端连接,提高服务器的并发处理能力。

错误处理

服务器需要能够处理各种错误情况,如网络错误、文件操作错误等。适当的错误处理可以提高系统的稳定性和可靠性。

性能优化

服务器性能是关键因素之一。合理的内存管理、最小化网络延迟和优化数据处理算法都能提高服务器的性能。

安全性考虑

安全是服务器设计中的重要方面。服务器需要采取措施防止恶意攻击,如拒绝服务攻击(DoS)和中间人攻击(MITM)等。

代码实现与调试

接下来,我们将通过具体的代码实现一个简单的C++11 TCP服务器,支持与客户端通信。

服务器主程序

以下是服务器的主程序代码:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <thread>
#include <mutex>

std::mutex mtx;

void handle_client(int client_sock) {
    char buffer[1024];
    int bytes_received;

    while (true) {
        bytes_received = recv(client_sock, buffer, 1024, 0);
        if (bytes_received <= 0) break;

        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "Received message: " << buffer << std::endl;

        std::string response = "Message received: " + std::string(buffer);
        send(client_sock, response.c_str(), response.size(), 0);
    }

    close(client_sock);
}

int main() {
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to bind" << std::endl;
        return 1;
    }

    if (listen(server_sock, 5) < 0) {
        std::cerr << "Failed to listen" << std::endl;
        return 1;
    }

    std::cout << "Server listening on port 12345" << std::endl;

    while (true) {
        int client_sock = accept(server_sock, nullptr, nullptr);
        if (client_sock < 0) {
            std::cerr << "Failed to accept client" << std::endl;
            continue;
        }

        std::cout << "New client connected" << std::endl;
        std::thread handler(handle_client, client_sock);
        handler.detach();
    }

    close(server_sock);
    return 0;
}

客户端程序

下面是一个简单的TCP客户端代码,用于测试服务器功能:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to connect to server" << std::endl;
        return 1;
    }

    std::string message = "Hello from TCP client";
    send(sock, message.c_str(), message.size(), 0);

    char buffer[1024];
    int bytes_received = recv(sock, buffer, 1024, 0);
    std::cout << "Received message: " << buffer << std::endl;

    close(sock);
    return 0;
}

调试与测试

在调试和测试阶段,可以使用以下步骤:

  1. 编译代码:使用g++编译服务器和客户端程序。
    g++ -std=c++11 -o server server.cpp
    g++ -std=c++11 -o client client.cpp
  2. 运行服务器:启动服务器程序。
    ./server
  3. 运行客户端:启动客户端程序,测试与服务器的通信。
    ./client

通过以上步骤,可以确保服务器程序能够正确运行并处理客户端请求。

服务器性能优化与安全

为了构建一个高效、可靠的服务器应用,性能优化和安全性考虑至关重要。性能优化可以提高服务器的响应速度和资源利用率,而安全性考虑可以防止恶意攻击和数据泄露。

性能优化技巧

优化内存使用

  1. 合理分配内存:避免不必要的内存分配和释放,使用智能指针(如std::unique_ptrstd::shared_ptr)管理内存。
  2. 重用资源:对于可重用的资源,如数据库连接和文件句柄,应尽量重用而不是每次都创建新的资源。

减少网络延迟

  1. 合理的数据封装:减少传输的数据量,使用更高效的编码方式压缩数据。
  2. 异步处理:使用异步处理技术,如多线程或多进程,提高并发处理能力。
  3. 连接池:对于频繁的网络连接,使用连接池来减少连接建立和关闭的开销。

优化算法和数据结构

  1. 高效算法:选择适合应用场景的高效算法,避免不必要的计算。
  2. 合理选择数据结构:根据数据的访问模式选择合适的数据结构,提高数据处理效率。

缓存策略

  1. 内存缓存:使用内存缓存存储频繁访问的数据,减少对存储系统的访问。
  2. 分布式缓存:在分布式系统中使用分布式缓存,提高数据访问速度。
安全性考虑与实现

防止SQL注入攻击

  1. 参数化查询:使用参数化查询,避免直接拼接SQL语句。
  2. 输入验证:对输入数据进行严格的验证和清洗,避免非法输入。

防止XSS攻击

  1. 内容过滤:对输出的内容进行过滤,防止恶意脚本注入。
  2. HTTPS加密:使用HTTPS加密传输数据,防止数据在传输过程中被拦截。

防止CSRF攻击

  1. CSRF令牌:在每个请求中加入CSRF令牌,验证请求的有效性。
  2. Same-Origin策略:使用Same-Origin策略限制跨域请求。

数据加密

  1. 传输加密:使用SSL/TLS加密传输数据,防止数据在传输过程中被窃听。
  2. 存储加密:对敏感数据进行加密存储,防止数据泄露。

安全审计

  1. 日志记录:记录重要的操作和事件,便于审计和回溯。
  2. 安全扫描:定期进行安全扫描,发现并修复潜在的安全漏洞。

代码审查

  1. 代码审查:进行代码审查,确保代码质量,避免引入安全漏洞。
  2. 安全培训:为开发人员提供定期的安全培训,提高安全意识。

示例代码

以下是几个简单的示例代码,展示如何实现上述安全性和性能优化技术:

参数化查询示例

使用参数化查询避免SQL注入攻击:

#include <iostream>
#include <mysql.h>

void execute_query(MYSQL *conn) {
    MYSQL_STMT *stmt;
    MYSQL_BIND params[1];

    // 初始化连接
    stmt = mysql_stmt_init(conn);
    std::string query = "SELECT * FROM users WHERE id = ?";
    mysql_stmt_prepare(stmt, query.c_str(), query.length());

    // 准备参数
    params[0].buffer_type = MYSQL_TYPE_LONG;
    params[0].buffer = (void *)&user_id;
    params[0].length = &length;

    // 执行查询
    mysql_stmt_execute(stmt);
    mysql_stmt_bind_result(stmt, params);
    mysql_stmt_store_result(stmt);
    mysql_stmt_fetch(stmt);
}

内存缓存示例

使用内存缓存提高数据访问速度:

#include <iostream>
#include <unordered_map>
#include <mutex>

std::unordered_map<int, std::string> cache;
std::mutex cache_mutex;

std::string get_data(int id) {
    std::lock_guard<std::mutex> lock(cache_mutex);
    if (cache.find(id) != cache.end()) {
        return cache[id];
    }

    // 从数据库获取数据
    std::string data = fetch_data_from_db(id);
    cache[id] = data;
    return data;
}

HTTPS加密示例

使用HTTPS加密传输数据:

#include <iostream>
#include <boost/beast.hpp>
#include <boost/asio.hpp>

namespace net = boost::asio;
namespace http = boost::beast::http;

void start_https_server() {
    net::io_context ioc;
    http::tcp::endpoint ep{net::ip::make_address("0.0.0.0"), 443};
    http::tcp::acceptor acceptor{ioc, ep};
    http::ssl_stream<http::tcp::socket> stream{ioc};

    net::ssl::context ctx{net::ssl::context::tlsv12};
    ctx.load_root_certificate("server.pem");
    ctx.use_private_key("server.key", net::ssl::context::pem);

    stream.set_verify_mode(net::ssl::verify_peer);
    stream.set_verify_callback(net::ssl::host_name_verification("example.com"));
    stream.set_verify_depth(5);
    stream.handshake(net::ssl::stream_base::server);

    acceptor.accept(stream.lowest_layer());
    stream.async_handshake(net::ssl::stream_base::server, [](boost::system::error_code ec) {
        if (!ec) {
            std::cout << "Handshake successful" << std::endl;
        }
    });
}

通过以上示例代码,可以更好地理解如何在实际应用中实现性能优化和安全性考虑,提高服务器的可靠性和安全性。

常见问题与调试技巧

在开发C++11服务器时,经常会遇到各种问题,如编译错误、运行时崩溃等。本节将介绍一些常见的错误及其解决方案,并推荐一些调试工具。

常见错误及解决方案

编译错误

  • 未定义的函数/变量:确保所有函数和变量的声明都在使用前进行。
  • 不兼容的数据类型:检查数据类型的兼容性,确保函数参数和返回值类型正确。
  • 缺失的头文件包含:确保所有需要的头文件都被正确包含。

运行时错误

  • 内存泄漏:使用工具检测内存泄漏,如Valgrind。
  • 访问非法内存:确保所有内存访问都是安全的,避免越界访问。
  • 死锁:检查线程之间是否发生死锁,确保线程同步正确。

网络错误

  • 端口冲突:确保服务器监听的端口没有被其他程序占用。
  • 连接超时:增加连接超时时间,确保连接能正常建立。
  • 数据包丢失:检查网络连接,确保数据包能正常传输。

调试工具推荐

GDB

GDB(GNU调试器)是一个强大的调试工具,可以用于调试C++程序。

g++ -g -o server server.cpp
gdb ./server

在GDB中可以使用以下命令:

  • break:设置断点。
  • run:开始运行程序。
  • continue:继续执行程序直到下一个断点。
  • step:单步执行直到下一个语句。
  • print:打印变量的值。
  • backtrace:显示当前调用堆栈。

Valgrind

Valgrind是一个内存调试工具,可以检测内存泄漏、内存访问错误等。

g++ -g -o server server.cpp
valgrind ./server

Valgrind会输出详细的错误信息,帮助你定位和修复内存问题。

Wireshark

Wireshark是一个网络协议分析器,可以捕获和分析网络数据包。

sudo apt-get install wireshark
sudo wireshark

Wireshark可以帮助你捕获和分析网络通信,检查数据包的传输情况。

示例代码

以下是一个简单的C++11服务器代码,展示一些调试技巧:

#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <mutex>

std::mutex mtx;

void handle_client(int client_sock) {
    char buffer[1024];
    int bytes_received;

    while (true) {
        bytes_received = recv(client_sock, buffer, 1024, 0);
        if (bytes_received <= 0) break;

        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "Received message: " << buffer << std::endl;

        std::string response = "Message received: " + std::string(buffer);
        send(client_sock, response.c_str(), response.size(), 0);
    }

    close(client_sock);
}

int main() {
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock < 0) {
        std::cerr << "Failed to create socket" << std::endl;
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        std::cerr << "Failed to bind" << std::endl;
        return 1;
    }

    if (listen(server_sock, 5) < 0) {
        std::cerr << "Failed to listen" << std::endl;
        return 1;
    }

    std::cout << "Server listening on port 12345" << std::endl;

    while (true) {
        int client_sock = accept(server_sock, nullptr, nullptr);
        if (client_sock < 0) {
            std::cerr << "Failed to accept client" << std::endl;
            continue;
        }

        std::cout << "New client connected" << std::endl;
        std::thread handler(handle_client, client_sock);
        handler.detach();
    }

    close(server_sock);
    return 0;
}

调试步骤

  1. 编译带调试信息的程序
    g++ -g -o server server.cpp
  2. 使用GDB调试程序
    gdb ./server
  3. 设置断点并运行程序
    (gdb) break handle_client
    (gdb) run
  4. 单步执行并查看变量值
    (gdb) step
    (gdb) print bytes_received

通过以上调试步骤,可以更好地定位和解决程序中的问题。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消