Linux网络编程
Posted qifeng1024
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux网络编程相关的知识,希望对你有一定的参考价值。
在学习网络编程之前,先了解一下OSI模型,以及TCP/IP协议和一些基础的知识
OSI模型(Open System Interconnection model 开放系统互联模型)
这是一个理想化的模型,实际上的TCP/IP协议跟这个模型还不太一样。
分别简单的理解一下这七层模型的意思
物理层:以二进制数据形式在物理媒体上传输数据,也就是最底层的硬件。
比如各种接口 RS-232 RJ-45 都属于该层
数据链路层:通过物理网络链路提供数据传输,可以理解为硬件和硬件之间的通信
比如IIC SPI就是属于该层
网络层:负责在源和终点之间建立连接,一般包括网络寻径,选择路由
传输层:提供端对端的网络数据流服务。后面将提到的TCP/IP协议也是属于这两层
会话层:解除或建立与别的接点的联系
表示层:提供多种功能用于应用层数据编码和转化,以确保应用层发送的消息能被其他人识别
包括数据格式转化和加密 压缩。
应用层:这里的应用层并非我们pc上所使用的软件,而是向应用服务提供网络资源的API
在TCP/IP协议中,并没有完全照般OSI模型,而是对他进行了整合和拆分
一般我们使用的是一个比较通用的四层的模型
和刚才的模型对比一下:
在实际使用中,我们把他分为:应用层、传输层、网络层、和网络接口层(硬件层)
网络接口层:提供TCP/IP协议的数据结构和实际的硬件之间的接口
网络层:IP协议、RIP协议,负责数据包装 寻址和路由
传输层:TCP可靠的数据流运输服务 UDP不可靠的数据报服务
应用层:FTP文件传输协议、HTTP超文本传输协议、Telent远程终端协议、等
IP地址
Internet Protocol Address 互联网协议地址
每台联网的设备都有一个IP地址,IP地址是一个32位数,常被分成4个4字节的数
ip地址被分为下面几类:
a.b.c.d 的形式,其中abcd都是 0-255的整数
那么问题就来了,一串这样的整数,早晚有一天会用完,毕竟255*255*255*255 = 4228250625
40亿,且不说因为格式等方面的问题,实际分配出去不足40亿。。
光是目前的手机电脑等能联网的设备,也肯定超出了40亿了。
而事实上在2011年IPV4的地址就已经用尽了。
为了解决这个问题,就诞生了IPV6。
IPV6也就是第六版的互联网协议。其地址长度为128位,比32位的IPV4拥有更多的可分配资源。
我们可以使用 ifconfig 查看机器的IP地址
端口号
前面说的IP地址是你计算机的地址,你一台计算机里面肯定运行了很多程序。
每个应用程序就对应了不同的端口号
同时制定了正确的IP地址和端口号,才能准确的发送数据
UNIX操作系统因具有运行稳定、系统要求低、安全性高,而得到广泛应用。其伯克利套接字,发展较早,具有鲜明特点,例如:UNIX系统有保留端口号的概念。只有具有超级用户特权的进程才允许给它自己分配一个保留端口号,这些端口号介于1~1023之间,一些应用程序将它作为客户与服务器之间身份认证的一部分。大多数TCP/IP实现给临时端口分配1024~5000之间的端口号。大于5000的端口与是为其他服务器预留的(Internet上并不常用的服务) 。
TCP、UDP协议
TCP Transmission Control Protocol 传输控制协议
UDP User Datagram Protocol 用户数据报协议
TCP和UDP都可以使用IPV4或IPV6。
UDP不保证数据包会到达目的地,不保证数据先后顺序跨网络之后保持不变,也不保证只到达一次。
TCP也不能保证发送的数据一定会被对方端接收,但是他会不断的重试。
TCP在连接时需要进行三次握手,前面的博客有动图演示讲解
形象一点说,就是这样一个过程:
1、屌丝(客户端)处于自闭状态,女神(服务器)处于等待状态
2、屌丝问女神”我要跟你处对象,是否同意“,同时屌丝变成发送状态
3、女神收到消息,回复屌丝“我同意,那么我要跟你处对象,你是否同意?”,然后变为接收状态
4、屌丝收到消息,变为“恋爱状态”,回复女神“我同意,开始处对象吧”
5、女神收到消息,也变为恋爱状态,于是开始了一段不可描述的故事。。。。
有一天。。。他们要分手了。。
1、屌丝付出了自己所有的爱,然后跟女神说“我要跟你分手”,并把自己变为等待状态
2、女神收到爱和消息,回复“同意分手”,然后又把自己所有的爱给了屌丝,又一次确认“我要和你分手”
3、屌丝收到爱和消息,回复“同意分手”,后进入自闭状态。
4、女神收到应答,也进入自闭状态。。。
上面例子中用用下划线标注出来的,就是建立连接的三次握手和数据发送完成后的四次挥手。
下面终于进入了网络编程的正题:套接字API的使用
创建套接字
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol); domain: Name Purpose Man page AF_UNIX, AF_LOCAL Local communication unix(7) AF_INET IPv4 Internet protocols ip(7) AF_INET6 IPv6 Internet protocols ipv6(7) AF_IPX IPX - Novell protocols AF_NETLINK Kernel user interface device netlink(7) AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7) AF_AX25 Amateur radio AX.25 protocol AF_ATMPVC Access to raw ATM PVCs AF_APPLETALK AppleTalk ddp(7) AF_PACKET Low level packet interface packet(7) AF_ALG Interface to kernel crypto API protocol: SOCK_STREAM TCP SOCK_DGRAM UDP SOCK_SEQPACKET 为最大长度固定的数据报提供有序、可靠、基于双向连接的数据传输路径 SOCK_RAW 原始套接字 SOCK_RDM 提供不保证排序的可靠数据报层。
成功返回非负的套接字描述符
失败返回 -1
绑定套接字和服务器地址
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); sockfd 套接字文件描述符 addr 服务器地址信息 struct sockaddr { sa_family_t sa_family; char sa_data[14]; } 但实际使用中对于IPV4我们常用这个结构 struct sockaddr_in { sa_family_t sin_family; IPV4对应AF_INET u_int16_t sin_port; 端口号 struct in_addr sin_addr; IP地址 }; /* Internet address. */ struct in_addr { u_int32_t s_addr; IP地址 }; addrlen addr的长度 sizeof(struct sockaddr)
成功返回 0 失败返回 -1
主要用与在TCP中的连接
监听模式
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int listen(int sockfd, int backlog); sockfd 套接字文件描述符 backlog 监听队列长度(等待连接的客户端的个数)缺省值20
等待客户端连接
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); sockfd 服务器套接字文件描述符 addr 客户端信息地址 addrlen addr的长度
成功返回连接的客户端的套接字文件描述符
失败返回 -1
接收数据
#include <sys/types.h> #include <sys/socket.h> ssize_t recv(int sockfd, void *buf, size_t len, int flags); //告诉调用者是谁发来的数据 ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); //无连接的套接字 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); sockfd 套接字文件描述符 buf 存放接收的数据 len 期望接收的数据长度 flags 0 src_addr 源机的IP地址端口号 addrlen addr的长度 msg struct iovec { /* Scatter/gather array items */ void *iov_base; /* Starting address */ size_t iov_len; /* Number of bytes to transfer */ }; struct msghdr { void *msg_name; /* optional address */ socklen_t msg_namelen; /* size of address */ struct iovec *msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data, see below */ size_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags on received message */ };
成功返回接到数据的实际长度,失败返回 -1
recvfrom() 在参数中添加了源机的地址返回,可以得到是从哪里接收到的数据地址信息。
如果把此函数的第五个参数置空NULL,则和recv() 函数相同
发送数据
#include <sys/types.h> #include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
send函数参数和recv完全一致,此处不再赘述。
成功返回发送数据的实际长度,失败返回 -1
sendto() 指定地址发送数据,
sendto() recvfrom() 主要用于UDP的连接
客户端连接服务器
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数为服务器地址信息
成功返回 0 失败返回 -1
connect() 函数不阻塞,所以在使用之前要确保服务器已经进入等待连接状态。
使用TCP协议的流程图:
UDP协议流程图:
以上是关于Linux网络编程的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装