vs2022 cmake 的 socket 程序 demo 模拟最简单 web 处理(windows/linux 兼容)

文章介绍了如何使用CMake来创建一个兼容Windows和Linux的小型Web服务器程序,通过socket实现基本的HTTP响应。作者分享了遇到的兼容性问题及解决方法,包括头文件、函数和类型的差异,并提供了源代码链接供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一次使用 cmake,做一个兼容 windows/linux 的小程序,使用 socket 模拟简单的 web 处理

为了兼容编译,遇到不少坑,终于完成了。代码现在放出来给大家参考。

https://e.coding.net/greenery2/demowebapp/demowebapp.git

使用效果截图:

┌─[yhen1@devops]─[~/.vs/CDemoWebApp/out/build/linux-debug]
└──╼ $./CDemoWebApp 8888
Demo web app. port: 8888
socket init: 3
=====================================================
waiting accept [8888]...
^CExit...
closesocket: 3 ...
┌─[yhen1@devops]─[~]
└──╼ $curl -vv 127.0.0.1:8888
* About to connect() to 127.0.0.1 port 8888 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8888 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8888
> Accept: */*
>
< HTTP/1.1 200 OK
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0
OK

CMakeLists.txt

# CMakeList.txt: CDemoWebApp 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)

# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
  cmake_policy(SET CMP0141 NEW)
  set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()

project ("CDemoWebApp")

# 将源代码添加到此项目的可执行文件。
add_executable (CDemoWebApp "CDemoWebApp.cpp" "CDemoWebApp.h")

if (CMAKE_VERSION VERSION_GREATER 3.12)
  set_property(TARGET CDemoWebApp PROPERTY CXX_STANDARD 20)
endif()

# TODO: 如有需要,请添加测试并安装目标。

if(WIN32)
  target_link_libraries(CDemoWebApp wsock32 ws2_32)
endif()

CDemoWebApp.cpp

// CDemoWebApp.cpp: 定义应用程序的入口点。
//

#include "CDemoWebApp.h"
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>

#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#define socklen_t int
#else
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define closesocket close
#define SOCKET int
#endif
#include <fcntl.h>
#include <errno.h>
#include <signal.h>



#define QUEUE 20  //连接请求队列
const char* DEFAULT_HTTP_RESPONE = "HTTP/1.1 200 OK\r\n\r\nOK";

using namespace std;
SOCKET sockfd, connfd;    // 定义服务端套接字和客户端套接字
bool appExitFlag = false;
void SigCatch(int sigNum)	//信号捕捉函数(捕获Ctrl+C)
{
    printf("Exit...\n");
    if (sockfd != -1)
    {
        appExitFlag = true;
        closesocket(sockfd);
        printf("closesocket: %d ...\n", sockfd);
        sockfd = -1;
    }
    exit(0);
}

int main(int argc, char** argv)
{
    char buffer[1024 * 8];

    u_short port = 80;
    if (argc >= 2) {
        port = atoi(argv[1]);
        if (port < 80) port = 80;
    }
    printf("Demo web app. port: %d\n", port);
    signal(SIGINT, SigCatch);	//注册信号捕获函数

    //printf("AF_INET: %d\n", AF_INET);  //IPv4协议
    //printf("SOCK_STREAM: %d\n", SOCK_STREAM); //字节流套接字
#ifdef WIN32
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
    sockfd = socket(AF_INET, SOCK_STREAM, 0);  //若成功则返回一个sockfd (套接字描述符)
    printf("socket init: %d\n", sockfd);
    struct sockaddr_in server_sockaddr;  //一般是储存地址和端口,用于信息的显示及存储作用

    //下面设置sockaddr_in 结构体中相关参数
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(port); //将一个无符号短整型数值转换为网络字节序,即大端模式
    //printf("INADDR_ANY: %d\n", INADDR_ANY);
    //INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或"所有地址"、“任意地址”。
    //一般来说,在各个系统中均定义成为0值。
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);  //将主机无符号长整型数转换成网络字节顺序。

    if (bind(sockfd, (struct sockaddr*)&server_sockaddr, sizeof(server_sockaddr)) == -1)
    {
        perror("bind error!\n");
        exit(1);
    }

    if (listen(sockfd, QUEUE) == -1)
    {
        perror("listen error!\n");
        exit(1);
    }

    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);

    while (1) {
        printf("=====================================================\n");
        printf("waiting accept [%d]...\n", port);

        //成功返回非负描述字,出错返回-1
        int conn = accept(sockfd, (struct sockaddr*)&client_addr, &length);
        //如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接
        //accept之后就会用新的套接字conn
        if (conn < 0)
        {
            // 如果正在退出系统,那么就不用打印错误
            if (appExitFlag) break;

            perror("connect error!\n");
            exit(1);
        }
        printf("accept ok: %d...\n", conn);

        memset(buffer, 0, sizeof(buffer));
        int len = recv(conn, buffer, sizeof(buffer), 0);   //从TCP连接的另一端接收数据。
        /*该函数的第一个参数指定接收端套接字描述符;
        第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
        第三个参数指明buf的长度;
        第四个参数一般置0*/

        printf("%s", buffer);//如果有收到数据则输出数据
        // 返回默认 http respone
        int ret = send(conn, DEFAULT_HTTP_RESPONE, strlen(DEFAULT_HTTP_RESPONE), 0);//向TCP连接的另一端发送数据。
        printf("respone: [%d]\n%s\n", ret, DEFAULT_HTTP_RESPONE);
        closesocket(conn);   //因为accept函数连接成功后还会生成一个新的套接字描述符,结束后也需要关闭
        printf("close connect: %d\n", conn);
    }
    closesocket(sockfd);     //关闭socket套接字描述符

	return 0;
}

