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

Linux网络_套接字_UDP网络_TCP网络

一.UDP网络

1.socket()创建套接字

#include<sys/socket.h>
int socket(int domain, int type, int protocol);
  1. domain (地址族): AF_INET网络 AF_UNIX本地

    • AF_INET:IPv4 地址族,适用于 IPv4 协议。用于网络通信
    • AF_INET6:IPv6 地址族,适用于 IPv6 协议。
    • AF_UNIX 或 AF_LOCAL:Unix 域套接字,用于本地通信。
    • AF_PACKET:用于与链路层通信(如以太网接口)。
    • 还有其他的地址族,例如 AF_APPLETALKAF_NETLINK 等,但这些较少使用。
  2. type (套接字类型):

    • SOCK_STREAM:流式套接字,表示 TCP 协议,面向连接,提供可靠的数据传输。
    • SOCK_DGRAM:数据报套接字,表示 UDP 协议,无连接的、不可靠的数据传输。
    • SOCK_RAW:原始套接字,允许直接操作底层协议,如 IP、ICMP 等(通常需要管理员权限)。
    • SOCK_SEQPACKET:顺序数据包套接字,适用于某些特定的协议。
  3. protocol (协议类型):

    • 通常设置为 0,系统会根据地址族和套接字类型自动选择合适的协议。
    • 也可以显式指定某个协议,例如:IPPROTO_TCP(TCP协议)或 IPPROTO_UDP(UDP协议)。

返回值

  • 如果调用成功,返回一个套接字描述符(一个非负整数),该描述符是后续与套接字进行交互的标识。
  • 如果调用失败,返回 -1,并设置 errno 来指示错误原因。

错误代码

  • EAFNOSUPPORT:不支持指定的地址族。
  • EINVAL:无效的套接字类型或协议。
  • ENFILE:系统中可用的文件描述符已用尽。
  • ENOMEM:系统内存不足。

2.bind()绑定

在 Linux 中,bind 系统调用用于将一个 套接字(socket)与一个本地地址(IP 地址和端口号)绑定。这个操作通常用于服务器端,目的是让服务器的套接字可以接收来自特定地址和端口的网络数据。

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

  • sockfd:要绑定的套接字描述符,通常是通过 socket() 系统调用创建的。
  • addr:指向一个 struct sockaddr 或其派生结构体的指针,用于指定要绑定的地址和端口。这个结构体的内容取决于地址族(AF_INETAF_INET6 等)。
  • addrlenaddr 指向的地址结构的大小,通常是 sizeof(struct sockaddr_in) 或 sizeof(struct sockaddr_in6)

返回值:

  • 成功:返回 0
  • 失败:返回 -1,并设置 errno 以指示错误。

sockaddr 结构

socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如 IPv4、IPv6,以及
后面要讲的 UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同.

#include<netinet/in.h>

#include<arpa/inet.h>

sockaddr:一个通用的地址结构体,所有网络地址结构体(如 sockaddr_in 和 sockaddr_un)都可以通过它来表示。它为不同协议族提供了统一的接口。

sockaddr_in:用于表示 IPv4 地址的结构体。它扩展了 sockaddr,包括端口号、IP 地址等信息,常用于网络通信/本地。

sockaddr_un:用于表示 UNIX 域套接字地址的结构体,主要用于进程间通信(本地),套接字地址基于文件路径。

struct sockaddr 结构

#include <netinet/in.h>
struct sockaddr {sa_family_t sa_family; // 地址族,例如 AF_INET 或 AF_UNIXchar sa_data[14];      // 用于存储地址信息的字符数组
};

strcuct sockaddr_in 结构

struct sockaddr_in {sa_family_t    sin_family; // 地址族,通常为 AF_INET(网络通信)in_port_t      sin_port;   // 端口号,使用网络字节序(大端)struct in_addr sin_addr;   // IP 地址unsigned char  sin_zero[8]; // 填充字节,保持结构体大小一致
};
struct in_addr {in_addr_t s_addr; // 32 位的 IP 地址
};

strcuct sockaddr_un 结构

struct sockaddr_un {sa_family_t sun_family;  // 地址族,通常是 AF_UNIX(本地通信)char sun_path[108];      // UNIX 域套接字路径,最大长度为 108 字节
};

在套接字编程中,我们通常会使用特定的结构体(如 sockaddr_in 或 sockaddr_un)来处理网络地址,而 sockaddr 作为通用结构体,通常在系统调用(如 bind(), connect() 等)中使用,要求通过类型转换将具体的地址结构体转为 sockaddr 类型。

htons() 主机字节序转网络字节序

因为TCP/IP 协议规定,网络数据流应采用大端字节序。

所以向网络发数据应改位大端。

htons()返回转换后的 16 位无符号整数,这个整数是网络字节序(大端字节序)下的值。

htonl() 回转换后的 32 位无符号整数,这个整数是网络字节序(大端字节序)下的值。

ntohs()用于将网络字节序(大端字节序)转换回主机字节序。 16位无符号整数

inet_addr() 字符型ip地址->32位网络字节序

inet_addr 是一个用于将 IPv4 地址从点分十进制字符串表示(如 "192.168.1.1")转换为网络字节序的 in_addr_t 类型(通常是一个 32 位的无符号整数)的方法。

#include <arpa/inet.h>  // 包含 inet_addr 的定义
in_addr_t inet_addr(const char *cp);

字符转整型+改大端

inet_pton() 字符型ip地址->32位网络字节序

