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 是网络编程的核心工具,掌握其基本概念和工作流程对于开发网络应用至关重要。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值