Linux 第三十八章

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

智能指针

socket

bind

struct sockaddr结构体

htons

inet_addr

recvfrom

sendto

return和exit的区别

127.0.0.1

netstat


智能指针

智能指针是 C++ 中的一个重要概念,它们是用来管理动态分配的内存,能够自动进行内存的释放,从而避免内存泄漏和悬空指针等问题。C++11 引入了三种主要的智能指针:std::unique_ptr、std::shared_ptr 和 std::weak_ptr。

下面是它们的简要介绍和使用示例:

1. std::unique_ptr
* std::unique_ptr 是一个独占式智能指针,表示它所指向的资源只有一个所有权。
* 当 std::unique_ptr 被销毁时,它所管理的资源会被自动释放。
* 不能进行复制,但可以进行移动。

示例:

#include <memory>
int main() {
    // 创建一个 unique_ptr,管理一个动态分配的整型对象
    std::unique_ptr<int> ptr(new int(42));
    
    // 使用箭头运算符来访问所管理的对象
    std::cout << *ptr << std::endl;
    
    // 可以通过 release() 方法释放所有权,但不会删除资源
    int* rawPtr = ptr.release();
    // 现在 ptr 不再管理资源,需要手动释放内存
    delete rawPtr;
    return 0;
}

socket

socket() 系统调用用于创建一个套接字,并返回一个文件描述符,之后可以使用该描述符进行网络通信。

它的原型如下:

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

参数说明:
* domain:指定协议族,常见的有 AF_INET(IPv4 地址)和 AF_INET6(IPv6 地址)等。
* type:指定套接字类型,常见的有 SOCK_STREAM(面向连接的流套接字,如 TCP)和 SOCK_DGRAM(数据报套接字,如 UDP)等。
* protocol:指定使用的协议,通常设置为 0,表示使用默认协议。
成功创建套接字后,socket() 返回一个非负整数文件描述符,用于后续的套接字操作。失败时返回 -1,并设置 errno 来指示错误的原因。

示例用法:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main() {
    int sockfd;

    // 创建一个 IPv4 TCP 套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    printf("Socket created successfully. File descriptor: %d\n", sockfd);

    // 在这里可以进行后续的套接字操作,如绑定地址、连接服务器等

    close(sockfd); // 使用完套接字后记得关闭

    return 0;
}
这段代码创建了一个 IPv4 TCP 套接字,并在创建成功后打印其文件描述符。

bind

bind() 系统调用用于将一个地址绑定到套接字上,这样套接字就可以使用指定的地址和端口进行通信。

它的原型如下:

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
* sockfd:指定要绑定地址的套接字文件描述符。
* addr:指向包含地址信息的 struct sockaddr 结构体的指针。
* addrlen:指定 addr 结构体的长度。
成功绑定地址后,bind() 返回 0;失败时返回 -1,并设置 errno 来指示错误的原因。
通常在服务器端程序中,先创建套接字,然后通过 bind() 将套接字绑定到一个地址上。绑定的地址可以是本地主机的 IP 地址和端口,也可以是特定的网络接口地址和端口。

示例用法:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    int sockfd;
    struct sockaddr_in server_addr;

    // 创建一个 IPv4 TCP 套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080); // 设置端口号为 8080
    server_addr.sin_addr.s_addr = INADDR_ANY; // 使用任意本地地址

    // 绑定地址到套接字
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    printf("Socket bound successfully.\n");

    // 在这里可以进行后续的套接字操作,如监听连接、接受连接等

    close(sockfd); // 使用完套接字后记得关闭

    return 0;
}

这段代码创建了一个 IPv4 TCP 套接字,并将其绑定到本地主机的 8080 端口上。

 bind函数被显式地指定了其所属的命名空间为全局命名空间,即::bind。这样可以确保不会和C++标准库中的同名函数产生冲突。

struct sockaddr结构体

struct sockaddr 是一个通用的套接字地址结构体,在网络编程中经常用于表示各种类型的地址信息。

它的定义如下:

struct sockaddr {
    unsigned short sa_family; // 地址族,如 AF_INET、AF_INET6 等
    char sa_data[14]; // 具体的地址信息,大小根据不同的地址族而变化
};