int inet_pton(int af, const char *src, void *dst);

参数:

  • af: 地址族,指定了 IP 地址的类型。常见的值有:

    • AF_INET:表示 IPv4 地址。
    • AF_INET6:表示 IPv6 地址。
  • src: 输入的地址字符串,表示待转换的 IP 地址。例如,IPv4 地址是 "192.168.1.1",IPv6 地址可能是 "2001:0db8:85a3:0000:0000:8a2e:0370:7334"

  • dst: 指向用于存储转换后的二进制地址的缓冲区。对于 IPv4,通常是 struct in_addr 类型,对于 IPv6,通常是 struct in6_addr 类型。

返回值:

  • 成功:返回 1,表示地址转换成功。
  • 失败
    • 如果输入的 IP 地址格式无效(例如,IPv4 地址包含不合法的数字),返回 0
    • 如果出现其他错误,返回 -1,并且可以通过 errno 获取详细错误信息。

inet_ntoa() 32位网络字节序->字符型ip地址

inet_ntoa 是一个用于将 IPv4 地址(以网络字节顺序存储的二进制格式)转换为 点分十进制

格式的函数。这个函数通常在 C 语言中使用,用于将 struct in_addr 结构中的二进制形式的 IPv4 地址转换为标准的文本表示形式。

<arpa/inet.h>
char *inet_ntoa(struct in_addr in);

inet_ntop() 32位网络字节序->字符型ip地址(多线程)

inet_ntop() 是一个更通用的函数,支持 IPv4 和 IPv6 地址。把转换的字符串地址放在提供的栈空间中,防止被覆盖。

inet_ntoa() 函数返回的是一个静态的缓冲区该缓冲区在函数调用之间会被复用,因此在多次调用 inet_ntoa() 时,返回的字符串会被覆盖。这使得在 多线程环境 中使用 inet_ntoa() 可能导致线程之间共享同一个静态缓冲区,进而引发 数据竞争 或 意外的覆盖问题。

#include <stdio.h>
#include <arpa/inet.h>const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
  • af:地址族,指定是 IPv4 还是 IPv6。IPv4 使用 AF_INET,IPv6 使用 AF_INET6
  • src:指向网络字节顺序的地址结构(struct in_addr 或 struct in6_addr)。
  • dst:用于存储结果字符串的缓冲区,必须足够大以容纳结果字符串(IPv4 地址需要 16 字节,IPv6 地址需要 46 字节)。
  • sizedst 缓冲区的大小。

返回值

  • 如果成功,返回 dst 指向的字符串。
  • 如果出错,返回 NULL,并设置 errno

3.recvfrom()接收数据

recvfrom 是一个用于接收数据的系统调用,它通常用于 UDP 套接字,或者在某些情况下,用于接收来自不同主机的 TCP 数据。它的功能是从指定的套接字中接收数据,并且可以获取远程主机的地址信息。

#include <arpa/inet.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);//socklen_t unsigned int 无符号整型

参数说明:

  • sockfd:目标套接字的文件描述符,通常是通过 socket() 函数返回的套接字描述符。
  • buf:指向接收数据的缓冲区
  • len:缓冲区的长度,即可以接收的最大字节数
  • flags:接收的标志位,通常为 0,或者使用一些标志,如 MSG_PEEK 等。
  • src_addr:指向 struct sockaddr 结构的指针,用于存放发送方的地址信息。对于 UDP 来说,这将包含发送方的 IP 地址和端口号。
  • addrlen指向一个 socklen_t 类型的变量表示 src_addr 缓冲区的大小recvfrom 调用返回后,这个变量将被更新为实际存放的地址长度。

返回值:

  • 成功时,返回实际接收到的字节数。
  • 出错时,返回 -1,并设置 errno

在使用 recvfrom 时,addrlen 初始时需要包含 src_addr 缓冲区的大小。recvfrom 在接收数据时,会根据实际填充的地址长度来更新 addrlen。

这种机制主要是为了处理不同类型的地址结构,它们可能有不同的大小。例如,IPv4 和 IPv6 的地址结构有不同的大小,因此 addrlen 必须传入一个适当的初始值,并且 recvfrom 会修改它,以便传出实际的地址长度。

如果 addrlen 不包含缓冲区的大小,系统无法确定在接收数据时应该使用多大的内存空间来存储地址信息,这可能导致:

无法获取正确的地址: recvfrom 在更新 addrlen 时,必须知道地址结构的空间。没有正确的大小,recvfrom 可能不会正确填充地址信息,或者根本无法获取发送方的地址。

4.sendto()发送数据

sendto 是一个用于发送数据报文(datagram)的系统调用函数,通常在基于 UDP 的网络编程中使用。它允许应用程序将数据发送到指定的目标地址,而无需先建立连接。它是 sockets API 的一部分,适用于无连接的协议,如 UDP。

#include <sys/types.h>
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

参数说明:

  1. sockfd

    一个已打开的 socket 描述符。它是通过 socket() 函数返回的,并且该 socket 必须是使用无连接协议(如 UDP)创建的。
  2. buf

    指向包含要发送数据的缓冲区的指针。数据的大小由 len 参数指定。
  3. len

    发送的数据的长度(字节数)。
  4. flags

    发送的标志,通常为 0。可以使用一些额外的标志,如 MSG_CONFIRMMSG_DONTWAITMSG_NOSIGNAL 等,具体使用取决于需求。
  5. dest_addr

    指向一个 struct sockaddr 类型的结构体,表示目标地址。对于 UDP,这通常是一个 struct sockaddr_in 类型的结构,包含目标主机的 IP 地址和端口号。
  6. addrlen

    dest_addr 结构的长度,通常是 sizeof(struct sockaddr_in)