注意事项

头文件不一样

windows的和linux的不一样。我用宏判断分别导入不同的头文件

#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif

注意,windows下面要先 include <winsock2.h> 再 include <windows.h>,否则会出现很多重复定义的错误

部分函数、类型不一样

windows的和linux的不一样。我简单统一了一下

#ifdef WIN32
#define socklen_t int
#else
#define closesocket close
#define SOCKET int
#endif

windows 下面socket要加lib

我写在 CMakeLists.txt,通过宏判断,进行lib导入

target_link_libraries(CDemoWebApp wsock32 ws2_32)

windows 下面socket要初始化

#ifdef WIN32
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

<think>我们正在使用CMake配置一个跨平台(WindowsLinux、macOS)的Qt6项目。根据引用[1],Qt6已经全面转向CMake作为构建系统,这为跨平台开发提供了便利。以下将详细说明配置步骤和注意事项。 ### 跨平台CMake配置Qt6项目的关键步骤 #### 1. **环境准备** - **Windows**: 安装Qt for Windows(如使用在线安装器选择MSVC或MinGW版本)和对应CMake。注意:如果使用MSVC,需要安装Visual Studio;若使用MinGW,则需安装MinGW并配置环境变量。 - **Linux**: 通过包管理器安装Qt6和CMake(如Ubuntu: `sudo apt install qt6-base-dev cmake`)。 - **macOS**: 使用Homebrew安装:`brew install qt cmake` 或从Qt官网下载安装包[^3]。 验证安装: ```bash cmake --version # 要求3.16+ qmake --version # 应为Qt6版本 ``` #### 2. **项目结构(示例)** ``` MyApp/ ├── CMakeLists.txt ├── src/ │ ├── main.cpp │ └── mainwindow.cpp ├── include/ │ └── mainwindow.h └── resources/ └── icons.qrc ``` #### 3. **核心CMakeLists.txt配置(跨平台关键点)** ```cmake cmake_minimum_required(VERSION 3.16) project(MyApp VERSION 1.0 LANGUAGES CXX) # 设置C++标准(Qt6要求C++17) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 自动处理Qt的元对象编译(moc)、资源(rcc)和界面(uic) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # 根据平台设置输出路径(可选) if(WIN32) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) else() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() # 查找Qt6组件(跨平台通用) find_package(Qt6 REQUIRED COMPONENTS Core Widgets) # 按需添加模块 # 添加可执行文件 add_executable(MyApp src/main.cpp src/mainwindow.cpp include/mainwindow.h resources/icons.qrc # 资源文件直接加入 ) # 链接Qt库 target_link_libraries(MyApp PRIVATE Qt6::Core Qt6::Widgets ) # 包含头文件目录 target_include_directories(MyApp PRIVATE include) ``` #### 4. **跨平台构建命令** - **Windows (MSVC)**: ```powershell cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_PREFIX_PATH="C:/Qt/6.4.0/msvc2019_64/lib/cmake" .. cmake --build . --config Release ``` - **Windows (MinGW)**: ```bash cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH="C:/Qt/6.4.0/mingw_64/lib/cmake" .. cmake --build . ``` - **Linux/macOS**: ```bash cmake .. -DCMAKE_PREFIX_PATH="/opt/Qt/6.4.0/gcc_64/lib/cmake" # Linux示例路径 # macOS若使用Homebrew安装的Qt,路径通常为:/usr/local/opt/qt/lib/cmake cmake --build . ``` #### 5. **跨平台注意事项** 1. **路径分隔符**: CMake中路径使用`/`(正斜杠)可跨平台兼容,避免使用`\`。 2. **动态库加载**: - Windows:运行时需将Qt的`bin`目录加入`PATH`(或复制dll到可执行文件目录)。 - macOS:使用`macdeployqt`打包.app时自动处理依赖。 - Linux:确保LD_LIBRARY_PATH包含Qt库路径,或使用rpath设置: ```cmake set(CMAKE_INSTALL_RPATH "$ORIGIN") ``` 3. **资源文件路径**: 在代码中访问资源文件(如图标)时,使用`:/`前缀(如`QIcon(":/icon.png")`),CMake通过`qt_add_resources`(或直接包含.qrc)自动处理。 4. **平台特定代码**: 如需平台相关代码,使用CMake条件判断: ```cmake if(WIN32) target_sources(MyApp PRIVATE windows_utils.cpp) elseif(APPLE) target_sources(MyApp PRIVATE mac_utils.mm) # .mm为Objective-C++文件 endif() ``` #### 6. **部署工具** - **Windows**:使用`windeployqt`(位于`<Qt路径>/bin`)自动复制依赖库。 - **macOS**:使用`macdeployqt`打包.app。 - **Linux**:可编写安装脚本,或使用`linuxdeployqt`。 ### 常见问题解决 - **CMake找不到Qt6**: 通过`-DCMAKE_PREFIX_PATH`显式指定Qt的CMake目录(如`/opt/Qt/6.4.0/gcc_64/lib/cmake`)。此路径下应包含`Qt6Config.cmake`[^2]。 - **macOS权限问题**: 若使用Homebrew安装Qt,确保CMake有权限读取Qt目录。可尝试: ```bash sudo chmod -R a+r /usr/local/opt/qt ``` - **Linux缺少OpenGL库**: 安装开发包:Ubuntu下`sudo apt install libgl1-mesa-dev`。 ### 进阶配置 - **添加翻译文件**: 使用`qt_add_translations`目标: ```cmake qt_add_translations(MyApp TS_FILES translations/app_zh_CN.ts translations/app_fr_FR.ts ) ``` - **Qt Quick应用**: 引入`Quick`组件并启用QML模块: ```cmake find_package(Qt6 REQUIRED COMPONENTS Quick) target_link_libraries(MyApp PRIVATE Qt6::Quick) ``` ### 总结 通过CMake配置Qt6项目可实现无缝跨平台编译,关键在于: 1. 正确设置`CMAKE_PREFIX_PATH`指向Qt安装路径。 2. 使用`find_package`加载所需Qt模块。 3. 启用`AUTOMOC`、`AUTORCC`、`AUTOUIC`简化元编译流程。 4. 遵循平台特定的构建和部署规则。 > 提示:更多跨平台细节参考Qt官方文档[^1]。 --- ### 相关问题 1. 如何在CMake项目中为Qt6应用程序添加国际化支持(多语言翻译)? 2. 如何配置CMake以在Qt6项目中同时使用Qt Widgets和Qt Quick? 3. 在Windows上使用MinGW构建Qt6项目时遇到链接错误如何解决? 4. macOS下如何将Qt6应用打包为.dmg安装文件? 5. Linux下如何解决Qt6程序运行时找不到动态库的问题? [^1]: 全面剖析Qt6新版构建系统CMake [^2]: ubuntu 使用 CMake 构建 Qt5 项目 [^3]: 尝试mac下编译qt 6.4.3</think>### 使用CMake配置Qt6实现跨平台编译(Windows/Linux/macOS) 以下是完整的跨平台配置指南,已整合引用内容的关键信息: #### 1. **基础CMake配置(跨平台核心)** ```cmake cmake_minimum_required(VERSION 3.18) # Qt6要求最低3.16,推荐3.18+[^1][^3] project(MyQtApp VERSION 1.0 LANGUAGES CXX) # 设置C++标准(Qt6需要C++17) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 启用Qt自动处理(关键跨平台特性) set(CMAKE_AUTOMOC ON) # 自动运行moc set(CMAKE_AUTORCC ON) # 自动处理资源文件 set(CMAKE_AUTOUIC ON) # 自动运行uic[^2] # 查找Qt6组件(跨平台通用) find_package(Qt6 REQUIRED COMPONENTS Core Widgets) ``` #### 2. **平台特定处理** ```cmake # Windows特殊配置 if(WIN32) # 设置MSVC运行时库(避免MT/MTd冲突) if(MSVC) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") endif() # 资源文件路径处理 set(QT_RESOURCES_PREFIX "/resources") endif() # macOS特殊配置 if(APPLE) # 设置Bundle标识符 set(MACOSX_BUNDLE_BUNDLE_NAME "MyQtApp") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.example.myapp") # 解决macOS权限问题 set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks") endif() # Linux特殊配置 if(UNIX AND NOT APPLE) # 设置安装路径 set(CMAKE_INSTALL_PREFIX "/usr/local") endif() ``` #### 3. **可执行文件配置** ```cmake # 添加可执行文件(跨平台) add_executable(MyQtApp src/main.cpp src/MainWindow.cpp include/MainWindow.h resources/app.qrc # 资源文件直接包含 ) # 链接Qt库(跨平台通用) target_link_libraries(MyQtApp PRIVATE Qt6::Core Qt6::Widgets ) # 包含头文件目录 target_include_directories(MyQtApp PRIVATE include) ``` #### 4. **跨平台构建命令** ```bash # 通用生成命令(各平台通用) cmake -B build -DCMAKE_PREFIX_PATH="<Qt安装路径>/lib/cmake" # 平台特定生成器(按需选择) # Windows (MSVC): cmake -B build -G "Visual Studio 17 2022" -A x64 # Windows (MinGW): cmake -B build -G "MinGW Makefiles" # Linux/macOS: cmake -B build # 编译命令(跨平台通用) cmake --build build ``` #### 5. **关键跨平台技巧 1. **Qt路径配置**: - 使用`-DCMAKE_PREFIX_PATH`指定Qt安装路径: ```bash # Windows示例 -DCMAKE_PREFIX_PATH="C:/Qt/6.4.0/msvc2019_64/lib/cmake" # macOS (Homebrew) -DCMAKE_PREFIX_PATH="/opt/homebrew/opt/qt/lib/cmake" # Linux -DCMAKE_PREFIX_PATH="/opt/Qt/6.4.0/gcc_64/lib/cmake" ``` 2. **资源文件处理**: ```cmake # 跨平台资源路径处理 qt_add_resources(MyQtApp "app_resources" PREFIX ":/" FILES resources/icons/app_icon.png resources/styles/style.css ) ``` 3. **依赖管理**: - Windows:使用`windeployqt`打包依赖 - macOS:使用`macdeployqt`打包.app - Linux:使用`linuxdeployqt`或设置RPATH #### 6. **完整示例结构 ``` MyQtApp/ ├── CMakeLists.txt # 主配置文件 ├── src/ │ ├── main.cpp # 主入口 │ └── MainWindow.cpp # 业务逻辑 ├── include/ │ └── MainWindow.h # 头文件 ├── resources/ │ ├── app.qrc # 资源文件 │ └── icons/ # 图标资源 └── CMakePresets.json # 跨平台预设(可选) ``` #### 7. **验证与调试 ```cmake # 添加跨平台验证目标 add_custom_target(verify-qt6 COMMAND ${Qt6_DIR}/Qt6Config.cmake --version COMMENT "验证Qt6配置: ${Qt6_DIR}" ) ``` > 提示:根据Qt官方说明,迁移到CMake的主要目标是简化跨平台集成[^1]。在macOS编译需注意安装C++17兼容编译器和Python依赖[^3]。 --- ### 相关问题 1. 如何在CMake中为Qt6项目配置多语言翻译文件(.ts)? 2. Windows平台使用MinGW构建Qt6时如何解决链接错误? 3. macOS下如何将Qt6应用打包为.dmg安装文件? 4. 如何在CMake中配置Qt6和Qt5的兼容模式? 5. Linux下如何解决Qt6程序运行时找不到动态库的问题? [^1]: 全面剖析Qt6新版构建系统CMake [^2]: ubuntu 使用 CMake 构建 Qt5 项目 [^3]: 尝试mac下编译qt 6.4.3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值