当前位置: 首页 > article >正文

C++网络编程之Socket

1.介绍

        在C++网络编程中,Socket是实现网络通信的核心工具,C++本身并没有直接提供socket接口,而是通过操作系统提供的Berkeley Socket API 来实现网络通信。下面将详细介绍一下如何用C++进行socket编程。

2.socket的基本概念

        socket是网络通信的端点,包含IP地址和端口号,用于标识通信的双方。通过socket,应用程序可以发送和接收数据。

        socket的类型主要有三种:

        1.流式socket(sock_stream):基于TCP,提供可靠的、面向连接的通信,确保数据顺序和完整性。

        2.数据报socket(sock_dgram):基于UDP,提供无连接的通信,速度快但不保证可靠性。

        3.原始socket(sock_raw):允许直接访问底层协议(IP、ICMP),通常用于开发自定义协议。

3.socket的基本工作流程

        (1)服务器端

        1.创建socket:使用socket()函数创建一个socket。

        2.绑定地址:使用bind()将socket绑定到指定的IP地址和端口。

        3.监听连接:使用listen()开始监听客户端连接。

        4.结构连接:使用accept()接收客户端的连接请求。

        5.数据交换:使用recv()和send()进行数据收发。

        6.关闭socket:使用close()关闭连接。

        (2)客户端

        1.创建socket:使用socket()函数创建一个socket。

        2.连接服务器:使用connect()连接到服务器。

        3.数据交换:使用recv()和send()进行数据收发。

        4.关闭socket:使用close()关闭连接。

4.C++socket编程示例

        (1)服务器端代码

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    // 创建 Socket
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        std::cerr << "无法创建 Socket\n";
        return 1;
    }

    // 绑定地址
    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口
    server_addr.sin_port = htons(12345);      // 监听端口 12345

    if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) {
        std::cerr << "绑定失败\n";
        close(server_socket);
        return 1;
    }

    // 监听连接
    if (listen(server_socket, 5) == -1) {
        std::cerr << "监听失败\n";
        close(server_socket);
        return 1;
    }

    std::cout << "服务器正在监听端口 12345...\n";

    // 接受连接
    sockaddr_in client_addr{};
    socklen_t client_addr_len = sizeof(client_addr);
    int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
    if (client_socket == -1) {
        std::cerr << "接受连接失败\n";
        close(server_socket);
        return 1;
    }

    std::cout << "客户端已连接\n";

    // 接收数据
    char buffer[1024];
    int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
    if (bytes_received == -1) {
        std::cerr << "接收数据失败\n";
    } else {
        buffer[bytes_received] = '\0';
        std::cout << "收到数据: " << buffer << std::endl;
    }

    // 发送数据
    const char* response = "你好,客户端!";
    send(client_socket, response, strlen(response), 0);

    // 关闭 Socket
    close(client_socket);
    close(server_socket);

    return 0;
}

        (2)客户端代码

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    // 创建 Socket
    int client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket == -1) {
        std::cerr << "无法创建 Socket\n";
        return 1;
    }

    // 连接服务器
    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(12345); // 服务器端口
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // 服务器 IP 地址

    if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) {
        std::cerr << "连接服务器失败\n";
        close(client_socket);
        return 1;
    }

    std::cout << "已连接到服务器\n";

    // 发送数据
    const char* message = "你好,服务器!";
    send(client_socket, message, strlen(message), 0);

    // 接收数据
    char buffer[1024];
    int bytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
    if (bytes_received == -1) {
        std::cerr << "接收数据失败\n";
    } else {
        buffer[bytes_received] = '\0';
        std::cout << "收到数据: " << buffer << std::endl;
    }

    // 关闭 Socket
    close(client_socket);

    return 0;
}
5.一些关键问题

        (1)地址结构

        sockaddr_in是IPv4的地址结构,包含IP地址和端口号。

        inet_pton()是将字符串形式的IP地址转换为二进制形式。

        (2)字节序转换

        htons()和htonl()用于将主机字节序转换为网络字节序。

        ntos()和ntohl()用于将网络字节序转换为主机字节序。

        (3)错误处理

        每个函数掉用户都应该检查返回值,确保操作成功。

        (4)多客户端支持

        服务器端可以使用多线程或多进程处理多个客户端连接。

6.其他常见问题

        (1)socket阻塞和非阻塞

        默认情况下socket是阻塞的,可以使用fcntl()或ioctl()设置为非阻塞模式。

        (2)地址重用

        使用setsockopt()设置SO_REUSEADDR选项,允许地址重用。

        (3)超时设置

        使用setsockopt()设置SO_RCVTIMEO和SO_SNDTIMEO选项,设置接收和发送的超时时间。

7.总结

        Socket 是网络编程的核心工具,掌握其基本概念和工作流程对于开发网络应用至关重要。

如有错误,敬请指正!!!


http://www.kler.cn/a/571206.html

相关文章:

  • 二分题目leetcode
  • 二百八十五、华为云PostgreSQL——建分区表并设置主键
  • 10.LED点阵实验
  • 安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露
  • Google chrome拦截某些下载内容
  • 基于EM期望最大化算法的GMM参数估计与三维数据分类系统python源码
  • 软件架构设计7大原则
  • ESP32之Flash操作
  • 11、HTTPS和HTTP有哪些区别【高频】
  • SSM开发(十四) Spring之IOC
  • 大模型——CogView4:生成中英双语高清图片的开源文生图模型综合介绍
  • DeepSeek vs Grok vs ChatGPT:大模型三强争霸,谁将引领AI未来?
  • Web⾃动化测试及常用函数
  • pnpm+monorepo实现前端公共函数、组件库
  • 芯麦 GC1272 芯片:电脑散热风扇领域的高效替代之选,对比 APX9172/茂达芯片优势解析
  • Linux基础 -- ARM 32位常用机器码(指令)整理
  • Deepseek的底层架构思维构成
  • 面试-----每日一题
  • android13打基础: 接收自定义广播并在接收到广播时触发设备震动
  • 3月4日C高级