返回值:

  • 成功时,返回发送的字节数(即 len)。
  • 失败时,返回 -1,并设置 errno 以指示错误。

netstat命令查看网络服务是否启动

netstat -nuap

-u 查看UDP连接

-a 查看所有网络连接

-p 查看每个连接的 PID(进程标识符)

-n 以数字形式显示地址和端口号

ifconfig命令查看网络接口(ip mac)

ifconfig 是一个用于在 Unix-like 操作系统(如 Linux 和 macOS)中查看或配置网络接口的命令。它通常用于显示当前的网络接口配置,启用或禁用网络接口,配置 IP 地址,子网掩码,广播地址等。

eth0      Link encap:Ethernet  HWaddr 00:0c:29:3d:5e:80  inet addr:192.168.1.10  Bcast:192.168.1.255  Mask:255.255.255.0inet6 addr: fe80::20c:29ff:fe3d:5e80/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:12345 errors:0 dropped:0 overruns:0 frame:0TX packets:12345 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000 RX bytes:9876543 (9.8 MB)  TX bytes:9876543 (9.8 MB)

在上面的输出中,eth0 是网络接口的名称,inet addr 显示的是接口的 IPv4 地址。

在一些现代的 Linux 发行版中,ifconfig 已被 ip 命令(由 iproute2 提供)所取代,ip 命令提供了更多的功能和更细粒度的控制。例如,使用以下命令查看网络接口:
ip a

INADDR_ANY宏 人员地址绑定

它是一个 in_addr_t 类型的值,通常用于网络编程中的 sockaddr_in 结构体,表示一个可以匹配所有网络接口的地址。


INADDR_ANY 是一个常量,通常被定义为 0.0.0.0。
在绑定套接字时使用 INADDR_ANY,服务器可以接收来自本机所有接口的连接请求。

#define INADDR_ANY ((in_addr_t) 0x00000000)

UPD网络流程

1. socket()创建套接字

客户端和服务器端都需要使用 socket() 函数创建一个 UDP 套接字。UDP 套接字使用 SOCK_DGRAM 类型。

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  // 创建 UDP 套接字

2. bind()设置服务器地址(服务器端)

服务器需要绑定一个本地的地址和端口,以便能够接收来自客户端的数据。

void *memset(void *ptr, int value, size_t num);把定义的sockaddr_in结构体清零。

INADDR_ANY 0.0.0.0 服务器可以接收来自本机所有接口的连接请求。

htons 转网络字节序

struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定到本机所有接口
server_addr.sin_port = htons(PORT);  // 绑定指定端口bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));  // 绑定端口

3. sendto()发送数据(客户端)

客户端可以直接通过 sendto() 函数将数据发送到服务器的 IP 地址和端口,无需建立连接。

inet_pton() 用于将 IP 地址从文本表示(如点分十进制的字符串)转换为二进制形式

struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "192.168.1.100", &server_addr.sin_addr);  // 服务器地址char message[] = "Hello, Server!";
sendto(sockfd, message, sizeof(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
//client不需要bind端口号吗?
//1.系统自动给客户端bind端口号 为什么?
//我客户端打开进程,只要保证进程的端口号有唯一性,能运行 连上服务端就行。没人会主动连我,所以没必 要知道端口号。
//同一个进程的端口号每次启动不一定是固定的,但一定唯一
//2.为什么服务端要显示bind端口号呢?
//因为服务端的端口号是不能随便改变的。不同的客户端访问到服务端就是靠唯一的端口号找到的。所以我们自 己定义端口号,固定端口号。

4. recvfrom() 接收数据(服务器端)

服务器端使用 recvfrom() 函数接收客户端发送的数据。该函数会返回数据并填充客户端的地址信息。

一定要设置对struct sockaddr结构体的大小addr_len

struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
char buffer[1024];int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &addr_len);
buffer[n] = '\0';  // 添加字符串结束符
printf("Received from client: %s\n", buffer);

5.  sendto() 发送响应(服务器端)

服务器端可以通过 sendto() 函数发送响应给客户端。

char response[] = "Hello, Client!";
sendto(sockfd, response, sizeof(response), 0, (struct sockaddr*)&client_addr, addr_len);

6.关闭套接字

完成数据通信后,客户端和服务器都需要关闭套接字。

close(sockfd);

二.TCP网络

1.listen() 监听套接字

listen() 将套接字设置为监听模式,准备接收来自客户端的连接请求。

int listen(int sockfd, int backlog);

参数说明:

  • sockfd:这是一个已创建并绑定的套接字文件描述符,通常通过 socket() 和 bind() 函数获得。
  • backlog定义了等待连接队列的最大长度。这个队列用于存放尚未被 accept() 接受的连接请求。队列中的连接数量可能会有所限制,具体值由操作系统决定。backlog 的大小决定了可以挂起多少个连接请求。

返回值:

  • 成功:返回 0,表示监听成功。
  • 失败:返回 -1,并设置 errno 来指示错误原因。

2.accept() 获取套接字 客户端信息

accept 是一个用于处理网络连接的系统调用,通常与套接字(socket)编程一起使用。它的作用是从一个已建立的连接的监听套接字队列中接受一个连接,并为该连接创建一个新的套接字。

最后两个输出型参数 获取客户端信息ip+port

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

参数:

  • sockfd:这是监听套接字的文件描述符,通常是通过 socket() 函数创建的套接字,并且通过 bind() 和 listen() 函数绑定和监听。
  • addr:一个指向 struct sockaddr 结构体的指针,用来存储客户端的地址信息
  • addrlen:这个参数是一个指向 socklen_t 类型的指针指示 addr 所指向的结构体的长度。在调用 accept 之后,它会被更新为实际存储的地址信息长度。

返回值:

  • 成功时,返回一个新的套接字描述符,这个套接字可以用来与客户端进行通信。
  • 如果失败,返回 -1,并设置 errno 以指示错误。

telnet命令

Linux 中使用 telnet 客户端进行网络连接或远程管理是非常常见的操作。虽然 Telnet 不提供加密,因此现在更多推荐使用 SSH(Secure Shell),但它仍然可以用于某些简单的远程连接和测试任务。

telnet <hostname> <port>
<hostname>:目标主机的域名或 IP 地址。
<port>:目标主机上的端口号,Telnet 默认使用 端口 23。

在 Telnet 会话中,按下 Ctrl + ],进入命令模式后,输入 quit 或 exit 来退出。