由于 struct sockaddr 是一个通用的结构体,它并不直接提供足够的信息来描述具体的地址。为了支持不同类型的地址,通常会使用其派生结构体,

例如:

* struct sockaddr_in:用于表示 IPv4 地址。
* struct sockaddr_in6:用于表示 IPv6 地址。
这些结构体在 netinet/in.h 头文件中定义。它们的定义包含了更具体的地址信息,
例如 IP 地址、端口号等。

下面是 struct sockaddr_in 的定义:

struct sockaddr_in {
    sa_family_t sin_family; // 地址族,总是设置为 AF_INET
    in_port_t sin_port; // 端口号
    struct sin_addr sin_addr; // IPv4 地址
    unsigned char sin_zero[8]; // 填充字段,用于使 sockaddr_in 和 sockaddr 保持相同的大小
};
struct sockaddr_in 中的 sin_addr 成员是一个 struct in_addr 结构体,用于表示 IPv4 地址。struct in_addr 的定义如下:
struct in_addr {
    in_addr_t s_addr; // IPv4 地址
};

通过使用这些结构体,我们可以方便地在网络编程中处理不同类型的地址。在使用时,通常会将 struct sockaddr 指针转换为特定类型的结构体指针,以便访问其中的具体信息。

htons

htons 是一个网络字节顺序和主机字节顺序之间进行转换的函数,用于将 16 位无符号整数从主机字节顺序转换为网络字节顺序。

在网络编程中,数据在传输过程中需要统一使用网络字节顺序(大端序),以确保不同主机之间能够正确解释数据。而在主机上,通常使用主机字节顺序(可能是大端序或小端序)。

函数原型如下:

#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
参数 hostshort 是一个 16 位无符号整数,表示主机字节顺序的端口号或其他数据。
htons 函数将 hostshort 中的值从主机字节顺序转换为网络字节顺序,并返回转换后的值。
如果主机字节顺序和网络字节顺序相同,htons 函数只是简单地返回 hostshort 的值。

inet_addr

在Linux中,inet_addr函数用于将点分十进制的IPv4地址转换为网络字节序的32位整数。这个函数在C语言的<arpa/inet.h>头文件中声明。

函数原型如下:

#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
其中参数cp是一个指向以空字符结尾的字符串,表示点分十进制表示的IPv4地址。
函数返回一个in_addr_t类型的值,即32位无符号整数,如果转换成功则返回相应的网络字节序整数,
如果转换失败则返回INADDR_NONE,其值通常为-1。

recvfrom

在Linux中,recvfrom函数用于从已连接或未连接的套接字接收数据。它可以用于接收来自网络的数据,也可以用于从其他进程通过UNIX域套接字传输的数据。

函数原型如下:

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
参数说明:
* sockfd:套接字描述符,用于指定要接收数据的套接字。
* buf:接收数据的缓冲区。
* len:缓冲区的长度,即可接收的最大字节数。
* flags:指定接收操作的可选标志。常见的标志有:
    * MSG_DONTWAIT:非阻塞模式,即使没有数据可接收也立即返回。
    * MSG_WAITALL:阻塞模式,等待直到接收到指定长度的数据。
* src_addr:如果不为 NULL,则用于存储发送方的地址信息。
* addrlen:指向存储src_addr结构体长度的变量的指针。
函数返回值:
* 成功时返回接收到的字节数,失败时返回-1,并设置errno来指示错误的原因。

recvfrom函数通常用于在UDP套接字上接收数据,因为UDP是无连接的协议,每个数据报都包含发送方的地址信息。在TCP套接字上,通常使用recv函数来接收数据,因为TCP是面向连接的协议,数据已经通过connect函数建立了连接,因此不需要再提供地址信息。

sendto

在Linux系统中,sendto函数用于通过指定的socket发送数据。

它的原型如下:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
参数说明:
sockfd:socket描述符。
buf:指向数据的指针。
len:要发送的数据长度。
flags:操作标志,例如MSG_CONFIRM确认消息已发送。
dest_addr:指向目的地址的 sockaddr 结构体的指针。
addrlen:dest_addr 结构体的长度。
返回值:成功返回发送的数据长度,失败返回-1。

