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

【C语言教程】【常用类库】(十五)网络编程 - <sys/socket.h> 和 <netinet/in.h>

15. 网络编程 - <sys/socket.h><netinet/in.h>

网络编程在C语言中是通过套接字来实现的,套接字提供了进程间通信的端点。C语言的网络编程涉及到创建套接字、绑定地址、监听和接收数据。以下是网络编程的关键概念和基本实现方法。

15.1. 套接字基础
15.1.1. 套接字类型与协议

套接字是网络通信的基础,它分为不同的类型和协议:

  • 套接字类型

    • 流套接字(SOCK_STREAM:基于TCP协议,提供可靠的双向字节流通信。
    • 数据报套接字(SOCK_DGRAM:基于UDP协议,无连接,面向消息,通信时不保证消息顺序和完整性。
  • 协议

    • TCP(传输控制协议):提供可靠、有序的字节流服务,比如HTTP。
    • UDP(用户数据报协议):提供较低效能的、不可靠的数据报服务,比如DNS查询。
15.1.2. 创建和绑定套接字:socket, bind

创建套接字并绑定到指定IP和端口是建立网络服务的基础步骤。

  • socket 函数:用于创建一个新的套接字。

    int socket(int domain, int type, int protocol);
    
    • domain:地址族,一般为 AF_INET(IPv4)或 AF_INET6(IPv6)。
    • type:套接字类型,如 SOCK_STREAM(TCP)或 SOCK_DGRAM(UDP)。
    • protocol:通常设为 0,自动匹配。
  • bind 函数:将套接字与特定IP地址和端口绑定。

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • sockfd:由 socket 返回的文件描述符。
    • addr:IP地址和端口信息结构体,通常为 struct sockaddr_in
    • addrlen:地址结构体的长度。
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>int main() {int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字 [1]struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr)); // 清零server_addr.sin_family = AF_INET; // IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // 任意可用的接口server_addr.sin_port = htons(8080); // 绑定端口8080bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 绑定套接字 [2]return 0;
}
  • [1]创建套接字:使用 socket 函数创建TCP套接字。IPv4地址AF_INET,流套接字类型。
  • [2]绑定套接字bind 函数将创建的套接字绑定到结构体中指定的IP地址和端口上。
15.2. 客户端与服务器模型
15.2.1. TCP 服务器:listen, accept

在创建并绑定了套接字后,服务器需要监听连接和接受请求。

  • listen 函数:将套接字设置为被动监听状态。

    int listen(int sockfd, int backlog);
    
    • sockfd:套接字描述符。
    • backlog:等待连接队列的最大长度。
  • accept 函数:从连接队列中取出一个连接请求。

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    
    • sockfd:监听中的套接字。
    • addr:客户机的IP地址和端口信息。
    • addrlen:用户提供的地址结构的大小。
listen(sockfd, 5); // 开始监听 [3]
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); // 接受连接 [4]
  • [3]监听连接listen 将套接字置为监听状态。
  • [4]接受连接accept 从队列中取出一个连接。
15.2.2. TCP 客户端:connect

客户端需要连接到服务端的指定地址和端口。

  • connect 函数:用于连接到服务端。
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • sockfd:套接字描述符。
    • addr:服务端的 IP 地址和端口信息。
    • addrlen:服务器地址信息的结构体大小。
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr)); // 清空地址
server_addr.sin_family = AF_INET; // IPv4
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); // IP 地址 [5]
server_addr.sin_port = htons(8080); // 目标端口
connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 发起连接请求 [6]
  • [5]设置地址:使用 inet_pton 设置目标服务的 IP。
  • [6]发起连接请求connect 连接到指定服务器。
15.2.3. 数据传输:send, recv

一旦连接建立,服务端和客户端之间就可以通过以下函数进行数据传输。

  • send 函数:用于发送数据。

    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    
    • sockfd:套接字描述符。
    • buf:要发送的缓冲区。
    • len:缓冲区长度。
    • flags:传输标志,通常设置为0
  • recv 函数:用于接收数据。

    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    

    用法与 send 类似。

char buffer[1024];
send(client_sockfd, "Hello, World!", 13, 0); // 发送信息 [7]
recv(client_sockfd, buffer, sizeof(buffer), 0); // 接收信息 [8]
  • [7]发送信息:使用 send 传输数据。
  • [8]接收信息:使用 recv 接收数据。
15.3. 高级套接字编程
15.3.1. 多路复用:select, poll

多路复用允许程序在一个线程中监视多个文件描述符上的事件。

  • select 函数:用于监视多个文件描述符。

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    
  • poll 函数:与 select 相似,使用 pollfd 结构体数组。

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);
    
15.3.2. UDP 套接字编程

UDP 套接字不需要连接,可以直接使用 sendtorecvfrom

  • sendto 函数:用于发送UDP数据包。

    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
    
  • recvfrom 函数:用于接收UDP数据包。

    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
    
char udp_buffer[1024];
struct sockaddr_in dest_addr;
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
inet_pton(AF_INET, "192.168.1.1", &dest_addr.sin_addr);
dest_addr.sin_port = htons(9090);
sendto(sockfd, "UDP message", 11, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); // 发送UDP [9]
recvfrom(sockfd, udp_buffer, sizeof(udp_buffer), 0, NULL, NULL); // 接收UDP [10]
  • [9]发送UDP: 使用 sendto 发出数据。
  • [10]接收UDP: 使用 recvfrom 接收UDP数据。

通过这些概念和代码示例,你可以开始进行C语言的网络编程,创建基本的网络应用程序。无论是客户端还是服务器端处理,正确使用这些网络编程API是至关重要的。

http://www.lryc.cn/news/461763.html

相关文章:

  • 正点原子讲解SPI学习,驱动编程NOR FLASH实战
  • 低代码开发助力中小企业数字化转型难度持续降低
  • 【Linux】:线程控制
  • 大数据-174 Elasticsearch Query DSL - 全文检索 full-text query 匹配、短语、多字段 详细操作
  • Spring Boot视频网站:构建可扩展的视频服务平台
  • 护眼台灯横评:书客、柏曼、明基哪款使用体验好,又能护眼?
  • RDMA笔记
  • Collection 单列集合 List Set
  • LabVIEW提高开发效率技巧----跨平台开发
  • 创建uniCloud新项目并且是新服务空间,运行会报Error: Invalid uni-id config file错误
  • 七、IPD 方法论框架(IPD的组织架构)
  • iPad mini 7惨遭暗砍一刀
  • 【计算机网络 - 基础问题】每日 3 题(三十六)
  • Docker镜像
  • Golang | Leetcode Golang题解之第478题在圆内随机生成点
  • 菜鸟笔记006 截图识别文字插件 textOCR
  • MySQL【知识改变命运】07
  • Matlab自学笔记三十八:日期时间序列的创建方法
  • fiber的原理
  • 重塑输电线路运维管理,巡检管理系统守护电网稳定运行
  • 各种排序方法总结
  • 【工欲善其事】巧用 PowerShell 自动清除复制 PDF 文本时夹杂的换行符号
  • Maven与Gradle的区别
  • 【linux 多进程并发】0202 Linux进程fork之后父子进程间的文件操作有着相同的偏移记录,多进程操作文件的方法
  • SQLite在安卓中的应用
  • Python数据库操作
  • 交叉熵损失函数为代表的两层神经网络的反向传播量化求导计算公式
  • 数据结构——八大排序(上)
  • vxe-table 导入导出功能全解析
  • 常用STL的操作以及特点