c++ socket基于TCP

linux网络编程基础api

  1. socket 地址api:ip地址和端口对,成为 soccket 地址。

  2. socket 基础api: sys/socket.h 中,包括创建、命名、监听 socket ;接受连接、发起连接、读写数据、获取地址信息、检测带外标记、读取设置 socket 选项

  3. 网络信息api:主机名和ip地址之间的转换、服务名称和端口号之间的转换。 netdb.h 中。

socket通信过程

  1. server端
    创建socket()->绑定地址和端口bind()->监听连接listen()->接受连接accept()->发送数据send()->关闭socket close()
  2. client
    创建socket()->IP地址转换inet_pton()->连接到服务端connect()->接收数据read()->关闭socket close()
  • TCP:可靠传输,三次握手建立连接,传出去一定接受的到(如聊天软件);

  • UDP:不可靠传输,不需要建立连接,只管发送,实时性好(如视频会议);

  • 套接字:表示通信的端点。就像用电话通信,套接字相当于电话,IP地址相当于总机号码,而端口号则相当于分机号码。

TCP:

 UDP:

socket地址

  1. 协议族和地址
    +=========+=========+==============+
    |     协议族     |     地址族    |          描   述          |
    +=========+=========+==============+
    |  PF_UNIX   |  AF_UNIX   |UNIX本地域协议族|
    +=========+=========+==============+
    |  PF_INET    |   AF_INET   |  TCP/IPv4协议族  |
    +=========+=========+==============+
    |  PF_INET6  |  AF_INET6 |  TCP/IPv6协议族   |
    +=========+=========+==============+

  2. tcp/ip 协议族有 sockaddr_in  和 sockaddr_in6两个专用socket地址结构体,分别用于ipv4和ipv6

// TCP/IPv4协议族
struct sockaddr_in {
    sa_family_t sin_family; /* 地址族 */
    in_port_t sin_port;  /* Port number.*/
    struct in_addr sin_addr; /*Internet address.  */
};

struct in_addr {
    in_addr_t s_addr;
};

// TCP/IPv6协议族
struct sockaddr_in6 {
    sa_family_t sin6_family; /* 地址族 */
    in_port_t sin6_port;	 /* Transport layer port # */
    uint32_t sin6_flowinfo;	 /* IPv6 flow information  = 0*/
    struct in6_addr sin6_addr;	/* IPv6 address */
    uint32_t sin6_scope_id;	 /* IPv6 scope-id */
};

struct in6_addr {
    unsigned charsa_addr[16]; /* IPv6要用网络字节序表示 */
};

ip转换函数

  1. 将点分十进制的 IPv4 地址转换为网络字节序整数表示的 IPv4 地址,是为了方便在网络通信中使用。整数形式的 IP 地址更容易存储、传输和比较。

  2. “192.168.1.1” 转换为010101···的值

# include <arpa/inet.h>

in_addr_t inet_addr( const char* strptr);   //将点分十进制的ipv4转化为网络字节序整数表示的ipv4

int inet_aton(const char * cp, struct in_addr* inp); //与上功能相同,但是转化结果存储与参数imp的地址结构中。返回1或0 表示成功或失败。

char* inet_ntoa( struct in_addr in );   //将网络字节序整数转化为点分十进制ipv4,该函数内部用一个静态变量存储静态结果,因此是不可重入的。

创建socket

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

int server_fd = socket(AF_INET, SOCK_STREAM, 0);
  • domain:指定要使用的协议族,常用的有 AF_INET(IPv4 地址族)和 AF_INET6(IPv6 地址族)。

  • type:指定套接字的类型,常用的有 SOCK_STREAM(流套接字,用于 TCP)和 SOCK_DGRAM(数据报套接字,用于 UDP)。

  • protocol:指定要使用的协议,通常为 0,表示使用默认协议。

  • 返回值:成功创建返回 0,失败返回 -1。

函数作用:socket 函数用于创建一个套接字(socket),并返回一个文件描述符,该描述符可以用于后续的套接字操作,如绑定地址、监听连接、发送和接收数据等。