3.connect()建立与服务端的连接 

在网络编程中,connect 是一个系统调用,用于建立客户端与远程服务器之间的连接。它通常用于 TCP/IP 套接字编程,用于向服务器发起连接请求。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数

  • sockfd:一个已经通过 socket() 函数创建的套接字描述符。
  • addr:一个指向 sockaddr 结构的指针,该结构包含服务器的地址信息(如 IP 地址和端口)。
  • addrlenaddr 结构的大小,通常是 sizeof(struct sockaddr_in) 或 sizeof(struct sockaddr_in6),取决于 IPv4 或 IPv6。

返回值

  • 成功时,返回 0。
  • 失败时,返回 -1,并设置 errno 来指示错误原因。

工作原理

  1. connect 调用会向目标主机发送连接请求(对于 TCP 是三次握手过程)。
  2. 如果连接成功,客户端与服务器之间就建立了连接,之后可以进行数据的发送和接收。
  3. 如果连接失败(例如目标主机不可达或端口不可用),connect 会返回 -1,并设置 errno,指示错误原因。

错误码(常见)

  • ECONNREFUSED:目标服务器拒绝连接。
  • ETIMEDOUT:连接超时。
  • EADDRINUSE:本地地址已经在使用。
  • EHOSTUNREACH:目标主机不可达。

4.recv() send() 收发消息

在网络编程中,recv 和 send 是两个常用的函数,它们分别用于接收和发送数据。这些函数通常与套接字(socket)一起使用,用于在客户端和服务器之间进行数据交换。

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd:是套接字的文件描述符,表示一个有效的已连接套接字。
  • buf:指向缓冲区的指针,recv 会将接收到的数据存放在这里。
  • len:缓冲区的大小,即 buf 能够存储的最大字节数。
  • flags:操作标志,通常为 0 或 MSG_WAITALL(等待接收指定字节数)。

返回值

  • 成功时,返回接收到的字节数。
  • 如果连接已关闭,返回 0。
  • 如果发生错误,返回 -1,并设置 errno
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd:是套接字的文件描述符,表示一个有效的已连接套接字。
  • buf:指向包含要发送数据的缓冲区。
  • len:要发送的数据字节数。
  • flags:操作标志,通常为 0。

返回值

  • 成功时,返回实际发送的字节数。
  • 如果发生错误,返回 -1,并设置 errno

recv 用于从网络上接收数据,它可以读取指定大小的字节。
send 用于向网络上发送数据,数据的大小由你提供。

read 和 write 没有套接字特有的标志控制功能,因此它们在某些情况下缺乏灵活性。例如,在高效处理网络数据时,可能需要精确控制数据接收量、非阻塞模式等,而 recv 和 send 可以通过特定标志轻松实现。

flags 参数:recv 和 send 都可以接受一个 flags 参数,这个参数可以控制一些特定的行为,例如 MSG_DONTWAIT(设为非阻塞状态) 或 MSG_WAITALL(接收指定数量的字节),但通常情况下我们将其设置为 0。

eg.

  • recv(sockfd, buffer, 512, MSG_WAITALL):此函数调用会阻塞直到至少接收到 512 字节的数据(或者发生错误)。
  • 如果没有收到足够的字节,recv 会继续等待,直到数据完整接收或遇到错误。

5.popen() pclose()父子进程间通信

我们之前怎么完成父子进程间通信的?
1.创建管道 int pipe(int pipefd[2]);pipefd[0] 是读取端,pipefd[1] 是写入端。

2.创建子进程 fork()

3.父进程关闭写端 子进程关闭读端 close()

4.子进程输出重定向到管道写端 dup2(pipefds[1], 1) 标志输出文件描述符是1

5.父进程从管道读端进行读取

下面popen pclose可以代替以上操作

FILE *popen(const char *command, const char *mode);

command:要执行命令的字符串

mode:"w" "r",读还是写

子进程执行完命令会把结果放在文件中并返回,pipe fork失败返回NULL

父进程接收文件并读取,最后关闭。

popen 用于打开一个进程,并将其标准输入(stdin)或标准输出(stdout)与父进程连接,返回一个文件指针,使得父进程可以通过该指针与子进程进行数据交互。

FILE *popen(const char *command, const char *mode);

