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

C++ 之 SOCKET 通信详解

C++ 之 SOCKET 通信详解

  • SOCKET中首先我们要理解如下几个定义概念:

    • 一是IP地址:IP Address, 就是依照TCP/IP协议分配给本地主机的网络地址, 比如两个进程要通讯,任一进程要知道通讯对方的位置,就用对方的IP。
    • 二是端口号: 用来标识本地通讯进程,方便OS提交数据.就是说进程指定了对方进程的网络IP,但这个IP只是用来标识进程所在的主机,如何来找到运行在这个主机的这个进程呢,就用端口号。
    • 三是连接: 指两个进程间的通讯链路
    • 四是半相关: 网络中用一个三元组可以在全局唯一标志一个进程:(协议,本地地址,本地端口号)
    • 五是全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:(协议,本地地址,本地端口号,远地地址,远地端口号)
  • 运行模式:

    • 在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器模式(Client/Server model),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务。
    • 客户/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是客户/服务器模式的TCP/IP。
  • 下面详细总结一下 SOCKET 相关原理

1. SOCKET 基础

  • Socket 是计算机网络中的端点,客户端和服务器通过Socket进行通信。每个Socket都是由操作系统提供的一个API,它封装了网络协议栈的各种细节,程序通过调用Socket相关函数来完成数据的发送和接收。

  • Socket的类型在网络编程中,主要有两种Socket类型:

    • TCP Socket (SOCK_STREAM):面向连接的可靠通信。数据以流的形式传输,适用于要求可靠性、顺序传输的应用(如HTTP、FTP等)。
    • UDP Socket (SOCK_DGRAM):无连接的、不可靠的通信方式。数据报文独立发送,不保证顺序、可靠性,适用于对实时性要求较高但对丢包可以容忍的场景(如DNS、视频流、实时游戏等)。
  • Socket是网络通信端点,TCP协议提供可靠连接(类似打电话),UDP协议提供无连接服务(类似发短信)。TCP服务端与客户端通信流程如下:
    在这里插入图片描述

2. 编程步骤

1. 创建Socket

  • 首先需要调用 socket() 函数来创建一个Socket。socket() 函数的原型如下:
int socket(int domain, int type, int protocol);

domain:指定协议族,通常是 AF_INET(IPv4)或者 AF_INET6(IPv6)。
type:指定Socket的类型,通常为 SOCK_STREAM(TCP)或者 SOCK_DGRAM(UDP)。
protocol:指定使用的协议,一般可以设置为0,操作系统会自动选择合适的协议。

  • 例如,创建一个TCP Socket:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
    perror("socket creation failed");
    exit(1);
}

2. 绑定Socket(bind)

  • 创建Socket之后,需要将其与特定的地址(IP地址和端口)绑定。这一步骤通常在服务器端进行,以便监听某个特定的端口。使用 bind() 函数绑定Socket
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;  // 监听所有的网络接口
server_addr.sin_port = htons(8080);        // 设置端口号

if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
    perror("bind failed");
    exit(1);
}

3. 监听Socket(listen) & 接受连接(accept)

  • 对于TCP连接,服务器端需要监听并等待客户端的连接请求。可以使用 listen()accept() 函数来实现:
if (listen(sockfd, 5) < 0) {
    perror("listen failed");
    exit(1);
}

int new_sock = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (new_sock < 0) {
    perror("accept failed");
    exit(1);
}

4. 连接到服务器(connect)

  • 客户端通过 connect() 函数与服务器建立连接。它需要指定服务器的IP地址和端口:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
    perror("connect failed");
    exit(1);
}

5. 数据发送与接收(send/recv)

  • 在连接建立之后,客户端和服务器就可以通过 send()recv() 函数进行数据传输。对于UDP,使用 sendto()recvfrom()

    • send():将数据发送到Socket。
    • recv():从Socket接收数据。
char message[] = "Hello, World!";
if (send(new_sock, message, sizeof(message), 0) < 0) {
    perror("send failed");
    exit(1);
}

char buffer[1024];
int n = recv(new_sock, buffer, sizeof(buffer), 0);
if (n < 0) {
    perror("recv failed");
    exit(1);
}
buffer[n] = '\0';
printf("Received message: %s\n", buffer);

6. 关闭Socket(close)

  • 通信完成后,需要关闭Socket以释放资源:
close(sockfd);
close(new_sock);

3. 一个简单的C++ TCP服务器和客户端

  • 服务端
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>

int main() {
    int server_fd, new_sock;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);
    char buffer[1024];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("Socket creation failed");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);

    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        exit(1);
    }

    if (listen(server_fd, 5) < 0) {
        perror("Listen failed");
        exit(1);
    }

    std::cout << "Waiting for client connection..." << std::endl;
    new_sock = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);
    if (new_sock < 0) {
        perror("Accept failed");
        exit(1);
    }

    std::cout << "Client connected!" << std::endl;

    int n = recv(new_sock, buffer, sizeof(buffer), 0);
    if (n < 0) {
        perror("Receive failed");
        exit(1);
    }
    buffer[n] = '\0';
    std::cout << "Received: " << buffer << std::endl;

    close(new_sock);
    close(server_fd);
    return 0;
}

  • 客户端
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>

int main() {
    int sockfd;
    struct sockaddr_in server_addr;
    char message[] = "Hello from client!";

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("Socket creation failed");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Connection failed");
        exit(1);
    }

    if (send(sockfd, message, sizeof(message), 0) < 0) {
        perror("Send failed");
        exit(1);
    }

    close(sockfd);
    return 0;
}
http://www.dtcms.com/a/91875.html

相关文章:

  • “自动驾驶背后的数学” 专栏导读
  • 推陈换新系列————java8新特性(编程语言的文艺复兴)
  • 【现代深度学习技术】现代卷积神经网络04:含并行连接的网络(GoogLeNet)
  • 每日总结3.26
  • 算法题(108):
  • IM腾讯Trtc与vod云点播:实现合流录制并上传,根据参数返回视频地址
  • JSON简介及C++中的JSON使用指南
  • LangChain4j(1):初识LangChain4j
  • 【Linux】POSIX信号量与基于环形队列的生产消费者模型
  • ADS 学习和培训资源 - Keysight ADS
  • Netty——TCP 粘包/拆包问题
  • 信息系统运行管理员教程1--信息系统运维概述
  • 人员进出新视界:视觉分析算法的力量
  • MySQL入门级操作
  • Ubuntu服务器中Swapper如何与虚拟内存配合
  • 【八股】未知宽高元素水平垂直居中的三种方法
  • CNN基础考点
  • 【C++ Linux编程进阶 从0实现muduo库系列】第五讲:实现C++日志库
  • system V 消息队列信息量(了解)
  • 基于MoE架构的AIGC引擎:海螺AI重新定义人机协同新范式
  • 青柠视频云支持808协议和1078协议,支持SIP信令日志追踪
  • C++ queue容器总结
  • Android系统的安全问题 - Linux的能力模型(Capability)和 SELinux 的区别
  • MarkLogic索引详解
  • C++20 中的std::c8rtomb和 std::mbrtoc8
  • LangChain开发(六)多模态输入与自定义输出
  • 国外计算机证书推荐(考证)(6 Sigma、AWS、APICS、IIA、Microsoft、Oracle、PMI、Red Hat)
  • Vue 把 Echarts 图传给后端:文件流信息方式传递
  • BFS专项练习 —— 蓝桥杯刷题
  • Java基础 3.26