绑定地址和端口

    struct sockaddr_in address;
    address.sin_family = AF_INET;     // TCP/IPv4   AF_INET6:TCP/IPv6
    address.sin_addr.s_addr = INADDR_ANY; // 地址
    address.sin_port = htons(8080); // 端口号

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) == -1) {
        std::cerr << "Error: Failed to bind\n";
        return 1;
    }
  1. int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:要绑定地址的套接字文件描述符。

  • addr:要绑定的地址信息,通常是一个 struct sockaddr 结构体指针,需要进行类型转换。

  • addrlen:地址信息的长度。

  • 返回值:成功绑定返回 0,失败返回 -1。

函数作用:bind 函数将一个套接字绑定到一个地址,使得该套接字可以在网络中被标识。对于服务器程序来说,通常在调用 bind 后还需要调用 listen 函数开始监听连接。对于客户端程序来说,通常不需要显式调用 bind 函数。

监听连接

    int listen(int sockfd, int backlog);

    if (listen(server_fd, 3) == -1) {
        std::cerr << "Error: Failed to listen\n";
        return 1;
    }
  • sockfd:套接字文件描述符,即要监听的套接字。
  • backlog:指定在拒绝新连接之前,操作系统可以挂起的最大连接数。
  • 返回值:成功返回 0,失败返回 -1。

函数作用:listen 函数将指定的套接字设置为监听状态,使其可以接受连接。backlog 参数指定操作系统可以挂起的最大连接数,超过这个数目的连接将被拒绝。通常在服务器端使用,用于开始接受客户端的连接请求。

接受连接

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


    int addrlen = sizeof(address);
    int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    
    if (new_socket == -1) {
        std::cerr << "Error: Failed to accept connection\n";
        return 1;
    }
  • sockfd:监听套接字的文件描述符,即调用 listen 函数后返回的套接字。

  • addr:指向 sockaddr 结构的指针,用于存储连接到的客户端的地址信息。

  • addrlensockaddr 结构的大小,在调用 accept 函数前,需将其初始化为 sizeof(struct sockaddr)

  • 返回值:返回一个新的套接字文件描述符,用于与客户端通信。如果出现错误,则返回 -1。

函数作用:accept 函数用于接受客户端的连接请求。当有客户端连接到服务器时,accept 函数会创建一个新的套接字,并返回该套接字的文件描述符,服务器可以使用该文件描述符与客户端进行通信。同时,addr 参数用于存储连接到的客户端的地址信息。

发送数据给客户端

    const char *message = "Hello from server";
    send(new_socket, message, strlen(message), 0);
    std::cout << "Message sent to client\n";
  • sockfd:要发送数据的套接字文件描述符。
  • buf:指向要发送数据的缓冲区。
  • len:要发送数据的长度。
  • flags:发送标志,通常设置为 0。
  • 返回值:成功时返回发送的字节数,失败时返回 -1。

函数作用:send 函数用于向指定套接字发送数据。它将缓冲区 buf 中的 len 字节数据发送到套接字 sockfd。函数的 flags 参数通常设置为 0,表示没有特殊标志

关闭socket

    close(new_socket);
    close(server_fd);

使用 close 函数关闭这个套接字,释放相关的资源。

  1. 释放系统资源:关闭套接字会释放操作系统为其分配的资源,包括文件描述符等。
  2. 避免资源泄漏:如果不关闭套接字,可能会导致资源泄漏,消耗系统资源并降低性能。
  3. 表示通信结束:关闭套接字可以告知对方通信结束,同时也能清理本地的通信状态。

在这段代码中,new_socket 是一个整数类型的变量,但它关联了一个与客户端通信的套接字文件描述符。在调用 accept 函数后,操作系统会创建一个新的套接字并返回其文件描述符,我们将这个文件描述符保存在 new_socket 中。因此,虽然 new_socket 是一个整数类型的变量,但它实际上是用来代表与客户端通信的套接字的文件描述符。

