基于linux的网络编程
Linux进程间通信方式:
无名管道 有名管道 信号通信 共享内存 消息队列 信号灯集
Socket
文件IO和标准IO的区别?
来源 缓存 可移植 fd FILE*
linux高级编程–》IO 进程线程 网络编程
Linux vxworks freeRTOS rt-thread ucos-ii winCE …
1 网络体系结构
定义:是指网络的分层模型和每层所使用的协议的集合
有两种网络体系结构:OSI和TCP/IP
OSI七层模型:应用层 表示层 会话层 传输层 网络层 数据链路层 物理层–》理想化的模型
TCP/IP四层模型:应用层 传输层 网络层 物理层
—》实际使用
对于以上两种模型来说,除了物理层没有协议,其他各 层都有对应的协议去完成该层相应的功能。
2 IP地址
IP地址: 在网络中唯一标识一台主机的符号
唯一标识一台主机的符号是MAC地址(硬件地址)
现在使用的IP地址是那个协议维护的IP地址?IPv4
ipV4维护的IP地址宽度是4个字节。
4个字节的IP地址可表示的地址范围是:
0000 00004~1111 11114
可以分成5类:
A类:1.0.0.1~126.255.255.254
B类:127.0.0.1~191.255.255.254
C类:192.0.0.1~223.255.255.254—》用户地址
D类:224.0.0.1~239.255.255.254–》组播&多播地址
E类:240以后
C类=24bit网络号+8bit主机号
3 网络协议
定义:通信双方对某种通信规则的约定
协议:通用的网络协议 TCP/IP协议栈(OS)
行业内部专用协议 协议开发
自定义协议
4 端口号
作用:用来区分应用进程
端口号是一个无符号的整数,范围:1~65535
1~1023已经被占用
5 字节序
主机字节序:是指不同的CPU主机存贮多字节整数的方 式,有大端序主机和小端序主机
大端序主机:数据的高字节存放在内存的地地址
小端序主机:数据的高字节存放在内存的高地址
主机字节序----》网络字节序
Htonl
Htons
多字节整数发送前要从主机字节序转化成网络字节序, 以适配对端的网络主机
网络字节序:大端序
二 基于TCP协议的网络客户端和服务端模型
服务端:socket–>bind–>listen–>accept–>IO函数
客户端:socket–>connect–>IO函数
int socket(int domain, int type, int protocol);
作用:创建一个网络软通道
domain:协议域 使用AF_INET–》ipv4协议
type:套接字类型
protocol:协议 0–》自动匹配必要的协议
返回值:文件描述符–》用来标识socket通道
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
作用:给套接字绑定网络终端主机信息
sockfd:文件描述符–》socket的返回值
*addr:指向网络终端主机信息的结构体指针
addrlen:struct sockaddr的大小
返回值:0 成功 -1 失败
int listen(int sockfd, int backlog);
作用:侦听–》有没有客户端连接
sockfd:文件描述符–》socket的返回值
backlog:最大侦听客户端的个数
返回值:0 成功 -1 失败
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
作用:接收客户端的连接请求
sockfd:文件描述符
*addr:用来存放客户端的主机地址信息
*addrlen:第二个参数的长度
返回值:成功,返回新的文件描述符–》标识一个新的IO通道(用于收发正文数据)
失败,-1
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
作用:接收数据
sockfd:文件描述符–》accept的返回值
*buf:接收数据的存放buf
len:期望接收的字节数
flags:阻塞或非阻塞的标识。0–》阻塞接收
返回值:成功,>0 接收到的字节个数
<=0 失败
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
作用:发送数据
sockfd:文件描述符–》accept的返回值
*buf:要发送数据
len:期望发送的字节数
flags:阻塞或非阻塞的标识。0–》阻塞接收
返回值:成功,>0 接收到的字节个数
-1 失败
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作用:连接服务端
sockfd:文件描述符–》socket的返回值
*addr:服务端主机的地址信息
addrlen:第二个参数的长度
返回值:0 成功
-1 失败
1 基于UDP协议的客户端和服务端模型
服务端:socket–>bind–>IO函数(recvfrom/sendto)
客户端:socket–>IO函数(sendto/recvfrom)
两种网络编程框架的对比:
1 特点
TCP:使用流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内部设置了流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
UDP:使用数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)–ping.c
可以对较低层次协议如IP、ICMP直接访问
2 协议
TCP(传输控制协议):
TCP是一个可靠的,全双工的,有序的,面向链接的字节流通信的协议。
为什么可靠:
1.丢失的数据包重发 (能保证拿到数据)
2.错误的数据包重发 (保证能拿到正确的数据)
3.数据的有序到达(因为对每个数据包进行了编号)(拆包,编 号)
4.有较为健全的校验机制(为了保证数据的正确性)
5.支持面向连接(保证通信线路的畅通)–>三次握手
6.有信道拥堵控制(通过一种对于信道拥堵解决的方案,来提高转发效率)
为什么有序(有序列号):
1.保证数据都能传输给对端,不至于当传输的数据 > 信道带宽,导致数据丢弃。
2.通过序号,在对端主机上可以拼接成原本的数据包
3.保证数据传输的可靠性
如何面向链接:
三次握手和四次挥手
UDP:
UDP(The User Datagram Protocol):无连接的数据报协议,别名"不可靠的协议"
<1>使用校验和来实现错误侦测
<2>UDP常用于媒体流的传输(音频、视频、等),在这种情况下,实时性比可靠性更重要
<3>UDP也常用于简单的查询/回应程序,例如DNS查找,在这种情况下,建立可靠传输的资源消耗太大
<4>UDP是一种实时传输协议(Real-time Transport Protocol),这种协议通常用来传输实时数据例如:音视频流
不可靠的原因:
1.非面向连接(不关心接收端是否在线)–》没有三次握手
2.丢包不重发
3.错误的包不重发
4.没有信道拥堵控制
5.有一个最大传输长度限制
6.没有严格的校验机制
如何抉择使用TCP还是UDP?
1.可靠性
2.实时性
可靠性 > 实时性: TCP
可靠性 < 实时性: UDP
2 IO模型 --》阻塞IO 非阻塞IO IO多路复用 异步IO
2.1 阻塞IO
若要读的数据没有准备好,或要写入的目标没有空间,将会发生读写阻塞
常见的阻塞IO函数:recv recvfrom read write send accept connect
2.2 非阻塞IO
若要读的数据没有准备好,IO函数返回一个约定的错误值,不阻塞当前进程 ,可以通过循环去多次尝试读取数据。
常见的非阻塞IO函数:read/write(可以通过修改底层驱动设 计成非阻塞)
2.3 IO多路复用
思想:
1 构建一张文件描述符集合表,表的大小为1024bit,这些bit分别对应的是1024个文件描述符,这些bit位中存放的数据表示的是该描述符对应的IO通道是否有数据发生(1 有数据;0 没有数据) int a[32]—>1024Bit
2 使用 select监测程序中的文件描述符对应的通道是否有IO数据发生?若有IO数据发生,将文件描述符集合表的相应Bit位置1,同时将其他的bit位置0,并返回监测到的文件描述符的通道个数。
3 对监测的结果做出判断和响应。
循环遍历文件描述符集合表,查看集合表中关心的描述符对应的BIT位是否是1?如果是1,响应这路IO;如果是0,继续循环
int select(int n, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *timeout);
作用:监控文件描述符对应的IO通道是否有数据
N:最多监控多少个通道
*read_fds:指向读文件描述符集合表
*write_fds:指向写文件描述符集合表
*except_fds:指向异常文件描述符集合表
*timeout:NULL—》阻塞监控
返回值:select监控到的有数据发生的IO通道的个数
为了设置文件描述符我们要使用几个宏:
FD_SET 将fd加入到fdset
FD_CLR 将fd从fdset里面清除
FD_ZERO 从fdset中清除所有的文件描述符
FD_ISSET 判断fd是否在fdset集合中
If(FD_ISSET(0,stFdr))
{响应0对应的通道数据 fgets();}
1 服务器模型
服务器:可以服务于多个客户端的服务程序
种类:循环服务器和并发服务器
循环服务器:指的是该服务程序可以服务于多个客户端, 但是在同一时刻只能服务一个客户端。while
并发服务器:指的是该服务器可以在同一时刻服务于多个 客户端
在linux系统中,实现并发服务器,可以使用:
多进程 多线程 select poll epoll
1 多进程
思想:主进程专门用于连接多个客户端,若有一个客户端接进来,就创建一个子进程来负责该客户端的业务数据的收发 。
2 多线程
思想:主进程专门用于连接多个客户端,若有一个客户端接进来,就创建一个子线程来负责该客户端的业务数据的收发 。
3 select–>IO多路复用
思想:
1 构建一张文件描述符集合表,表的大小为1024bit,这1024个bit位用来存放1024个文件描述符对应的IO通道是否有数据发生,有数据发生的通道对应的BIT位置1,没数据发生的通道对应的BIT位置0。–》空表
2 使用select函数去监控关注的文件描述符对应的通道是否有数据发生?若监控到一路或多路通道有数据发生,则返回通道的路数同时将有数据发生的通道对应的文件描述符集合表的相应BIT位置1,同时将其他BIT位置0
(监控 置位)
3 对文件描述符集合表中的置位结果做出判断和响应。使用FD_ISSET去判断关心的描述符是否被置位了,若被置位了,返回真,那么响应这路IO;若没有被置位,返回假,不做处理。
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
作用:监控文件描述符对应的IO通道是否有数据发生
参数1:监控的最大通道个数
参数2:指向读文件描述符集合表的指针
参数3:指向写文件描述符集合表的指针
参数4:指向异常文件描述符集合表的指针
参数5:timeout=0,只检测文件描述符集合的状态,然 后立即返回
Timeout=NULL,select函数阻塞监控关注的文件 描述符通道
Timeout=时间,时间到达之间select函数一置阻 塞监控,时间到,结束监控。
返回值:成功返回监控到有数据发生的IO通道的个数
失败 -1
1 网络服务器超时检测
1 select超时设置–》select
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
Timeout:超时时间,若在指定的时间内没有客户端连接该服务器,服务器会一直阻塞,当指定时间到时,没有客户端连接,select阻塞时间到,返回0。
2 使用信号和alarm
Signal(信号,信号对应的新的处理函数)–》set
Sigaction(信号,NULL,&act) —>/get获取信号对应的旧的处理动作
Sigaction(信号,&act,NULL)–>set 设置信号对应的新的处理动作
void handler(int signo) { return; }–>新的处理函数
struct sigaction act;–》信号对应的处理对象
sigaction(SIGALRM, NULL, &act);–》获取信号旧的处理对象信息
act.sa_handler = handler;–》设置对象新的处理函数
act.sa_flags &= ~SA_RESTART;–》设置对象的重启标志为不重启
sigaction(SIGALRM, &act, NULL);–》设置信号对应的新对象
alarm(5);–》启动定时器,定时5S
if (recv(,) < 0) ……
3 设置socket属性
Setsockopt:设置套接字的属性
Getsockopt:获取套接字的属性
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv));
2 广播&组播
在网络中,数据包的发送方式有三种:单播 广播 组播
广播:数据发送方将数据包发送给了局域网中的所有的主机。
广播地址通常是这个网段中最大的IP地址,
例如192.168.12.255
或者是255.255.255.255
广播发送:socket–>setsockopt(允许广播发送) --》sendto(广播地 址) udp_client.c
广播接收:socket–>bind–>recvfrom udp_server.c
组播:数据发送方将数据包发送到了某个主机的组播组里,加入 到该组播组的所有的主机能够接收到组播数据
组播地址:224.0.0.1~239.255.255.254
组播发送:socket–>指定目标地址为组播地址–》sendto udp_client.c
组播接收:socket–>加入组播组–》bind->recvfrom
Udp_server.c
unix域套接字–》socket文件–》通信介质
unix域:socket文件(使用本地协议创建的socket文件)
用socket函数使用本地协议可以创建一个socket文件,通过该文件能够实现一台主机上两个进程的通信。
unix域套接字有两种:流式套接字 数据报套接字
TCP流式套接字:
使用TCP协议的网络编程框架创建流式套接字文件,该套接字文件可以实现一台主机上两个本地进程的通信。
服务端:socket–》bind–>listen–>accept–>IO函数
客户端:socket–>connect–>IO函数
注意:tcp方式的unix域套接字,类似无名管道,实现双向通信只需要一个文件。可以实现两个不相关进程的通信
UDP数据报套接字:
使用UDP协议的网络编程框架创建数据报套接字文件,该套接字文件可以实现一台主机上两个本地进程的通信。
发送方:socket–>bind–>IO函数
接收方:socket–>bind–》IO函数
注意:udp方式unix域套接字,类似于有名管道,实现双工通信需要两个管道文件。用于两个不相关进程的通信
b c d - l s p
unlink(“hello”)–>删除已经存在的套接字文件
数据库:是指以同一组织方式将相关的数据组织在一起,并存放在计算机的存储器上的能够为多个用户所共享的文件,该文件与应用程序彼此独立。
在嵌入式领域常见的数据库有:SQLite mySql–>SQL语句
SQlite是一个开源的,内嵌的关系型数据库。
特点:源码开放 代码精简 免安装 支持SQL语句–》2w+
1 SQL语句—》用做操作数据库的指令
Primary key:–>主键约束
A 主键值必须是唯一的,用于标识每条记录,如学生 的学号
B 主键同时也是一个索引,通过主键查找记录的速度 最快
C 主键如果是整数类型,该列的值可以自动增长。
创建一张表:
Create table 表名(字段&约束)
给表插入一条表项:
Insert into 表名(字段列表) values (插入值列表)
查询:
Select *from 表名—》查整张表
Select *from 表名 where 条件1 and/or 条件2
修改记录:
Update 表名 set 字段名=新值 where id=2
删除表项:
Delete from 表名 where id=1–>条件删除
Drop table 表名—》删除整张表