command: 要执行的命令字符串。它是你希望启动的子进程命令。
mode: 访问模式。常见的有:
"r":读取模式,父进程从子进程读取输出(即子进程的标准输出)。popen 会创建一个管道,将子进程的标准输出与父进程连接。父进程可以通过 fgets、fread 等读取子进程的输出。
"w":写入模式,父进程向子进程写入输入(即将数据传递到子进程的标准输入)。popen 会创建一个管道,将父进程的标准输入与子进程连接。父进程可以通过 fputs、fprintf 等向子进程传递数据。

eg.FILE* p=popen("ls","r");

#include <stdio.h>int main() {FILE *fp;char buffer[128];// 打开子进程,执行命令并读取输出fp = popen("ls", "r");if (fp == NULL) {perror("popen");return 1;}// 读取子进程输出并打印while (fgets(buffer, sizeof(buffer), fp) != NULL) {printf("%s", buffer);}// 关闭文件指针pclose(fp);return 0;
}

pclose 用于关闭由 popen 打开的文件指针,并等待子进程的终止。

int pclose(FILE *fp);
  • fp: 是由 popen 返回的文件指针。

返回值:

  • 如果子进程正常退出,pclose 返回子进程的退出状态(通常是 0)。
  • 如果子进程异常退出,返回一个负值。

fgets() 读文件

fgets 是 C 语言标准库中的一个函数,用于从文件或其他输入流中读取一行数据。它通常用于从文件、标准输入(如键盘输入)等地方读取字符串。与 gets 函数相比,fgets 更安全,因为它允许指定最大读取字符数,避免缓冲区溢出问题。

char *fgets(char *str, int num, FILE *stream);

参数说明:

  • str:用于存储读取数据的字符数组。fgets 会将从流中读取的字符存储到 str 中。
  • num:要读取的最大字符数,包括结束符 \0。一般而言,num 应该是你希望读取的最大字节数 + 1,以便为字符串结尾的空字符(\0)留出空间。
  • stream:指向文件流的指针。它可以是:
    • stdin,用于从标准输入读取数据(通常是键盘)。
    • 任何通过 fopen 或其他方式打开的文件指针。

返回值:

  • 如果成功,fgets 返回 str,即读取的字符串。
  • 如果发生错误或到达文件末尾(EOF),返回 NULL

特点:

  • fgets 会读取指定数量的字符,直到遇到换行符 \n 或文件结尾(EOF),并将换行符包括在内。
  • fgets 会自动添加字符串结束符 \0,以保证字符串正确终止。

相关文章:

Linux网络_套接字_UDP网络_TCP网络

一.UDP网络 1.socket()创建套接字 #include<sys/socket.h> int socket(int domain, int type, int protocol);domain (地址族): AF_INET网络 AF_UNIX本地 AF_INET&#xff1a;IPv4 地址族&#xff0c;适用于 IPv4 协议。用于网络通信AF_INET6&#xff1a;IPv6 地址族&a…...

Java学习教程,从入门到精通,JDBC驱动程序类型及语法知识点(91)

JDBC驱动程序类型及语法知识点 一、JDBC驱动程序类型 JDBC驱动程序主要有以下四种类型&#xff1a; 1. Type 1&#xff1a;JDBC - ODBC桥驱动程序&#xff08;JDBC - ODBC Bridge Driver&#xff09; 特点&#xff1a;这种驱动程序是Java与ODBC&#xff08;Open Database C…...

YOLOv8从菜鸟到精通(二):YOLOv8数据标注以及模型训练

数据标注 前期准备 先打开Anaconda Navigator&#xff0c;点击Environment&#xff0c;再点击new(new是我下载anaconda的文件夹名称)&#xff0c;然后点击创建 点击绿色按钮&#xff0c;并点击Open Terminal 输入labelimg便可打开它,labelimg是图像标注工具&#xff0c;在上篇…...

3D目标检测数据集——Nusence数据集

链接地址 [官网] nuScenes[arXiv] nuScenes: A multimodal dataset for autonomous driving[GitHub] nuScenes devkitnuScenes devkit教程数据集概述 2.1 数据采集 2.1.1 传感器配置 nuScenes的数据采集车辆为Renault Zoe迷你电动车,配备6个周视相机&#x...

网站收录入口提交的方法有哪些(网站收录的方式都有哪些)

网站被搜索引擎收录是获得流量和曝光的重要前提&#xff0c;以下为你介绍常见的网站收录方式&#xff1a; 搜索引擎提交入口 各大搜索引擎都设有专门的网站收录入口&#xff0c;供站长提交网站。例如百度搜索资源平台、谷歌搜索控制台等。以百度为例&#xff0c;在百度搜索资…...

移动端H5缓存问题

移动端页面缓存问题是指页面的静态资源&#xff08;如图片、JS 和 CSS 文件&#xff09;在浏览器中被缓存后&#xff0c;用户在下次访问时可以直接从本地获取缓存数据&#xff0c;而不需要每次都从服务器重新获取&#xff0c;不过这样可能会导致页面不能正确地更新或者加载最新…...

11-1.Android 项目结构 - androidTest 包与 test 包(单元测试与仪器化测试)

androidTest 包与 test 包 在 Android 项目中&#xff0c;androidTest 包与 test 包用于存放不同类型的测试代码的 1、测试类型 &#xff08;1&#xff09;androidTest 包 主要用于存放单元测试&#xff08;Unit Tests&#xff09;代码 单元测试是针对应用程序中的独立模块…...

计算机网络(五)——传输层

