linux高级编程(OSI/UDP(用户数据报))

OSI七层模型:

OSI 模型 --> 开放系统互联模型 --> 分为7层:

理想模型 --> 尚未实现

1.应用层 QQ

应用程序的接口

2.表示层 加密解密 gzip

将接收的数据进行解释(机器->人)

3.会话层 网络断开,连接状态,keep-close keep-alive

通信双方管理会话

4.传输层:tcp udp 协议 文件 视频,音频

(传数据)

5.网络层ip NAT

实现数据从源经过多条链路到目的地的转发(找主机)

6.链路层 交换机 数据的格式化 帧 校验

将电信号封装,建立数据链路,实现点对点数据传输

7.物理层:100Mb/8 Gbits 100MB 同轴电缆 10Gb 2.4G 5G

可通过物理介质传播的电信号

TCP/IP模型:

TCP/IP模型 --> 网际互联模型 --> 分为4层:

实用模型 --> 工业标准

1.应用层 ---> 应用程序(用户与应用程序的接口)(会话层+表示层+应用层)

2.传输层 ---> 端口号tcp udp (传数据)

3.网络层 ---> IP 地址(找主机)

4.接口层 ---> 网卡 驱动 1GB(连结互联网的基础设施)(物理层+链路层)

网络基础

IP地址 = 网络位 + 主机位

010 3333344444

IP地址的分类: 点分十进制 ipv4(4字节(32位)数据,42亿个地址,已耗尽)

ipv6(16字节(128位)数据,地址很多,未耗尽

A类: 超大规模性网络

8 8 8 8

1.0.0.0 - 126.255.255.255 126.1.1.1

126.1.1.2

255.0.0.0

私有:

10.0.0.0 - 10.255.255.255

127.0.0.1

B类: 大中规模型网络

128.0.0.0 - 191.255.255.255

128.2.1.2 128.2.7.2

255.255.0.0

私有:

172.16.0.0 - 172.31.255.255

C类: 中小规模型网络

192.0.0.0 - 223.255.255.255

255.255.255.0

私有:

192.168.0.0 - 192.168.255.255

静态路由

192.168.0.0

192.168.0.1 网关

192.168.0.255

D类: 组播和广播(广播:所有用户都能传播,组播:某个小范围组内能传播)

(无子网掩码)

224.0.0.0 - 239.255.255.255

192.168.0.255 == 255.255.255.255

235.1.2.3

192.168.1.0

192.168.0.1 网关

192.168.1.255 广播

E类: 实验

(无子网掩码)

240.0.0.0 - 255.255.255.255

子网掩码:1代表网络部分,0代表主机部分

C 类网络:

ip地址的前三组是网络地址,第四组是主机地址。

二进制的最高位必须是: 110xxxxx开头

十进制表示范围: 192.0.0.0 -223.255.255.255

默认网络掩码: 255.255.255.0

网络个数: 2^24 个 约 209 万个

主机个数: 2^8 个 254 个+2 --> 1个是网关(网络地址.0 的下一个地址.1) 另1个是广播(.255最后一个地址)

私有地址: 192.168.x.x 局域网地址。

网络接口(端口+ip --> 找到进程+找到主机)

1、socket 套接字 --> BSD socket --> 用于网络通信的一组接口函数。socket api application interface --> 进程到进程 --> 实现主机到主机通信

2、ip+port 地址+端口 --> 地址用来识别主机

端口用来识别应用程序

port分为TCP port / UDP port 范围都是: 1-65535(2^16,两个byte)

约定1000 以内的端口为系统使用。

网络字节序

--> 大端排序(高位数据放在高地址处)(高地址:值较大的地址)

--> 主机 --> 小端(高位数据放在低地址处)(从小往大走)

数字转换函数:

#include <arpa/inet.h>

主机转网络:uint32_t htonl(uint32_t hostlong);

ipv4 192.168.0.1 1~65535

uint16_t htons(uint16_t hostshort);

网络转主机:host to net long

net to host

uint32_t ntohl(uint32_t netlong); //对应16位转换与32位转换

uint16_t ntohs(uint16_t netshort);

主机转网络:in_addr_t inet_addr(const char *cp);

inet_addr("192.168.1.20");

网络转主机:char *inet_ntoa(struct in_addr in);

字符串转换函数:

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

主机转网络:in_addr_t inet_addr(const char *cp);

cli.sin_addr

inet_addr("192.168.1.20");

网络转主机:char *inet_ntoa(struct in_addr in);

收发数据(UDP)

UDP:半双工,同一时刻要么收要么发

1、模式 C/S 模式 --> 服务器/客户端模型(client/server)

server:socket() ===>bind()===>recvfrom()===>close()

client:socket() ===>bind()===>sendto() ===>close()

socket()

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

功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain 地址族,PF_INET(协议族) == AF_INET(地址族,IPv4) ==>互联网程序

PF_UNIX == AF_UNIX ==>单机程序

type 套接字类型:

SOCK_STREAM 流式套接字 ===》TCP

SOCK_DGRAM 用户数据报套接字===>UDP

SOCK_RAW 原始套接字 ===》IP

protocol 协议 --> 0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id

失败 -1;

bind()

2、int bind(int sockfd, struct sockaddr *my_addr,

socklen_t addrlen);

功能:如果该函数在服务器端调用,则表示将参数1相关

的文件描述符文件与参数2 指定的接口地址关联,

用于从该接口接受数据。

如果该函数在客户端调用,则表示要将数据从

参数1所在的描述符中取出并从参数2所在的接口

设备上发送出去。

注意:如果是客户端,则该函数可以省略,由默认

接口发送数据。

参数:sockfd 之前通过socket函数创建的文件描述符,套接字id

my_addr 是物理接口的结构体指针。表示该接口的信息。

struct sockaddr 通用地址结构

{

u_short sa_family; 地址族

char sa_data[14]; 地址信息

};

转换成网络地址结构如下:

struct _sockaddr_in ///网络地址结构

{

u_short sin_family; 地址族

u_short sin_port; ///地址端口

struct in_addr sin_addr; ///地址IP

char sin_zero[8]; 占位

};

struct in_addr

{

in_addr_t s_addr;

}

socklen_t addrlen: 参数2 的长度。

返回值:成功 0

失败 -1;

bind传参要进行强转,在实际使用中,struct sockaddr过于底层,不方便处理,而struct sockaddr_in专门用于IPv4地址,所以一般用struct sockaddr_in来定义

#typedef struct sockaddr * (SA);

struct sockaddr_in ser;
int ret = bind(sockfd,(SA)&ser,sizeof(ser));

一般bind的操作为:

struct sockaddr_in ser,cli;
bzero(&ser,sizeof(ser));
bzero(&cli,sizeof(cli));
// 大小端转化 host to net short 
ser.sin_port = htons(50000);
ser.sin_addr.s_addr = inet_addr("192.168.203.128");
int ret = bind(sockfd,(SA)&ser,sizeof(ser));
if(-1 == ret)
{
    perror("bind");
    exit(1);
}

接收函数/发送函数

发送函数:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

const struct sockaddr *dest_addr, socklen_t addrlen);

