【嵌入式Linux系统开发】网络编程
网络编程1.基本概念网络程序和普通程序最大的区别是,网络程序是由两个部分组成的,即客户端和服客户端的由务器端。网络程序是先服务器程序启动,等待客户端的程序运行并建立连接,一般来说,服务器的程序在一个端口上监听,直到有一个客户端的程序发来请求。1.1 OSI模型OSI模型是国际互联网标准化组织所定义的,目的是为了使网络的各个层次有标准。OSI模型共7个层次:(1)物理层:硬件连接的接口(2)数据链路
文章目录
1.基本概念
网络程序和普通程序最大的区别是,网络程序是由两个部分组成的,即客户端和服客户端的由务器端。网络程序是先服务器程序启动,等待客户端的程序运行并建立连接,一般来说,服务器的程序在一个端口上监听,直到有一个客户端的程序发来请求。
1.1 OSI模型
OSI模型是国际互联网标准化组织所定义的,目的是为了使网络的各个层次有标准。
OSI模型共7个层次:
(1)物理层:硬件连接的接口
(2)数据链路层:负责实现通信信道的无差错传输,提供数据帧、差错控制、流量控制和链路控制等功能。
(3)网络层:负责将数据正确迅速地从源主机传送到目的主机,其功能主要有寻址以及相关的流量控制和拥塞控制等。
(4)传输层:为上层处理过程掩盖下层结构的细节,保证把会话层的信息有效地传输到另一方的会话层
(5)会话层:提供服务请求者和提供者之间的通信,用以实现两端主机之间的会话管理、传输同步和活动管理等
(6)表示层:主要功能是实现信息转换
(7)应用层:为用户提供常用的应用
1.2 常用命令
-
netstat
命令netstat用于网络的连接、路由器和接口统计等网络的信息
常用命令:netstat -an:用于显示详细的网络状态
-
telnet
命令telnet是用来远程控制的程序,可以用该程序来调试用户的服务端程序
1.3 网络地址
网络地址是终端在整个网络中的唯一标识,
1.4 IP设置项
- IP地址:机器的唯一识别的网络地址
- 网络广播地址
- 子网掩码:用于——屏蔽IP网络的一部分、区分网络标识和主机标识、识别子网
- 网关:用于访问外网
- MAC地址:网卡的物理地址
1.5 端口
网络地址用来识别哪一台机器;端口用于识别一台机器的哪一个程序
端口分类:
- 公认端口:端口号为0~1023
- 注册端口:端口号为1024~49151
- 动态端口:端口号为49152~65535
2.TCP/IP协议
TCP/IP:传输控制协议/因特网互联协议,又叫网络通信协议
2.1 整体架构概述
TCP/IP 实际上一个协同工作的通信家族,为网络数据通信提供通路。为讨论方便可TCP/IP 协议组大体上分为三部分:
- Internet 协议(IP)
- 传输控制协议(TCP)和用户数据报协议(UDP)
- 处于 TCP 和 UDP 之上的一组应用协议。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等
2.2 IP协议
IP主要有以下四个主要功能:
- 数据传送
- 寻址
- 路由选择
- 数据报文的分段
IP的主要目的
为数据输入/输出网络提供基本算法,为高层协议提供无连接的传送服务。
2.3 IP构成
IP包由IP协议头与协议数据两部分构成。
2.4 TCP协议
TCP是重要的传输层协议,目的是允许数据同网络上的其他节点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输
TCP 协议具有严格的内装差错检验算法确保数据的完整性。
TCP 是面向字节的顺序协议,这意味着包内的每个字节被分配一个顺序编号,并分配给每包一个顺序编号。
基于TCP连接的建立
2.5 UDP协议
UDP也是传输层协议,它是无连接的,不可靠的传输服务。
当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文。
由于它执行功能时具有较低的开销,因而执行速度比TCP快。
基于UDP协议连接的建立
3.Linux网络编程
Linux中的网络编程通过Socket(套接字)接口实现,Socket是一种文件描述符
3.1 类型
套接字socket有三种类型:
- 流式套接字(SOCK_STREAM)
流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP 保证了数据传输的正确性和顺序性
- 数据报套接字(SOCK_DGRAM)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的 ,并且不保证可靠,无差错,它使用数据报协议UDP。
- 原始套接字
原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议的测试等
3.2 函数使用
进行Socket编程
常用函数:
- socket()
创建一个socket(套接字)。
- bind()
用于绑定IP地址和端口号到socket。
- connect()
该函数用于绑定之后的client端,与服务器建立连接。
操作函数:
- listen()
设置能处理的最大连接要求,Listen()并未开始接收连线,只是设置socket为listen模式。
- accept()
用来接受socket连接。
- Send()
发送数据
- Recv()
接收数据
4.服务器模型
在网络程序里面,一般来说都是许多客户对应一个服务器,为了处理客户的请求, 对服务端的程序就提出了特殊的要求。目前最常用的服务器模型有:
循环服务器
:服务器在同一个时刻只可以响应一个客户端的请求并发服务器
:服务器在同一个时刻可以响应多个客户端的请求
4.1 UDP循环服务器
UDP循环服务器的实现方法:
UDP服务器每次从套接字上读取一个客户端的请求->处理->然后将结果返回给客户机。
socket(...);
bind(...);
while(1)
{
recvfrom(...);
process(...);
sendto(...);
}
因为UDP是非面向连接的,没有一个客户端可以老是占住服务端, 服务器对于每一个客户机的请求总是能够满足。
4.2 TCP循环服务器
TCP服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。算法如下:
socket(...);
bind(...);
listen(...);
while(1)
{
accept(...);
process(...);
close(...);
}
TCP循环服务器一次只能处理一个客户端的请求。只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求。这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了,因此,TCP服务器一般很少用循环服务器模型的。
4.3 TCP并发服务器
并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是由服务器创建一个 子进程来处理。算法如下:
socket(...);
bind(...);
listen(...);
while(1)
{
accept(...);
if(fork(..)==0)
{
process(...);
close(...);
exit(...);
}
close(...);
}
TCP并发服务器可以解决TCP循环服务器客户机独占服务器的情况。但同时也带来了问题:为了响应客户的请求,服务器要创建子进程来处理,而创建子进程是一种非常消耗资源的操作。
5.多路复用IO
1.设置要监控的文件
2.调用Select开始监控
3.判断文件是否发生变化
阻塞函数在完成其指定的任务以前不允许程序继续向下执行。
例如:当服务器运行到accept语句时,而没有客户请求连接,服务器就会停止在accept语句上等待连接请求的到来。这种情况称为阻塞(blocking)
而非阻塞操作则可以立即完成。
例如,如果你希望服务器仅仅检查是否有客户在等待连接,有就接受连接,否则就继续做其他事情,则可以通过使用select系统调用来实现。
除此之外,select还可以同时监视多个套接字 。
int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct timeval *timeout)
- Maxfd: 文件描述符的范围,比待检的最大文件描述符大1
- Readfds:被读监控的文件描述符集
- Writefds:被写监控的文件描述符集
- Exceptfds:被异常监控的文件描述符集
- Timeout:定时器
系统提供了4个宏对描述符集进行操作:
#include <sys/select.h>
void FD_SET(int fd, fd_set *fdset)
void FD_CLR(int fd, fd_set *fdset)
void FD_ZERO(fd_set *fdset)
void FD_ISSET(int fd, fd_set *fdset)
宏FD_SET
将文件描述符fd添加到文件描述符集fdset中;
宏FD_CLR
从文件描述符集fdset中清除文件描述符fd;
宏FD_ZERO
清空文件描述符集fdset;
在调用select后使用FD_ISSET
来检测文件描述符集fdset中的文件fd发生了变化。
实例:
FD_ZERO(&fds); //清空集合
sock1 = socket(……);
sock2 = socket(……);
bind(sock1,…);
bind(sock2,…);
listen(sock1,…);
listen(sock1,…);
FD_SET(sock1,&fds); //设置描述符
FD_SET(sock2,&fds); //设置描述符
maxfdp=(sock1>sock2?sock1:sock2) + 1;
switch(select(maxfdp,&fds,NULL,NULL,&timeout))
case -1: exit(-1);break; //select错误,退出程序
case 0:break;
default:
if(FD_ISSET(sock1,&fds)) //测试sock1是否可读
accpet(sock1,…)
更多推荐
所有评论(0)