网络编程基础

1. 网络发展背景

独立模式
早期计算机独立工作,无法实现信息共享,是计算机网络发展的萌芽阶段。

网络互联
随着计算机数量的增加,迫切需要一种方式将它们连接在一起,实现数据共享。这标志着计算机网络的初步形成。

局域网(LAN)与广域网(WAN)
随着技术的进步,局域网和广域网的概念应运而生。局域网通过交换机和路由器连接多台计算机,而广域网则将地理位置相隔较远的计算机连接在一起。

2. 网络协议初识

协议 是计算机网络中的一种重要约定,用于规定通信双方的数据格式、传输方式以及其他必要信息。协议的制定使得不同设备能够协同工作,实现数据的有序传输。
在这里插入图片描述

协议分层
为了更好地管理和维护网络协议,人们引入了分层设计的思想。这种分层模型有助于提高系统的可扩展性和可维护性。

OSI七层模型
OSI七层模型为网络协议提供了一种清晰的框架,将网络分为七个层次,每个层次负责特定的功能。然而,由于其复杂性,实际应用中并不普遍。

TCP/IP五层模型
TCP/IP是最为广泛使用的网络协议簇,采用五层模型,包括物理层、数据链路层、网络层、传输层和应用层。这种模型更为实用,是当前网络通信的基础。

3. 网络传输流程

在这里插入图片描述

网络传输流程图
通过网络传输分为同一网段内和跨网段的两种情况。数据在传输过程中经过不同层次的协议,通过封装和分用实现端到端的通信。

数据包封装和分用
在传输过程中,不同协议层对数据包有不同的称谓,如在传输层称为“段”、在网络层称为“数据报”、在链路层称为“帧”。数据在传输过程中通过封装和分用完成各层之间的交互。

认识IP地址
IP地址是用来标识网络中不同主机的地址。IPv4是32位的整数,通常以点分十进制表示。IPv6是IP协议的新版本,为网络提供更多的地址空间。

认识MAC地址
MAC地址用于识别数据链路层中相连的节点,长度为48位。它在网卡出厂时确定,通常是唯一的。MAC地址是数据链路层的硬件地址,与IP地址不同。

4. sockaddr结构

struct sockaddr 和其派生的具体地址结构(例如 struct sockaddr_instruct sockaddr_un)用于在网络编程中表示不同类型的地址。

struct sockaddr 是一个通用的结构体,用于表示各种类型的套接字地址。

struct sockaddr {
    sa_family_t sa_family;  // 地址族,通常是 AF_INET 或 AF_UNIX
    char sa_data[14];       // 具体的地址信息,大小为 14 字节
};

sa_family: 字段表示地址的协议族,通常是 AF_INET(IPv4)或 AF_UNIX(UNIX 域套接字)。
sa_data: 字段包含了具体的地址信息,大小为 14 字节。具体的协议族和地址信息的存储方式依赖于 sa_family 字段。

struct sockaddr_in 是用于表示 IPv4 地址的具体结构体。

struct sockaddr_in {
    sa_family_t sin_family;  // 地址族,始终为 AF_INET
    in_port_t sin_port;      // 16 位端口号,网络字节序
    struct in_addr sin_addr; // IPv4 地址结构
    char sin_zero[8];        // 用于填充,保持结构大小与 sockaddr 一致
};

struct in_addr {
    in_addr_t s_addr; // IPv4 地址,32 位无符号整数,通常使用网络字节序存储
};

sin_family: 始终为 AF_INET,表示 IPv4 地址。
sin_port: 是 16位端口号,使用网络字节序(big-endian)存储。
in_addr: 是一个 struct in_addr 结构,表示 IPv4 地址。
sin_zero: 是用于填充,以保持结构大小与 struct sockaddr 一致。

struct sockaddr_un 是用于表示 UNIX 域套接字地址的具体结构体。

#define UNIX_PATH_MAX 108

struct sockaddr_un {
    sa_family_t sun_family;        // 地址族,始终为 AF_UNIX
    char sun_path[UNIX_PATH_MAX];  // 路径名
};

sun_family 始终为 AF_UNIX,表示 UNIX 域套接字。
sun_path 包含了套接字文件的路径名,长度受限于UNIX_PATH_MAX
在这里插入图片描述

sa_family 字段是这三个结构体中的一个共同成员,用于指示地址族或协议族。这个字段表示了套接字地址的类型,以便在处理套接字地址时正确地解释其余的结构体字段。以下是各结构体中的 sa_family 字段的关系:

struct sockaddr:

struct sockaddr 是一个通用结构体,其中的 sa_family 字段表示地址族。 不同的 sa_family
值对应不同的协议族或地址类型
。例如,AF_INET 表示 IPv4 地址,AF_INET6 表示 IPv6 地址,AF_UNIX 表示
UNIX 域套接字地址等。

struct sockaddr_in:

struct sockaddr_instruct sockaddr 的一个具体实现,用于表示 IPv4 地址。 sin_family字段表示地址族,它设置为 AF_INET,表示 IPv4 地址。

struct sockaddr_un:
sockaddr_unstruct sockaddr 的另一个具体实现,用于表示UNIX 域套接字地址。 sun_family 字段表示地址族,它始终为 AF_UNIX,表示 UNIX 域套接字。

5. sockaddr_in结构体详解

在网络编程中,sockaddr_in 结构体是一个关键的数据结构,用于表示 IPv4 地址和端口号。该结构体在套接字编程中扮演着重要的角色,用于指定网络通信的终端地址。