连接到服务端

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        std::cerr << "Invalid address/ Address not supported\n";
        return 1;
    }

    if (connect(client_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cerr << "Connection failed\n";
        return 1;
    }
  1. int inet_pton(int af, const char *src, void *dst);
  • af:指定地址族,常用的有 AF_INET(IPv4 地址族)和 AF_INET6(IPv6 地址族)。
  • src:要转换的点分十进制或十六进制字符串形式的 IP 地址。
  • dst:用于存储转换后的二进制形式 IP 地址的内存地址。
  • 返回值:如果转换成功,返回 1(对于 IPv4 地址)或 0(对于 IPv6 地址)。如果发生错误,返回 -1。

函数作用:inet_pton 函数用于将点分十进制或十六进制字符串形式的 IP 地址转换为二进制形式的 IP 地址表示。在这个示例中,它将字符串形式的 IPv4 地址 "127.0.0.1" 转换为二进制形式,并将结果存储在 serv_addr.sin_addr 中。如果转换成功,则条件 inet_pton(...) <= 0 将为假,否则为真。

  1. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:套接字文件描述符,表示要连接的套接字。
  • addr:指向要连接的目标地址信息的 sockaddr 结构体指针。
  • addrlensockaddr 结构体的大小。
  • 返回值:成功返回 0,失败返回 -1。

函数作用:connect 函数用于向指定的目标地址发起连接请求。在客户端中,通常在创建套接字后调用 connect 函数,指定要连接的服务器的地址和端口号,以建立与服务器的连接。如果连接成功建立,则可以通过该套接字进行数据传输。

从服务端接收数据

    ssize_t read(int fd, void *buf, size_t count);

    read(client_fd, buffer, 1024);
    std::cout << "Message from server: " << buffer << std::endl;
  • fd:文件描述符,即要从中读取数据的文件或套接字。
  • buf:指向存储读取数据的缓冲区的指针。
  • count:要读取的最大字节数。
  • 返回值:返回实际读取的字节数。如果返回 0,表示已经读到文件末尾(对套接字则表示连接已关闭)。如果返回 -1,表示出现错误。

函数作用:read 函数用于从文件描述符 fd 指定的文件或套接字中读取数据,将读取的数据存储到 buf 指向的缓冲区中。它会尽可能读取 count 指定的字节数,但可能会因为文件末尾或其他原因而读取少于 count 字节的数据。

代码

server.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    // 创建socket
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        std::cerr << "Error: Failed to create socket\n";
        return 1;
    }

    // 绑定地址和端口
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    address.sin_family = inet_addr("100.10.10.1");//AF_INET;     // TCP/IPv4   AF_INET6:TCP/IPv6
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) == -1) {
        std::cerr << "Error: Failed to bind\n";
        return 1;
    }

    // 监听连接
    if (listen(server_fd, 3) == -1) {
        std::cerr << "Error: Failed to listen\n";
        return 1;
    }

    // 接受连接
    int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
    if (new_socket == -1) {
        std::cerr << "Error: Failed to accept connection\n";
        return 1;
    }

    // 发送数据给客户端
    const char *message = "Hello from server";
    send(new_socket, message, strlen(message), 0);
    std::cout << "Message sent to client\n";

    // 关闭socket
    close(new_socket);
    close(server_fd);

    return 0;
}

client.cpp

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    // 创建socket
    int client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd == -1) {
        std::cerr << "Error: Failed to create socket\n";
        return 1;
    }

    // 连接到服务端
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { //IP地址转换
        std::cerr << "Invalid address/ Address not supported\n";
        return 1;
    }

    if (connect(client_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        std::cerr << "Connection failed\n";
        return 1;
    }

    // 从服务端接收数据
    char buffer[1024] = {0};
    read(client_fd, buffer, 1024);
    std::cout << "Message from server: " << buffer << std::endl;

    // 关闭socket
    close(client_fd);

    return 0;
}

上面内容比较简单基础,这篇socket网络通信包含TCP和UDP,以供参考 