功能:用于UDP协议中向对方发送数据。

参数:sockfd 本地的套接字id

buff 本地的数据存储,一般是要发送的数据。

len 要发送的数据长度

flags 要发送数据方式,0 表示阻塞发送。

dest_addr: 必选,表示要发送到的目标主机信息结构体。

addrlen :目标地址长度。

返回值:成功 发送的数据长度

失败 -1;

接收函数:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

功能:用于UDP协议中获取对方发送的数据。

参数:sockfd 本地的套接字id

buff 要存储数据的内存区,一般是数组或者动态内存。

len 要获取的数据长度,一般是buff的大小。

flags 获取方式,0 阻塞

src_addr 可选,表示对方的地址信息结构体,

如果为NULL,表示不关心对方地址。(一般在用户端中,因为服务器地址一般默认

是已知恒定的,用户端是未知多变的,就是要

在服务端变量初始化中写入服务器的地址)

addrlen 对方地址信息结构体大小。

如果对方地址是NULL,则该值也为NULL。

返回值:成功 接收到的数据长度

失败 -1;

close()

5、close() ===>关闭指定的套接字id;

注意事项:

sendto与recvfrom都写的是对方的sockaddr_in结构体

服务器:

一般需要定义两个结构体,因为服务器需要知道客户端的ip

struct sockaddr_in ser,cli;

需要先接收客户端的地址(recvfrom),不然无法发送数据

typedef struct sockaddr *(SA);
socklen_t cli=sizeof(cli);
recvfrom(sockfd,buf_r,sizeof(buf_r),0,(SA)&cli,len_cli);

客户端:

一般不需要定义自己的sockadr_in结构体,且recv时可以写NULL

struct sockaddr_in ser;
recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);

需要空发一下让服务器拿到(对于收发先后没有太大要求,recvfrom具有读阻塞的作用)

char buf[128];
sendto(sockfd,buf,sizeof(buf),0,(SA)&ser,sizeof(ser));

客户端recvfrom不需要最后两个参数可以是NULL,因为本来就有父进程的端口号和ip

 recvfrom(sockfd,buf_r,sizeof(buf_r),0,NULL,NULL);
相关推荐
Tassel_YUE1 小时前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
hjjdebug1 小时前
linux 下 signal() 函数的用法,信号类型在哪里定义的?
linux·signal
其乐无涯1 小时前
服务器技术(一)--Linux基础入门
linux·运维·服务器
Diamond技术流1 小时前
从0开始学习Linux——网络配置
linux·运维·网络·学习·安全·centos
斑布斑布1 小时前
【linux学习2】linux基本命令行操作总结
linux·运维·服务器·学习
Spring_java_gg2 小时前
如何抵御 Linux 服务器黑客威胁和攻击
linux·服务器·网络·安全·web安全
✿ ༺ ོIT技术༻2 小时前
Linux:认识文件系统
linux·运维·服务器
会掉头发2 小时前
Linux进程通信之共享内存
linux·运维·共享内存·进程通信
我言秋日胜春朝★2 小时前
【Linux】冯诺依曼体系、再谈操作系统
linux·运维·服务器