进程间通信方式有七种:无名管道、有名管道、信号、消息队列、共享内存、信号灯集、socket 套接字通信。
前六种只能实现同主机的进程间通信,而socket 套接字既可以实现同主机的进程间通信,也能实现不同主机的进程间通信。
APRANET阶段
1968年6月DARPA提出“资源共享计算机网络”
(Resource Sharing Computer Networks),目的在于
让DARPA的所有电脑互连起来,这个网络就叫做ARPAnet,
即“阿帕网”,是Interne的最早雏形
早期的ARPAnet使用网络控制协议(Network Control
Protocol,NCP),不能互联不同类型的计算机和不
同类型的操作系统,没有纠错功能
TCP/IP两个协议阶段
1974年12月两人正式发表第一份TCP协议详细说明,
但此协议在有数据包丢失时不能有效的纠正
TCP/IP协议分成了两个不同的协议:
用来检测网络传输中差错的传输控制协议TCP
专门负责对不同网络进行互联的互联网协议IP
OSI开放系统互联模型
是由 ISO 国际标准化组织提出的。
*物数网传会表应
TCP/IP协议族(簇)的体系结构
实际生产过程中,由于OSI开放系统互联模型太过繁琐,所以没人使用,
但是他的思想思路是正确的,后面提出的其他体系结构,都是基于OSI开放系统互联模型而来的。
TCP/IP协议族是Internet事实上的工业标准。
应用层 HTTP:超文本传输协议,
FTP:文件传输协议,
TFTP:简单文件传输协议(使用TCP),
SMTP:简单邮件传输协议。
网卡驱动 物理接口 交换机
传输层 TCP:传输控制协议,面向连接的,可靠的,
UDP:用户数据报协议,无连接的,不可靠,快速传输。
网络层 IP:网际互连协议,
ICMP:互联网控制信息协议,ping命令使用的协议 IP和路由器之间传递消息
IGMP:互联网组管理,组播协议
路由器
网络接口和物理层(链路层) FTP
ARP:地址解析协议,通过IP获取对方MAC地址
RARP:逆向地址解析协议,通过MAC地址获取IP地址
数据封包和拆包:(比特流)
应用层:用户数据(一般128byte)
传输层:TCP头(源端口号和目的端口号)20byte
网络层:IP头(源IP地址和目的IP地址)20byte
链路层:以太网头(目的MAC地址和源MAC地址)14byte(linux一帧数据最大1500byte不算以太网头)
LINUX内核五大功能:
进程管理:时间片轮转、上下文切换
内存管理:内存的分配和回收
文件管理:将一堆 0 1 转换成人类能识别的字符
设备管理:一切皆文件
网络管理:网络协议栈(网络协议栈可以理解成内核提供的函数)
TCP和UDP异同:
相同点:都是传输层协议
不同点:TCP是一种面向连接的可靠的传输协议,它能提供高可靠性的通信,数据无误,无丢失,无失序,无重复到达的通信
适合于对传输质量要求高,以及传输大量数据的通信,例如用户登录账号管理,密码等
UDP用户数据报协议,是不可靠的无连接的协议,数据在发送之前,因为不需要连接,所以可以进行高效率的额数据传输
适合发送小尺寸数据(如DNS服务器对IP地址查询时),适合于广播、组播式通信。即时通讯软件,音视频通讯。
TCP循环服务器:两个阻塞函数。
UDP并发服务器:一个阻塞函数。
网络编程基础知识:
字节序:内存存储多字节整数序列。(主机字节序HBO)
小端序:数据低位存在地址地位 Intel、AMD
大端序:数据高位存在地址低位 ARM/Motorola
判断自己的主机字节序?
#include <stdio.h>
int main(){
int m = 0x12345678;
char *p = (char *)&m;
if(*p == 0x78){
printf("小端\n");
}else if(*p == 0x12){
printf("大端\n");
}
return 0;
}
不同类型CPU主机字节序不一定相同,所以发送端和接收端的数据可能出现不一致的情况,就发明了网络字节序的概念
规定数据在网络中传输,必须是大端序。
什么情况下需要考虑字节序转换的问题?
1.数据大小超过一字节,并且作为整体发送。(字符串不需要)
2.不知道通信双方的主机字节序。
如何将小端序的无符号四字节整型转换成大端序?
#include <stdio.h>
int main(){
unsigned int m = 0x12345678;
unsigned int n = 0;
char *p = (char *)&m;
char *q = p+3;
unsigned char temp = 0;
temp = *p;
*p = *q;
*q = temp;
p++;
q--;
temp = *p;
*p = *q;
*q = temp;
printf("%#x --> %#x\n", m, n);
return 0;
}
字节序转换函数:h(host) n(network) l(long) s(short)
unint32_t htonl //主机转网络 4字节
uint16_t htons //主机转网络 2字节
uint32_t ntohl //网络转主机 4字节
uint16_t ntohs //网络转主机 2字节
//以 htonl 为例
#include <arpa/inet.h>
#include <stdio.h>
int main(){
unsigned int m = 0x12345678;
unsigned int n = htonl(m);
printf("%#x --> %#x\n", m, n);
return 0;
}
打印结果:0x12345678 --> 0x78563412
socket函数,也是一种特殊的文件描述符,一般叫它套接字
流式套接字SOCK_STREAM:TCP使用
数据包套机欸SOCK_DGRAM:UDP使用
原始套接字DOCK_RAW:可以对较低层次的协议,如IP/ICMP直接访问
IP地址:是主机在网络中的编号。
IP地址和MAC地址的区别:每张网卡在出厂时都会有一个唯一的标识,叫做MAC地址。
在局域网通信时,都是使用MAC地址通信的,交换机时工作在链路层的设备
如果在是网络中通信,要使用IP地址,路由器是工作在网络层的设备。
IP地址i分为IPV4(4字节32bit)和IPV6(16字节128bit)
为什么会有IPV4和IPV6之分?
因为IPV4地址不够用了。但也不是必须使用IPV6,因为现在有很多技术,都可以弥补IPV4数量不足的缺陷,
如NAT技术,一个IP地址可以经过路由器下发局域网IP地址,局域网内部同i性能,使用局域网的IP地址
如果数据走出局域网,会通过NAT技术,将数据包中的源IP地址从局域网IP替换成公网IP。
通过百度查询到的IP地址,是我们付费从运营商那里租来的。
IP地址的表示形式:192.168.60.55 叫做点分十进制,是字符串。在计算机中,是无符号的4字节整型。
IPV4地址组成:网络号和主机号。
IPV4地址分类:
网络号 主机号 规定最高位 范围 使用单位
A 1字节 3字节 0 0.0.0.0 - 127.255.255.255 政府/大公司/学校
B 2字节 2字节 10 128.0.0.0-191.255.255.255 中等规模的公司
C 3字节 1字节 110 192.0.0.0-223.255.255.255 个人
192.168.1.255 广播地址
D 1110 [224-239] 组播
E 11110 [240-255] 保留测试用的
子网掩码:是由一堆连续的1和连续的0组成的,用来和IP地址及进行与运算来获取网络号的,从未能限制某一网段内能容纳的最大主机数。
如,ip地址是192.168.70.8 子网掩码设置成 255.255.255.0
取与运算可以得到的结果:192.168.70.0 ----这是网络号,网络号相同时,才能进行通信
这时该网段内共有IP地址 256 个:
其中 192.168.70.0 是网络号,是不能占用的
192.168.70.255 是广播的地址,也不能占用
网关设备也需要占用一个IP地址,一般是同一局域网内可用的编号最小的。
192.168.70.1
所以能容纳的主机数:256-1-1-1(网关设备也可以算作一台IP主机) = 254
192.168.70.x 网段将子网掩码设置成 255.255.255.128,同一子网能容纳的最大主机数?
答案:这种方式可以将同一网段再划分成两个子网
第一个子网IP地址范围:192.168.70.0~192.168.70.127
第二个子网IP地址范围:192.168.70.128~192.168.70.255
其中每个子网中有需要减掉 网络号 广播地址 网关地址
所以子网掩码不一定都是255255255.0 网关设备的IP地址也不一定是编号最小的。
IP地址转换的函数:
inet_addr()
将strptr所指的字符串转换成32位的网络字节序二进制值。
in_addr_t inet_addr(const char *strptr);
inet_ntoa()
将32位网络字节序二进制地址转换成点分十进制的字符串。
char *inet_ntoa(stuct in_addr inaddr);
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, const char *argv[])
{
unsigned char ip_str[] = "192.168.70.10";
unsigned int ip_int = 0;
ip_int = inet_addr(ip_str);
unsigned char *p = (unsigned char *)&ip_int;
printf("%d.%d.%d.%d\n", *p, *(p+1), *(p+2), *(p+3));
//执行结果 192.168.70.10 ----网络字节序的无符号4字节整型
return 0;
}
端口号:为了区分一台主机接收到的数据包应该转交给哪个进程来处理,使用端口号来区分。
端口号范围:0-65535,使用unsigned short来存储。
常见的服务使用端口号:
FTP:21
SSH:22
TFTP:69
HTTP:80/8080
TCP的三次握手和四次挥手:
三次握手:
发生在建立连接的过程中的,有客户端主动发起,在客户端的connect函数(listen函数)和服务器的accept函数之间发生的
SYN:seq->SYN:seq,ACK->ACK
为什么要三次握手?两次或者四次行不行?
三次握手主要是为了确认通信双方首发数据的能力没有问题,也用来同步序列号seq。两次缺少一次确认,四次多余。
序列号时通信双方自己维护的一个随机值,自动增长,超过4字节就重新从0开始累加。
四次挥手:
在断开连接的过程中完成的,由主动断开连接的一方发起(一般是客户端)
FIN->ACK->FIN->ACK