struct sockaddr_in {
    sa_family_t sin_family;  // 地址族,始终为 AF_INET
    in_port_t sin_port;      // 16 位端口号,网络字节序
    struct in_addr sin_addr; // IPv4 地址结构
    char sin_zero[8];        // 用于填充,保持结构大小与 sockaddr 一致
};

struct in_addr {
    in_addr_t s_addr; // IPv4 地址,32 位无符号整数,通常使用网络字节序存储
};
  1. 设置地址族为IPv4
struct sockaddr_in server_addr; // 创建sockaddr_in结构体
bzero(&server_addr, sizeof(server_addr)); // 清零结构体
server_addr.sin_family = AF_INET;
  1. 设置端口号
uint16_t port = 8080;
server_addr.sin_port = htons(port);

端口号需要以网络字节序的形式传输。
网络字节序是一种用于确保不同计算机之间数据传输一致性的规范,特别针对不同字节序(大端序或小端序)的计算机。在网络通信中,使用网络字节序有助于正确解析传输的数据。

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); //将32位整数从主机字节序转换为网络字节序。
uint16_t htons(uint16_t hostshort);//将16位短整数从主机字节序转换为网络字节序。
uint32_t ntohl(uint32_t netlong);//将32位整数从网络字节序转换为主机字节序。
uint16_t ntohs(uint16_t netshort);//将16位短整数从网络字节序转换为主机字节序。
  1. 设置IP地址
const char* ip_str = "192.168.0.1";
inet_pton(AF_INET, ip_str, &(server_addr.sin_addr);

使用 inet_pton 函数将 IP 地址字符串转换为网络字节序的二进制形式,并设置到 sin_addr 字段中。这确保了在网络通信中正确解释 IP 地址。

#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);

参数说明:
af:地址族(Address Family),可以是 AF_INET(IPv4)或 AF_INET6(IPv6)。
src:待转换的 IP 地址字符串。
dst:转换后的二进制形式存储的目标内存空间。
返回值:
若成功转换,则返回 1。
若地址族无效或转换失败,则返回 0。
若发生错误,返回 -1,并设置 errno。

6. 网络编程接口

  1. socket() 函数用于创建一个套接字,为后续的网络通信提供文件描述符
#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

参数:

domain:指定套接字使用的协议族,可以是 AF_INET(IPv4)、AF_INET6(IPv6)、AF_UNIX(UNIX域套接字)等。
type:指定套接字的类型,可以是 SOCK_STREAM(流套接字,用于 TCP)或
SOCK_DGRAM(数据报套接字,用于 UDP)等。
protocol:指定使用的传输协议,一般为 0,表示使用默认协议。
返回值
如果成功,返回一个非负整数,表示套接字文件描述符
如果失败,返回 -1,表示发生错误。

  1. 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: 表示地址结构体的长度。
返回值:
如果成功,返回 0。
如果失败,返回 -1,表示发生错误。

  1. sendto() 函数用于通过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);

参数:
sockfd 是套接字文件描述符。
buf 是要发送的数据缓冲区的指针。
len 是要发送的数据长度。
flags 允许设置一些标志,一般可以设置为0。
dest_addr 是目标地址的 struct sockaddr 结构体指针,包含了目标地址和端口信息
addrlen 表示目标地址结构体的长度。
返回值:
如果成功,返回发送的字节数。
如果失败,返回 -1,表示发生错误。

  1. recvfrom() 函数用于通过UDP协议从指定的地址和端口接收数据
#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 允许设置一些标志,一般可以设置为0。
src_addr 是发送端地址的 struct sockaddr 结构体指针,用于存储发送端的地址信息
addrlen 是一个指向整数的指针,用于存储 src_addr 结构体的长度。
返回值:
如果成功,返回接收的字节数。
如果失败,返回 -1,表示发生错误。

  1. listen() 函数用于TCP协议将套接字标记为被动套接字,即用于监听连接。
#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);

参数:
sockfd:套接字文件描述符,通常是通过 socket() 创建的监听套接字。
backlog:在连接队列中允许的未完成连接的最大数量。这指定了服务器愿意排队等待接受连接的客户端的最大数量。
返回值:
如果成功,返回 0。
如果失败,返回 -1,错误码存储在 errno 中。

  1. accept() 函数用于TCP协议接受客户端连接请求。它从未完成连接队列中取出一个连接请求,创建一个新的套接字用于与客户端通信,并返回这个新套接字的文件描述符。
#include <sys/types.h>
#include <sys/socket.h>

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

参数:

sockfd:被监听的套接字文件描述符。
addr:指向 struct sockaddr 结构体的指针,用于存储客户端的地址信息
addrlen:指向整数的指针,用于存储 addr 结构体的长度。
返回值:
如果成功,返回一个新的连接套接字文件描述符,用于与客户端通信
如果失败,返回 -1,错误码存储在 errno 中。

  1. connect() 函数用于在 TCP 协议中建立与服务器的连接。
#include <sys/types.h>
#include <sys/socket.h>

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

参数:
sockfd:套接字文件描述符,通常是通过 socket() 创建的套接字。
addr:指向 struct sockaddr 结构体的指针,包含了要连接的目标地址信息。
addrlenaddr 结构体的长度。
返回值:
如果成功,返回 0。
如果失败,返回 -1,错误码存储在 errno 中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值