一、功能 传输层的主要功能是向两台主机进程之间的通信提供通用的数据传输服务。功能包括实现端到端的通信、多路复用和多路分用、差错控制、流量控制等。 复用&#xff1a;多个应用进程可以通过同一个传输层发送数据。 分用&#xff1a;传输层在接收数据后可以将这些数据正确分…...

ZCC9159 -7V 300mA 超低功耗高速 LDO

功能描述 ZCC9195是一款超低功耗并具有快速响应、关断快速放电功能的高速LDO。静态电流低至 0.8uA&#xff0c;输出电流最大为300mA。 ZCC9195具有输出过流保护、输出短路保护、温度保护等功能&#xff0c;确保芯片在异常工作条件 下不会损坏。 ZCC9195只需要1uF的陶瓷电容即…...

微信小程序实现个人中心页面

文章目录 1. 官方文档教程2. 编写静态页面3. 关于作者其它项目视频教程介绍 1. 官方文档教程 https://developers.weixin.qq.com/miniprogram/dev/framework/ 2. 编写静态页面 mine.wxml布局文件 <!--index.wxml--> <navigation-bar title"个人中心" ba…...

【C语言算法刷题】第7题

题目描述 一个XX产品行销总公司&#xff0c;只有一个boss&#xff0c;其有若干一级分销&#xff0c;一级分销又有若干二级分销&#xff0c;每个分销只有唯一的上级分销。 规定&#xff0c;每个月&#xff0c;下级分销需要将自己的总收入&#xff08;自己的下级上交的&#xf…...

BERT与CNN结合实现糖尿病相关医学问题多分类模型

完整源码项目包获取→点击文章末尾名片&#xff01; 使用HuggingFace开发的Transformers库&#xff0c;使用BERT模型实现中文文本分类&#xff08;二分类或多分类&#xff09; 首先直接利用transformer.models.bert.BertForSequenceClassification()实现文本分类 然后手动实现B…...

RocketMQ消息发送---源码解析

我们知道rocketMQ的消息发送支持很多特性&#xff0c;如同步发送&#xff0c;异步发送&#xff0c;oneWay发送&#xff0c;也支持超时机制&#xff0c;回调机制&#xff0c;并且能够保证消息的可靠性和消息发送的限流&#xff0c;底层使用netty框架等等&#xff0c;如此多的特性…...

机器学习06-正则化

机器学习06-正则化 文章目录 机器学习06-正则化0-核心逻辑脉络1-参考网址3-大模型训练中的正则化1.正则化的定义与作用2.常见的正则化方法及其应用场景2.1 L1正则化&#xff08;Lasso&#xff09;2.2 L2正则化&#xff08;Ridge&#xff09;2.3 弹性网络正则化&#xff08;Elas…...

如何开放2375和2376端口供Docker daemon监听

Linux (以 Ubuntu 为例) 1. 修改 Docker 配置文件 打开 Docker 的配置文件 /etc/docker/daemon.json。如果该文件不存在&#xff0c;则可以创建一个新的。 bash sudo nano /etc/docker/daemon.json在配置文件中添加以下内容&#xff1a; json {"hosts": ["un…...

Vue.js组件开发-如何实现路由懒加载

在Vue.js应用中&#xff0c;路由懒加载是一种优化性能的技术&#xff0c;它允许在需要时才加载特定的路由组件&#xff0c;而不是在应用启动时加载所有组件。这样可以显著减少初始加载时间&#xff0c;提高用户体验。在Vue Router中&#xff0c;实现路由懒加载非常简单&#xf…...

rclone,云存储备份和迁移的瑞士军刀,千字常文解析,附下载链接和安装操作步骤...

一、什么是rclone&#xff1f; rclone是一个命令行程序&#xff0c;全称&#xff1a;rsync for cloud storage。是用于将文件和目录同步到云存储提供商的工具。因其支持多种云存储服务的备份&#xff0c;如Google Drive、Amazon S3、Dropbox、Backblaze B2、One Drive、Swift、…...

集成学习算法

目录 1.必要的导入 2.Bagging集成 3.基于matplotlib写一个函数对决策边界做可视化 4.总结图中结论 5.扩展说明 1.必要的导入 # To support both python 2 and python 3 from __future__ import division, print_function, unicode_literals# Common imports import numpy as np…...

vue3之pinia学习

最近查看了pinia这个状态管理管理&#xff0c;想跟大家一起学习下&#xff0c;下面是我的个人理解&#xff0c;希望对大家有帮助&#xff0c;我们开始吧&#xff01; 第一步&#xff1a;安装pinia npm install pinia 第二步&#xff1a;创建pinia <script setup langts&…...

Flink (七): DataStream API (四) Watermarks

1. Event Time and Processing Time 1. 1 处理时间&#xff08;Processing time&#xff09; 处理时间是指执行相应操作的机器的系统时间。当流处理程序基于处理时间运行时&#xff0c;所有基于时间的操作&#xff08;如时间窗口&#xff09;将使用执行相应算子的机器的系统时…...

卷积神经05-GAN对抗神经网络

卷积神经05-GAN对抗神经网络 使用Python3.9CUDA11.8Pytorch实现一个CNN优化版的对抗神经网络 简单的GAN图片生成 CNN优化后的图片生成 优化模型代码对比 0-核心逻辑脉络 1&#xff09;Anacanda使用CUDAPytorch2&#xff09;使用本地MNIST进行手写图片训练3&#xff09;…...

【原创】大数据治理入门(2)《提升数据质量:质量评估与改进策略》入门必看 高赞实用

