同一主机间的进程通讯方式:
1.无名管道(亲缘关系间的通讯,固定的读端和写端)
2.有名管道(半双工(因为文件可见,可再次打开交换读端写端),非亲缘关系)
3.信号
4.共享内存(效率最高)
5.消息队列(可以指定发送和接收的数据类型)
6.信号灯集(常和共享内存一起使用)
7.socket套接字(UNIX编程)
详情见->进程间的通讯
前言:做系统开发的程序员至少要精通两门语言,一门脚本和网络知识
同一台主机间进程间通讯方式XSI IPC
不同计算机上进程相互通讯的机制:网络进程间通讯(Network IPC)
Internet-“冷战”的产物
1957年10月和11月,前苏联先后有两颗“Sputnik”卫星上天
1958年美国总统艾森豪威尔向美国国会提出建立DARPA (Defense Advanced Research Project Agency),即国防部高级研究计划署,简称ARPA
1968年6月DARPA提出“资源共享计算机网络” (Resource Sharing Computer Networks),目的在于让DARPA的所有电脑互连起来,这个网络就叫做ARPAnet,即“阿帕网”,是Interne的最早雏形
1.批处理(20世纪50年代)
是指实现将用户每个数据装入卡带或者磁带。并有计算机按照一定的顺序读取,是用户索要执行的这些程序和数据能够一并批量得到处理的方式。
2.分时系统(20世纪60年代)
是指多个终端(包含鼠标、键盘、显示器等输入输出设备组成,最初还包括打印机)与一台计算机连接,允许多个用户同时使用一台计算机的系统。
特性:多路性、独占性、交互性和及时性。
3.计算机之间的通信(20世纪70年代)
4. 计算机网络的产生(20世纪80年代)
5. 互联网的普及(20世纪90年代)
6. 以互联网技术为中心的时代(2000年)
7. 从“单纯建立连接”到“安全建立连接”(2010年)
通常把功能先近的协议们组织在一起,放在一层,协议栈(protocol Suite)
分层的好处?
1、各层之间独立,每一层不需要知道他的下一层如何实现,而仅仅需要知道该层通过层间的接口所提供的服务。
2、稳定,当任何一层发生变化时候,只要层间接口关系保持不变,则这层以上或以下层不受影响。
3、易于实现和维护
4、能促进标准化工作
ISO(国际标准化组织)制定了一个国际标准OSI(开放式通讯系统互联参考模型),对通讯系统进行了标准化。
OSI模型最终没有得到广泛应用的原因:
第六层和第五层广受诟病,因为显得多余,在实际使用中这两层合并到第七层应用层。
OSI模型的定义先于OSI模型中协议的定义,这让OSI模型多少有了纸上谈兵的味道。
TCP/IP模型正好和OSI模型相反,他是通过既有协议归纳总结出来的模型。
因此比OSI模型更有现实意义
(1)应用层:提供应用软件而设的接口,以设置与另一个软件之间的通讯
(2)表示层:设备固有数据格式和网络标准数据格式的转换
(3)会话层:负责数据传输中设置和维护计算机网络中两台计算机之间的通讯连接
(4)传输层:管理两个节点之间数据传输
(5)网络层:地址管理与路由选择
(6)数据链路层:互联设备之间传送和识别数据帧
(7)物理层:传输物理信号,以0、1代表高低电平
OSI模型是一个理想化的模型已经很少使用,没有完整的实现,但是模型本身非常通用。
TCP/IP协议是Internet事实上的工业标准
也叫网络访问层,功能:包括IP地址与物理地址的映射,以及将上一层IP报文封装成帧。
MAC地址:48位全球唯一,网络设备的身份标识。
电气电子工程师学会IEEE
ARP/RARP协议:地址解析协议
ARP: IP地址—获取—MAC
RARP:MAC–获取—IP地址
PPP协议:拨号协议(GPRS/3G/4G)
负责在主机之间的通讯中选择数据报的传输路径,即路由
最核心的协议IP协议(Internet Protocol因特网协议)
IP协议根据数据包的目的IP地址来决定如何投递他
如果数据包不能直接发送给目标主机,那么IP协议就为他寻找一个合适的下一跳路由器。
ICMP协议:因特网控制管理协议,ping检测网络连接。
IGMP协议:因特网分组管理协议,组播,广播
负责提供应用程序之间通讯服务这种通讯又称为端到端通讯。
与网络层使用逐跳通讯方式不同,传输层只关心通讯的起始端和目的端,并不在乎数据包的中转过程。
TCP(Transmission Control Protocol,传输控制协议)提供面向连接的,一对一可靠数据传输的协议。
UDP(User Datagram Protocol,用户数据报协议)提供不可靠,无连接尽力传输的协议。
负责处理应用程序的逻辑
网页访问协议:HTTP/HTTPS(Hyper Text Transfer Protocol secure)
邮件协议:
收POP3(post office Protocol)邮局协议第三个版本,从服务器接收邮件,接收完服务器就没有这个邮件了。发SMTP(简单邮件传输协议)
IMAP交互式邮件存取协议,它跟POP3类似邮件访问标准协议之一,收取邮件后,服务器上邮件仍然存在,如果删除,标记等操作服务器也会做响应的动作
FTP 文件传输
DNS
Telnet/ssh远程登录
嵌入式相关
NTP网络时钟协议
SNMP简单网络管理协议(实现对设备集中式管理)
RTP/RTSP用于传输音视频的协议(安防监控)
数据链路层(驱动程序)封装了物理网络的电器细节
网络层封装了网络连接的细节
传输层为应用程序封装了一条端到端通讯的链路,它负责数据的收发链路的超时重连等
校验每一帧的CRC,验证解码或编码出来的码流是否正确
码串在传输的时候因为不可控的原因,有可能会发生错误
这就需要在码串中加入校验码,方便再接收端进行校验。
Maximum Transmit Unit 最大传输单元
物理接口(数据链路层)提供给上层(网络层(IP层))最大一次传输数据的大小。
规定了数据链路层所能传送最大数据长度
以太网为例,缺省MTU=1500字节,这是以太网接口对IP层的约束
如果IP层<=1500字节需要发送,只需要一个IP包就可以
如果IP层>1500字节需要发送,需要分片才能发送
Maximum Segment Size 最大报文长度
TCP提交给IP层最大分段大小,指TCP报文所允许传送数据部分最大长度。
不包含TCP头,MSS式TCP来限制应用层最大发送字节数。
如果MTU=1500,则MSS = 1500-20(IP header)-20(TCP header) =1460字节
如果应用有2000字节要发,需要2 Segment
第一个TCP Segment = 1460 第二个TCP Segment = 540
IP地址式因特网中主机的标识,每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由。
IP地址是指Internet协议使用的地址,而MAC地址是Ethernet协议使用的地址。当存在一个附加层的地址寻址时,设备更易于移动和维修。
IP地址的分配是基于网络拓朴,MAC地址的分配是基于制造商。
IP地址是可以自动分配的,MAC地址在每个网卡出场的时候就有一个全球唯一的MAC地址,所以很多的验证软件就是验证mac地址的。
IPv4 :采用32位无符号整数 42,9496,7296
局域网式为了解决IP地址不够用的问题
LAN:Local Area Network
WAN:Wide Area Network
IPv6:采用128位无符号整数
每个32位IP地址被分割成2部分,这样两级划分结构设计使得寻径很有效。
地址前一部分确定计算机从属的物理网络,也就是说互联网中每个物理网络分配唯一值作为网络号(network number)
网络号再从属该网络的每台计算机地址中作为前一部分出现。
后一部分确定该网络上的一台主机,通常称为主机号
IP地址分为两部分,必须决定每部分包含多少位
地址的前4位决定了地址所属的类别,并且确定如何将地址的其余部分划分网络号和主机号
ABC类称为基本类,他们用于主机地址
D类不表识网络用于特殊用途,组播(多目广播)
E类保留实验来使用
分配给主机的地址只能为基本类ABC
当组内所有位都是0,最小值0
当组内所有位都是1,最大值255
点分十进制非常适合用于IP地址,因为IP以8位位阻为界,把地址分为前缀和后缀
A类地址中,后三组是主机后缀,B、C以此类推
A类地址 | 0.0.0.0~127.255.255.255 | 2^7 | 2^24 | 大型网络 |
---|---|---|---|---|
B类地址 | 128.0.0.0~191.255.255.255 | 2^14 | 2^16 | 名地址网管中心 |
C类地址 | 192.0.0.0~223.255.255.255 | 2^21 | 2^8 | 校园网或企业网 |
D类地址 | 224.0.0.0~239.255.255.255 | 组播地址 | ||
E类地址 | 240.0.0.0~255.255.255.255 | 保留实验 |
有效的网络号+全是0的主机号—》代表一个网络
192.168.1. 0 代表192.168.1这个网络
有效的网络号+全是1的主机号—》代表向当前网络所有主机发送消息192.168.1. 255
一般192.XXX.XXX. 10.XXX.XXX.XXX
内外网IP定义
内网IP地址就是私有IP地址,不允许在公网上面传递,只能供内部使用。内网使用了私有地址无法访问internet 会用到NAT-地址转换技术,将内部的私有地址转换为可以访问internet的外网地址让内部可以上网。外网IP地址就是除了私有地址和被保留的地址外的所有地址,需要申请才能使用。
ABC三类地址中划分出了三类私有地址:
A类10.0.0.0~10.255.255.255
B类172.16.0.0~172.31.255.255
C类192.168.0.0~192.168.255.255
内网概念
即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的。但两个局域网内的内网IP可以有相同的。
外网概念
即互联网,局域网通过一台服务器或是一个路由器对外连接的网络,这个IP地址是惟一的。也就是说内网里所有的计算机都是连接到这一个外网IP上,通过这一个外网IP对外进行交换数据的。也就是说,一个局域网里所有电脑的内网IP是互不相同的,但共用一个外网IP。(用ipconfig/all查到的IP是你本机的内网IP;在网页上看到的是你连接互联网所使用的IP,即外网)
内外网联系及区别
在局域网中,每台电脑都可以自己分配自己的IP,这个IP只在局域网中有效。而如果你将电脑连接到互联网,你的网络提供商(ISP)的服务器会为你分配一个IP地址,这个IP地址才是你在外网的IP。两个IP同时存在,一个对内,一个对外。
当你家里买了两台电脑,你想组建一个局域网,你除了要用网线和路由器等设备将两台电脑相连,你还要将两台电脑设置固定IP,比如电脑A设为192.168.1.2,电脑B设为192.168.1.3,这样你就可以用这两个IP地址互相访问两台电脑,但这两个IP地址只在这两台电脑间有效,对外网无效。所以局域网中分配的IP与广域网中的IP完全没有对应关系。你在内网的机子在上网时,都是在向网关发出请求,再由网关(一般为路由器)用外网IP转到INT网上,接受数据后,再分发到你的内网IP上。
由于二级IP地址存在灵活性差的问题,增加了一个子网号字段
使用两级的IP地址编程三级IP地址,也就是IP地址由网络号、子网号和主机号3部分组成
子网实际上是把主机号进行了划分。
子网掩码就是和IP地址一样长的32位整数
是由一串1后面跟着一串0组成的
子网掩码种的1标识在IP地址种网络号和子网号的对应比特位
掩码中0表示在IP地址种主机号对应的比特位
C类地址默认子网掩码是255.255.255.0
B类地址默认子网掩码是255.255.0.0
A类地址默认子网掩码是255.0.0.0
例子:某公司由四个部门:行政、研发、售后、营销,每个部门各20台电脑接入公司局域网交换机,如果要在192.168.1.0网段位每个部门划分子网,子网掩码怎么设置?子网的地址范围是什么?
192.168.1.0网段共256个地址划分成4个子网,每个子网共64个IP地址,64是2的6次方,所以主机号有6位是0,
剩下的全是1,也就是26个1后面跟着6个0.
掐头去尾可以用的地址62个
行政:第一个子网可以用的IP地址范围是:192.168.1.1~62
研发:第二个子网可以用的IP地址范围是:192.168.1.65~126
售后:第三个子网可以用的IP地址范围是:192.168.1.129~190
营销:第四个子网可以用的IP地址范围是:192.168.1.193~254
概念:
大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway) 就是一个网络连接到另一个网络的“关口”。也就是网络关卡。
网关(Gateway)又称网间连接器、协议转换器。默认网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。
【说明:由于历史的原因,许多有关TCP/IP的文献曾经把网络层使用的路由器称为网关,在今天很多局域网采用都是路由来接入网络,因此通常指的网关就是路由器的IP!】
网关是一个网络通向其他网络的IP地址
目前家用路由器一般使用192.168.1.1和192.168.0.1作为LAN接口的地址,这个两个也是最常用的网关地址。
由于使用IP地址来指定计算机不方便人们记忆,且输入时候容易出错,用字符标识网络种计算机名称方法。
这种命名方法就像每个人的名字,这就是域名(Domian Name)
域名是因特网种联网计算机名称
域名服务器(Domain Name server)用来处理IP地址和域名之间的转换。
域名翻译成IP地址的软件称为域名系统(Domain Name System,DNS)
域名结构
例如域名 www.baidu.com.cn
cn为高级域名,也叫一级域名,它通常分配给主干节点,取值为国家名,cn代表中国
com为网络名,属于二级域名,它通常表示组织或部门
中国互联网二级域名共40个,edu表示教育部门,com表示商业部门,gov表示政府,军队mil等等
baidu为机构名,在此为三级域名,表示百度
www万维网world wide web,也叫环球信息网,是一种特殊的信息结构框架。
为了区分一台主机接收到的数据包应该转交给那个进程来处理,使用端口号来区别。
2个字节,16位无符号整数(1~65535)
众所周知的端口号:
1~1023端口我们编程时候不要使用,是那些”VIP“应用程序占了
TCP 21端口:FTP文件传输服务
TCP 23端口:TELNET终端仿真服务
TCP 25端口:SMTP简单邮件传输服务
TCP 110端口:POP3邮局协议版本3
TCP 80端口:HTTP超文本传输服务
TCP 443端口:HTTPS加密超文本传输服务
UDP 53端口:DNS域名解析服务
可以使用的:1024~49151,就是我们平时编写服务器使用的端口号
临时端口号:49152~65535,这部分是客户端运行时候动态选择的
TCP端口和UDP端口号相互独立
网络里面的通讯是由 IP地址+端口号 来决定
1)字节序是指不同类型的CPU主机种,内存存储 多字节整数 序列的方法
同一台计算机上的进程通讯一般不考虑字节序
小端序little-endian 低序字节存储在低地址
Intel、AMD等采用种方式,ARM默认也是小端
大端序big-endian高序字节存储在低地址
ARM作为路由器时候采用
如果是字符串,则不存在大小端问题,字符串是单字节的
大小端特点
大端模式:符号位判断固定在第一个字节容易判断正负
小端模式:强制转换数据不需要调整字节内容
#include
union{
int a;
char b;
}t;
int main(int argc, char *argv[])
{
printf("argc=%d,argv[0]=%s\n",argc,argv[0]);
/* 共用体判断大小端字节序 */
t.a = 0x87654321;
fprintf(stderr, "%#x\n",t.b);
/* 指针强制转换判断大小端 */
int a = 1;
char * p = (char*)&a;
if (*p == 1) {
┊ fprintf(stderr, "小端字节序\n");
} else {
┊ fprintf(stderr, "大端字节序\n");
}
return 0;
}
不严格区分大小端
那区分:
主机字节序:(Host Byte Order )HBO
网络字节序:(Network Byte Order)NBO
网络传输就转换成网络字节序,使用统一的字节序,避免兼容性问题
不同的机器HBO不一样,这个和CPU设计有关。
#include
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
返回值:以网络字节序表示的无符号整数
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
返回值:以本地字节序表示的无符号整数
注意:网络通信中端口号的转换经常用htons和ntohs
#include
#include
int main(int argc, char *argv[])
{
unsigned int host_t = 0x87654321;
fprintf(stderr, "host_t=%#x\n",host_t);
unsigned int net_t = htonl(host_t);
fprintf(stderr, "net_t=%#x\n",net_t);
unsigned short host_s_t = (unsigned short)0x12345678;
fprintf(stderr, "host_s_t=%#x\n",host_s_t);
unsigned short net_s_t = htons(host_s_t);c
fprintf(stderr, "net_s_t =%#x\n",net_s_t);
return 0;
}
编译器会对结构体对齐,加速CPU取值周期,由于数据对齐也是与平台相关,不同主机如果使用不同的对齐方式,就会导致数据无法解析。所以网络传输结构体时候一定要禁止结构体对齐。
偏移地址 | 起始地址 % sizeof(type) == 0 | |
---|---|---|
struct{ | 0x00 | a |
char a; | 0x01 | 空(01%4!=0) |
int b; | 0x02 | 空(02%4!=0) |
char c; | 0x03 | 空(03%4!=0) |
short d; | 0x04 | b(04%4==0) |
} | 0x05 | b |
0x06 | b | |
0x07 | b | |
0x08 | c(08%1!=0) | |
0x09 | 空(09%2!=0) | |
0x10 | d(10%2==0) | |
0x11 | d |
#include typedef struct{
char a;
int b;
char c;
int d;
}__attribute__((packed)) qxdq;
typedef struct{
char a;
int b;
char c;
int d;
} dq;
int main(int argc, char *argv[])
{
printf("argc=%d,argv[0]=%s\n",argc,argv[0]);
fprintf(stderr, "结 构 体 对 齐 = %ld\n",sizeof(dq));
fprintf(stderr, "取消结构体对齐 = %ld\n",sizeof(qxdq));
return 0;
}
假如通讯双方传送一个int类型数据,那么对方机器上int类型的位数与我们机器上的位数是否相同?
有可能不同,如果不同的话就这样传送,会出问题的。
所以通讯双方的数据类型要采用完全一致的约定。
16位机器32位机器64位机器他们long大小不一样
解决方式:使用通用类型 uint32_t int8_t uint64_t等等
因为涉及到跨平台,不同平台可能会有不同的字长
拓展:
long 在32位上是4个字节,在64位上是8个字节,16位上是16位,16位的int是2位
在ubantu上看系统是多少位的->命令行输入:uname -a (或者file a.out)
#include
typedef struct{
int8_t a;
uint32_t b;
int8_t c;
uint32_t d;
}__attribute__((packed)) qxdq;
头文件:
#include
#include
#include
原型:
int inet_aton(const char *cp, struct in_addr * inp);
参数:
const char *cp 点分十进制ip字符串
struct in_addr * inp 转换结果,网络字节序
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr;
};
返回值:
成功1
ip无效0,不设置errno
#include
#include
#include
#include
#include
#define IP "1.2.3.4"
int main(int argc, char *argv[])
{
struct in_addr ip_t;
if( inet_aton(IP,&ip_t) == 0 ) {
perror("aton");//并不设置errno
fprintf(stderr, "地址非法\n");
exit(1);
}
fprintf(stdout, "%#x\n",ip_t.s_addr);
return 0;
}
头文件:
#include
#include
#include
原型:
in_addr_t inet_addr(const char *cp);
typedef uint32_t in_addr_t;
参数:
cp 点分十进制ip字符串
特点:只适用于IPv4
不能转换 255.255.255.255
出错的时候返回 -1 (-1补码形式存储)
#include
#include
#include
#include
#include
#define IP "1.2.3.4"
int main(int argc, char *argv[])
{
uint32_t ip_t = 0;
ip_t = inet_addr(IP);
if(-1 == ip_t) {
fprintf(stderr, "error\n");c
exit(1);
}
fprintf(stdout, "%#x\n",ip_t);
return 0;
}
头文件:
#include
#include c
#include
原型:
char * inet_ntoa(struct in_addr in);
返回值:
函数返回指向点分十进制字符串指针
该字符串存放在静态区(静态分配),这就意味着第二次调用该函数时候会覆盖掉前一次的结果,所以应该保存结果
#include
#include
#include
#include
int main(int argc, char *argv[])
{
struct in_addr addr1,addr2;
addr1.s_addr = inet_addr("192.168.1.123");
addr2.s_addr = inet_addr("123.234.56.78");
fprintf(stderr, "addr1:%s addr2:%s \n",inet_ntoa(addr1),inet_ntoa(addr2));c
fprintf(stderr, "addr2:%s addr1:%s \n",inet_ntoa(addr2),inet_ntoa(addr1));
fprintf(stderr, "addr1:%s \n",inet_ntoa(addr1));
fprintf(stderr, "addr2:%s \n",inet_ntoa(addr2));
return 0;
}
将IP地址字符串,转换成网络字节序二进制
头文件:
#include
原型:
int inet_pton(int af, const char *src, void *dst);
参数:
int af:填写AF_INET或AF_INET6
const char *src 一个指向IP字符串的地址
void *dst 一个指向转换后网络字节序二进制值的指针
返回值:
若成功返回1
输入无效返回0
af错误-1 设置errno
将网络字节序二进制转换成IP字符串
头文件:
#include
原型:
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
参数:
int af:填写AF_INET或AF_INET6
const void *src:一个指向网络字节序二进制的指针
char *dst:转换后点分十进制字符串首地址
socklen_t size:缓冲区大小
返回值:
成功返回转换结果的非空指针
错误返回NULL,设置errno
#include
#include
#include
int main(int argc, char *argv[])
{
char IP[20]={
};
struct in_addr s;
fprintf(stderr, "请输入IP");
int num = scanf("%s", IP);
if (num != 1) {
fprintf(stderr, "输入有误\n");
exit(3);
}
fflush(NULL); //刷新所有
int pn = inet_pton(AF_INET,IP,(void*)&s);
if(pn <= 0){
if (pn == 0) {
fprintf(stderr, "无效IP\n");
}else{
perror("");
}
exit(1);
}
fprintf(stderr, "inet_pton:%#x \n",s.s_addr);
const char *np = inet_ntop(AF_INET,(void*)&s,IP,20);
if(np == NULL) {
perror("");
exit(2);
}
fprintf(stderr, "inet_ntop:%s\n",IP);c
return 0;
}