【C++】基础:网络编程介绍与TCP&UDP示例_c++网络编程-CSDN博客

抛弃别人的目光才是自由的开始!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/603677.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络机顶盒哪个牌子好?经销商整理热门网络机顶盒排名

做实体数码店多年来&#xff0c;网络机顶盒这行我非常了解&#xff0c;各种品牌的网络机顶盒我们全销售过。近来很多朋友咨询我网络机顶盒哪个牌子好&#xff0c;我按照店内近一个季度的销量情况整理了是实体店最畅销的网络机顶盒排名&#xff0c;最受欢迎的品牌是以下这些&…

WM Shell多动画场景处理

Shell导致的内存泄漏 基本上都是某个动画未正常结束&#xff0c;执行时间太久导致后续动画堆积或被merge到异常动画导致相关Surface得不到释放导致的。 某个Transition执行时间太久导致后续动画堆积 Visible layers 中有1558 个Transition Root相关layer Visible layers (c…

卡牌——蓝桥杯十三届2022国赛大学B组真题

样例输入 4 5 1 2 3 4 5 5 5 5样例输出 3样例说明 这 5 张空白牌中,拿2张写1,拿1张写2,这样每种牌的牌数就变为了3,3,3,4, 可以凑出 3套牌,剩下2张空白牌不能再帮助小明凑出一套。 评测用例规模与约定 对于30%的数据&#xff0c;保证n ⩽ \leqslant ⩽ 2000; 对于100%的数据…

笔记85:如何计算递归算法的“时间复杂度”和空间复杂度?

先上公式&#xff1a; 递归算法的时间复杂度 递归次数 x 每次递归消耗的时间颗粒数递归算法的空间复杂度 递归深度 x 每次递归消耗的内存空间大小 注意&#xff1a; 时间复杂度指的是在执行这一段程序的时候&#xff0c;所花费的全部的时间&#xff0c;即时间的总和而空间复…

ORA-28575: unable to open RPC connection to external procedure agent

环境&#xff1a; Oracle 11.2.0.4x64 RAC AIX6.1版本SDE for aix oracle11g版本10.0 x64 sde配置情况如下&#xff1a; 检查oracle和grid用户下的$ORACLE_HOME/hs/admin/extproc.ora文件均包含有如下&#xff1a; SET EXTPROC_DLLSANY 两个节点sde下的user_libraries都正常…

【STM32+HAL+Proteus】系列学习教程---中断(NVIC、EXTI、按键)

实现目标 1、掌握STM32的中断知识 2、学会STM32CubeMX软件关于中断的配置 3、具体目标&#xff1a;1、外部中断检测按键&#xff0c;每按一次计一次数&#xff0c;满5次LED1状态取反。 一、中断概述 1.1、中断定义 CPU执行程序时&#xff0c;由于发生了某种随机的事件(包括…

巡检机器人有哪些功能和作用?

在科技如此发达的时代&#xff0c;巡检机器人犹如一位不知疲倦的守护者&#xff0c;悄然走进了我们的生活。它们具备着令人惊叹的功能和作用&#xff0c;成为了保障安全、提高效率的重要力量。那么&#xff0c;巡检机器人功能和作用&#xff1f;下面我们来说说旗晟机器人的几款…

faad2交叉编译——aac解码为pcm,解决faad单通道转双通道问题

FAAD是比较成熟高效的开源AAC解码库&#xff0c;这里用于解码AAC生成PCM数据&#xff0c;用于音频播放。这里因为faad库&#xff0c;会将单通道转化为双通道踩了些坑&#xff0c;所以记录一下。 我使用的是2.11.0版本&#xff0c;貌似往前的版本没有使用CMake&#xff0c;需要c…

自动化测试:Selenium入门指南!

Selenium是一个强大的自动化测试工具&#xff0c;特别适用于Web应用测试。本指南将介绍Selenium的安装、常用功能以及一些常见方法&#xff0c;帮助入门并能够更灵活地进行自动化测试。Selenium是一个用于自动化浏览器操作的工具&#xff0c;它广泛应用于Web应用程序的测试和网…