提升数据质量&#xff1a;质量评估与改进策略 引言&#xff1a;数据质量的概念 在大数据时代&#xff0c;数据的质量直接影响到数据分析的准确性和可靠性。数据质量是指数据在多大程度上能够满足其预定用途&#xff0c;确保数据的准确性、完整性、一致性和及时性是数据质量的…...

GLM: General Language Model Pretraining with Autoregressive Blank Infilling论文解读

论文地址&#xff1a;https://arxiv.org/abs/2103.10360 参考&#xff1a;https://zhuanlan.zhihu.com/p/532851481 GLM混合了自注意力和masked注意力&#xff0c;而且使用了2D位置编码。第一维的含义是在PartA中的位置&#xff0c;如5 5 5。第二维的含义是在Span内部的位置&a…...

总结SpringBoot项目中读取resource目录下的文件多种方法

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…...

云原生第四次作业

下载 [rootopenEuler-1 ~]# wget https://archive.apache.org/dist/httpd/httpd-2.4.46.tar.gz 压缩 配置实验环境 [rootopenEuler-1 httpd-2.4.46]# yum -y install apr apr-devel cyrus-sasl-devel expat-devel libdb-devel openldap-devel apr-util-devel apr-util pcre-d…...

day10_Structured Steaming

文章目录 Structured Steaming一、结构化流介绍&#xff08;了解&#xff09;1、有界和无界数据2、基本介绍3、使用三大步骤(掌握)4.回顾sparkSQL的词频统计案例 二、结构化流的编程模型&#xff08;掌握&#xff09;1、数据结构2、读取数据源2.1 File Source2.2 Socket Source…...

设计模式-工厂模式/抽象工厂模式

工厂模式 定义 定义一个创建对象的接口&#xff0c;让子类决定实列化哪一个类&#xff0c;工厂模式使一个类的实例化延迟到其子类&#xff1b; 工厂方法模式是简单工厂模式的延伸。在工厂方法模式中&#xff0c;核心工厂类不在负责产品的创建&#xff0c;而是将具体的创建工作…...

【算法学习】——整数划分问题详解(动态规划)

&#x1f9ee;整数划分问题是一个较为常见的算法题&#xff0c;很多问题从整数划分这里出发&#xff0c;进行包装&#xff0c;形成新的题目&#xff0c;所以完全理解整数划分的解决思路对于之后的进一步学习算法是很有帮助的。 「整数划分」通常使用「动态规划」解决&#xff0…...

【新教程】Ubuntu 24.04 单节点安装slurm

背景 网上教程老旧&#xff0c;不适用。 详细步骤 1、安装slurm sudo apt install slurm-wlm slurm-wlm-doc -y检查是否安装成功&#xff1a; slurmd --version如果得到slurm-wlm 23.11.4&#xff0c;表明安装成功。 2、配置slurm。 使用命令&#xff1a; sudo vi /etc/s…...

window下用vim

Windows 默认不支持 vim 命令&#xff0c;需要手动安装后才能使用。以下是解决方案&#xff1a; 1. 安装 Vim 编辑器 方法 1&#xff1a;通过 Scoop 或 Chocolatey 安装 使用 Scoop&#xff1a; 安装 Scoop&#xff08;如果尚未安装&#xff09;&#xff1a;iwr -useb get.sco…...

citrix netscaler13.1 重写负载均衡响应头(基础版)

在 Citrix NetScaler 13.1 中&#xff0c;Rewrite Actions 用于对负载均衡响应进行修改&#xff0c;包括替换、删除和插入 HTTP 响应头。这些操作可以通过自定义策略来完成&#xff0c;帮助你根据需求调整请求内容。以下是三种常见的操作&#xff1a; 1. Replace (替换响应头)…...

使用PWM生成模式驱动BLDC三相无刷直流电机

引言 在 TI 的无刷直流 (BLDC) DRV8x 产品系列使用的栅极驱动器应用中&#xff0c;通常使用一些控制模式来切换MOSFET 开关的输出栅极。这些控制模式包括&#xff1a;1x、3x、6x 和独立脉宽调制 (PWM) 模式。   不过&#xff0c;DRV8x 产品系列&#xff08;例如 DRV8311&…...

常见的php框架有哪几个?

一直以来&#xff0c;PHP作为一种广泛使用的编程语言&#xff0c;拥有着许多优秀的框架来帮助开发人员快速构建稳定的Web应用程序。本文降为大家介绍几种常见的PHP的主流框架&#xff0c;以及它们相关的特点和使用场景。如有问题&#xff0c;欢迎指正&#xff01; 1.Laravel&a…...

机器学习(2):线性回归Python实现

1 概念回顾 1.1 模型假设 线性回归模型假设因变量y yy与自变量x xx之间的关系可以用以下线性方程表示&#xff1a; y β 0 β 1 ⋅ X 1 β 2 ⋅ X 2 … β n ⋅ X n ε y 是因变量 (待预测值)&#xff1b;X1, X2, ... Xn 是自变量&#xff08;特征&#xff09;β0, β1,…...

Unity-Mirror网络框架-从入门到精通之RigidbodyPhysics示例

文章目录 前言示例一、球体的基础配置二、三个球体的设置差异三、示例意图LatencySimulation前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开…...

【Unity-Animator】通过 StateMachineBehaviour 实现回调