使用sendto函数发送数据时,需要指定目的地址和端口。以下是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
    struct sockaddr_in dest_addr;
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(12345);
    inet_pton(AF_INET, "127.0.0.1", &dest_addr.sin_addr);
    char *data = "Hello, world!";
    ssize_t sent = sendto(sock, data, strlen(data), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (sent < 0) {
        perror("sendto");
        close(sock);
        exit(EXIT_FAILURE);
    }
    printf("Sent %ld bytes to %s:%d\n", (long)sent, inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port));
    close(sock);
    return 0;
}

这个示例创建了一个UDP socket,然后向本地地址127.0.0.1的端口12345发送了一条消息。

return和exit的区别

return 和 exit 在 C/C++ 中的主要区别如下:

1. 调用位置不同:

return 语句通常用于函数中,用于返回一个值给调用者,并退出当前函数

exit 函数可以用于在任何地方调用,用于立即终止程序的执行,并可以传递一个退出状态码给操作系统。

2. 返回值不同:

return 语句可以返回一个值给调用者,这个值通常是函数计算的结果。

exit 函数不能返回值给调用者,但是可以传递一个退出状态码给操作系统。这个状态码可以被其他程序(如 shell 脚本)用来判断程序的执行结果。

3. 退出方式不同:

return 语句退出当前函数,但程序仍然继续执行后续的代码。

exit 函数立即终止程序的执行,不再执行后续的代码。

4. 应用场景不同:

return 语句通常用于正常的函数返回,或者在某些条件满足时提前退出函数。

exit 函数通常用于在程序遇到错误、异常或其他特殊情况时,立即终止程序的执行。

客户端也需要绑定套接字空间,但是,不需要显示的绑定,client会在首次发送数据的时候自动绑定服务器的端口号,一定众所周知的,不可以随意改变,client需要port,客户端需要绑定随机端口因为客户端非常多,所以客户端需要绑定随机端口

127.0.0.1

本地环回,通常用来测试网络cs的测试

127.0.0.1是一个特殊的IP地址,通常被称为"本地回环地址"或"环回地址"。它是IPv4地址空间中的一部分,用于在本地设备上测试网络功能和通信。当计算机发送数据到127.0.0.1时,数据包实际上并不会离开计算机,而是被送往本地网络接口,然后被送回给发送者。这样就实现了在同一台计算机上进行网络通信的效果,而无需连接到外部网络。

在大多数情况下,当应用程序需要与自己的同一台计算机上的另一个应用程序进行通信时,可以使用127.0.0.1地址。例如,当你在本地计算机上运行一个Web服务器时,可以使用127.0.0.1作为服务器地址来访问该服务器,而不必连接到外部网络。

netstat

netstat 是一个用于显示网络状态信息的命令行工具,可以用于查看网络连接、路由表、接口统计等。在Linux系统中,它是一个非常常用的网络调试工具。

以下是 netstat 命令的常见用法和选项:

* netstat -a:显示所有连接和监听中的套接字。
* netstat -t:显示TCP连接。
* netstat -u:显示UDP连接。
* netstat -n:以数字形式显示地址和端口号。
* netstat -p:显示正在使用的协议。
* netstat -l:显示监听中的套接字。
* netstat -r:显示路由表。
* netstat -s:显示网络统计信息。
* netstat -i:显示网络接口信息。

client bind是在首次发送数据的时候,进行有内核随机bind(而不·需要我们手动绑定)

如果服务器绑定的ip是127.0.0.1就只能进行本地通信

云服务器公网ip其实是供应商给你虚拟出来的公网ip,无法进行直接bind

我们强烈不推荐给服务器bind固定ip,更推荐本地任意ip

因为,bind指定的ip只能够接受和发送该ip的报文

不推荐:local.sin_addr.s_addr = inet_addr(_ip.c_str()); //指定ip,需要传递整形的ip
推荐:local.sin_addr.s_addr = INADDR_ANY; //指定ip,INADDR_ANY表示本机的任意一个ip地址

  🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值