【前缀和】560. 和为 K 的子数组 974. 和可被 K 整除的子数组

题目链接 974. 和可被 K 整除的子数组 560. 和为 K 的子数组 今天刷题的时候&#xff0c;刷了这两题&#xff0c;感觉挺有意思的。代码写起来挺简单的&#xff0c;但是思路和其中的细节以及涉及到的知识点确实让我挺意外的。这里写个博客解析一波&#xff0c;也是巩固一下。 力…

分享《2024年中国企业级SaaS行业研究报告》

&#xff08;文章作者与来源&#xff1a;艾瑞咨询&#xff09; 大浪淘沙&#xff0c;SaaS行业进入关键转折点&#xff0c;企业级SaaS的总体市场规模达到888亿元&#xff0c;同比增长13.0%。内外部因素叠加之下&#xff0c;预计三年未来企业级SaaS市场规模的增速将稳定在15%-20…

请大数据把我推荐给正在申请小程序地理位置接口的人

小程序地理位置接口有什么功能&#xff1f; 若提审后被驳回&#xff0c;理由是“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;那么遇到这种情况&#x…

2024速通python之python基础

文章目录 一、你好&#xff0c;世界二、基本数据类型&#xff08;1&#xff09;数字型&#xff08;2&#xff09;字符串&#xff08;3&#xff09;列表&#xff08;4&#xff09;元组&#xff08;5&#xff09;集合&#xff08;6&#xff09;字典 二、注释&#xff08;1&#x…

【面试干货】http请求报文的组成与作用?

【面试干货】http请求报文的组成与作用&#xff1f; 一、http 的请求报文组成二、请求行&#xff08;Request Line&#xff09;三、请求头部&#xff08;Request Headers&#xff09;四、请求体&#xff08;Request Body&#xff09;五、响应头部 &#xff08;Response Headers…

LeetCode70:爬楼梯

题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 解题思想 1.确定dp数组以及下标的含义 dp[i]&#xff1a; 爬到第i层楼梯&#xff0c;有dp[i]种方法 2.确定递推公式 从dp[i]的定义可以…

Ansible任务剧本Playbook之变量、模板、角色介绍

前言 上篇介绍了 Ansible 单模块&#xff08;AD-Hoc&#xff09;的相关内容Ansible自动化运维工具单模块介绍-CSDN博客&#xff0c;Ad-Hoc 命令是一次性的、即时执行的命令&#xff0c;用于在远程主机上执行特定任务&#xff0c;这些命令通常用于快速执行简单的任务。当需要在…

【AI绘画】Midjourney 工笔画 水蓝色衣服的少女

using Midjourney 提示词&#xff1a; highly detailed,细节刻画细腻,超高清晰度,32k,HD,大师作品,高质量,动漫少女,水墨人像,20岁年轻身材很好的中国少女,惊人的美貌,五官精致,精致的妆容,华丽的水蓝色衣服,古风服饰,华丽的珠宝,飞扬的黑色长发,大风吹起头发,宝石发光,黄金装饰…

如何给正弦信号添加12V直流偏置

一个有趣问题的探究&#xff1a; 运放在单电源的情况下只能输出正电压&#xff08;单方向的&#xff09;&#xff0c;这就使得有正负值的信号电压只能输出一半&#xff1a; 【单电源供电的运放如何增加直流偏置】&#xff08;电阻分压法&#xff09;&#xff1a; 单电源供电的…

某云eHR PtFjk.mob 任意文件上传漏洞复现

0x01 产品简介 某云eHR是大中型企业广泛采用人力资源管理系统。某云是国内顶尖的HR软件供应商,是新一代eHR系统的领导者。 0x02 漏洞概述 某云EHR系统PtFjk.mob接口处存在未授权文件上传漏洞,攻击者可上传webshell来命令执行,获取服务器权限。 0x03 复现环境 FOFA:bod…
最新文章