StateMachineBehaviour 简介 StateMachineBehaviour是一个基类&#xff0c;所有状态脚本都派生自该类。它可以在状态机进入、退出或更新状态时执行代码&#xff0c;而无需编写自己的逻辑来测试和检测状态的变化。这使得开发者可以更方便地处理状态转换时的逻辑&#xff0c;例…...

并行服务、远程SSH无法下载conda,报错404

原下载代码无效&#xff0c;报错404 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.03-1-Linux-x86_64.sh 使用下面代码下载 wget --user-agent"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12…...

cuquantum 简介

1. 关于 cuquantum 概述 官方文档&#xff1a; https://docs.nvidia.com/cuda/cuquantum/latest/appliance/overview.html#prerequisites NVIDIA 的 cuQuantum 是一个专门用于量子计算的高性能库&#xff0c;旨在加速量子电路的模拟和量子算法的执行。cuQuantum 提供了一系列…...

小程序如何引入腾讯位置服务

小程序如何引入腾讯位置服务 1.添加服务 登录 微信公众平台 注意&#xff1a;小程序要企业版的 第三方服务 -> 服务 -> 开发者资源 -> 开通腾讯位置服务 在设置 -> 第三方设置 中可以看到开通的服务&#xff0c;如果没有就在插件管理中添加插件 2.腾讯位置服务…...

【react】使用antd Table渲染数据遇到的报错问题

记录自己在开发过程中遇到的报错问题&#xff1a; 目录 原本写法&#xff1a;错误分析&#xff1a;解决方案&#xff1a; 原本写法&#xff1a; render: (text) > {console.log(text, "111111text");console.log(typeof text, "111111text");return t…...

55_OpenResty开发入门

Nginx编程需要用到Lua语言,因此我们必须先学习Lua的基本语法。Nginx本身也是C语言开发,因此也允许基于Lua做拓展。多级缓存的实现离不开Nginx编程,而Nginx编程又离不开OpenResty。 1.OpenResty概述 OpenResty是一款基于NGINX和LuaJIT的Web平台。通过Lua扩展NGINX实现的可伸…...

(即插即用模块-Attention部分) 四十四、(ICIP 2022) HWA 半小波注意力

文章目录 1、Half Wavelet Attention2、代码实现 paper&#xff1a;HALFWAVELET ATTENTION ON M-NET FOR LOW-LIGHT IMAGE ENHANCEMENT Code&#xff1a;https://github.com/FanChiMao/HWMNet 1、Half Wavelet Attention 传统的图像增强方法主要关注图像在空间域的特征信息&am…...

链家房价数据爬虫和机器学习数据可视化预测

完整源码项目包获取→点击文章末尾名片&#xff01;...

全网首发:编译libssh,产生类似undefined reference to `EVP_aes_256_ctr@OPENSSL_1_1_0‘的大量错误

具体错误 前面和后面的&#xff1a; /opt/linux/x86-arm/aarch64-mix210-linux/host_bin/../lib/gcc/aarch64-linux-gnu/7.3.0/../../../../aarch64-linux-gnu/bin/ld: warning: libcrypto.so.1.1, needed by ../lib/libssh.so.4.10.1, not found (try using -rpath or -rpat…...

springboot 集成javaFx 两个面板之间如何进行跳转

1.创建两个面板 可参考博主的 java8 springboot 集成javaFx 实现一个客户端程序 文章来实现 2.完善代码 以下是博主创建的两个模板 博主在这里实现的是登录跳转功能,注意:这里登录按钮的触发实现方式做了以下小小的改动,也可根据自己的习惯来处理 相较第一篇文章,博主在Lo…...

vue-cli项目配置使用unocss

在了解使用了Unocss后&#xff0c;就完全被它迷住了。接手过的所有项目都配置使用了它&#xff0c;包括一些旧项目&#xff0c;也跟同事分享了使用Unocss的便捷性。 这里分享一下旧项目如何配置和使用Unocss的&#xff0c;项目是vue2vue-cli构建的&#xff0c;node<20平常开…...

ASP.NET Core - IStartupFilter 与 IHostingStartup

ASP.NET Core - IStartupFilter 与 IHostingStartup 1. IStartupFilter2 IHostingStartup2.5.1 创建外部程序集2.5.2 激活外部程序集 1. IStartupFilter 上面讲到的方式虽然能够根据不同环境将Startup中的启动逻辑进行分离&#xff0c;但是有些时候我们还会可以根据应用中的功能…...

学习ASP.NET Core的身份认证(基于JwtBearer的身份认证5)

用户在前端页面登录成功后会从服务端获取Token&#xff0c;后续调用服务器的服务接口时都得带着Token&#xff0c;否则就会验证失败。之前使用postman测试的时候&#xff0c;获取Token后再调用其它服务都是人工将Token添加到Header中&#xff0c;网页中没法这么做&#xff0c;只…...

【Vue】let、const、var的区别、适用场景

let、const、var&#xff0c;有哪些区别&#xff0c;适用场景 var 特点&#xff1a; var 是 JavaScript 中最传统的变量声明方式。具有函数作用域&#xff0c;即在函数内声明的 var 变量&#xff0c;在整个函数内都可以访问。变量提升&#xff1a;使用 var 声明的变量会被提升…...

【llama_factory】qwen2_vl训练与批量推理

训练llama factory配置文件 文件&#xff1a;examples/train_lora/qwen2vl_lora_sft.yaml ### model model_name_or_path: qwen2_vl/model_72b trust_remote_code: true### method stage: sft do_train: true finetuning_type: lora lora_target: all### dataset dataset: ca…...