前面的进程间通信最后一个socket是网络方面的知识,现在来引入网络的基础概念吧。
一.网络基础篇
Internet历史:
1.1957年,前苏联卫星上天
2.1958年,美国建立ARPA(国防部高级研究计划署)
3.1968年,ARPA提出 资源共享计算机网络,简称ARPAnet,“阿帕网”,实现互联不同的计算机
4.早期的ARPAnet使用的网络控制协议NCP(network control procotol)。
TCP/IP 协议:Internet中的“世界语”。
1.TCP:用来检测网络传输中的出错,并具备一定的纠错能力。
2.IP协议:实现互联网不同类型的操作系统和计算机的网络连接。
网络体系结构:
由于网络是非常复杂的,因此采用分而治之的方法设计。
因此网络体系结构是指 网络的层次结构和每层使用的协议的集合。
OSI体系结构:七层模型,理想化的模型,尚未完成实现。
1.应用层:主要是对一些应用程序,获得要传输的数据。
2.表示层:对数据进行 格式定义,加密或者 转换。
3.会话层:建立通信进程的 逻辑名字和物理名字之间的联系。
4.传输层:提供可靠数据传输,差错处理及恢复(TCP),流量控制(UDP)。
5.网络层:数组分组.路由选择。
6.数据链路层:数据组成 可发送和 接收的帧
7.物理层:传输物理信号等,硬件层面。
与七层有关的例子:
1.两路交换机:用到数据链路层的交换(硬件)
2.三路交换机:网络层的交换(软件)
TCP/IP体系结构:Internet 事实上的工业标准
1.应用层:负责处理特定的应用程序细节,应用层面面向不同的网络应用引入不同的应用层协议
常用协议(http:超文本传输,ftp:文件传输,dns:域名解析协议,SMTP:邮件传输协议)
2.传输层:确定数据包交给主机上的哪个任务
常用协议(TCP.UDP)
3.网络层:实现端到端的传输
常用协议(IP:互联网络.ICMP:互联网络控制管理协议ping.IGMP:广播.组播)
4.网络接口和物理层:屏蔽硬件差异,向上层提供统一的接口
常用协议(ARP:地址解析协议 IP地址:MAC地址
RARP:逆地址解析协议 MAC地址:IP地址)
TCP/IP协议族
TCP/IP协议通信模型
TCP/IP协议:
1.MTU(max transform unit):最大传输单元,1500字节
2.MSS(maxitum segment size):最大报文长度【app header + user data=1460】
TCP协议和UDP协议
1.TCP协议:传输控制协议,面向连接,数据安全可靠(数据无失序.无重复.无丢失)
常用场景:密码传输QQ,微信的登陆注册
大量的数据传输
特点:面向连接,建立连接管道,因此数据传输效率相对较低
2.UDP协议:传输控制协议,无连接,不保证数据的安全可靠性
常用场景:少量图片数据传输
音视频,媒体流量数据传输
无线网络
广播.组播通信
特点:由于无连接,不用建立连接管道,因此数据传输效率相对高。
OSI模型和TCP/IP对应:
二.网络编程基础篇
预备知识
1.socket
(1)独立于具体协议的网络编程接口
(2)在OSI模型中,主要在会话层和传输层
(3)是一个文件描述符(套接字)
(4)可用于TCP.UDP.IPX通信
2.socket的类型
(1)流式套接字(SOCK_STREAM):提供一种面向连接的服务,用于TCP传输控制协议
(2)数据报套接字(SOCK_DGRAM):提供无连接的服务,用于UDP通信。
(3)原始套接字(SOCK_RAW):提供底层通信(IP.ICMP.IGMP)
3.IP地址:网路中标识主机的编号,常以点分形式存在(例如“192.168.2.177”)
1.IPV4地址:整个ip占32位,每段8位表示0-255
IPV6地址: 整个ip占128位
2. ip地址组成: 网络号 + 主机号 列如“192.168.2”+“177”
其中“2”表示网段号,也就是在哪个路由网络中(网络号+1)
3.网络ip分类:主要ip的第一段前8位数据组成
A类网:0~127 子网掩码:255.0.0.0
B类网:128~191 子网掩码:255.255.0.0
C类网:192~223 子网掩码:255.255.255.0
D类网:224~239 组播地址
E类网:240~255保留测试地址
4.私有IP地址范围
5.子网掩码 :例如:255.255.255.255.0(c类网)
6.已知,计算机网络号:ip&(umask)=“192.168.2.177”&((255.255.255.0))=“192.168.2”
主机号: ip&(~umask)=“192.168.2.177”&(~(255.255.255.0))=“177”
注意:这是c类网的例题
4.由于网络中识别2进制的数据,因此ip地址必须进行转换
1.将代码字符串的ip地址转换成 网络字节序 二进制,并返回转换后的地址
in_addr_t inet_addr(const char *strptr);
头文件:
#include <arpa/inet.h>
参数:
strptr:代码中的字符串 ip(主机字节序的ip地址)
返回值:
成功:返回网络字节序二进制的首地址
2、将网络字节序的二进制 转换成 主机字节序的 ip
char *inet_ntoa(stuct in_addr inaddr);
头文件:
#include <arpa/inet.h>
参数:
inaddr:网络字节序的 ip地址
返回值:
成功:主机字节序的 ip字符串 首地址。
5.字节序:数据的存储顺序(方式)
小端序:低序字节存储低地址
Ubuntu采用小端序,也就是主机字节序
大端序:低序字节存储高地址
网络采用大端序,也就是网络字节序
例如:0x1122 ————>11 高字节
6.端口号:在主机中标识处理网络数据的进程,也就是进程ID号
总所周知端口号:1~1023 (用户一般不能使用)
已登记的端口号:1024~49151
动态端口号: 49152~65535
(1)主机字序转网络字节序
u_long htonl(int port); //host to network long
u_short htons(int port); //host to network short
(2)网络字节序转主机字节序
u_long ntohl(u_long hostlong); //network to host long
u_short ntohs(u_short hostshort); //network to host short
7.
客户端:与用户进行数据交互的界面程序,即 上位机。
服务器:为客户端提供数据服务的后台软件。
8.基于 tcp的服务器编程流程(框架)
(1)创建套接字 socket()
(2)绑定 bind()
(3)监听 listen()
(4)接受连接 accept()
(5)数据交互 recv/send read/write
(6)关闭 close()
9.api接口
(1)函数原型socket()
1、函数原型:
int socket(int domain, int type, int procotol);
功能:
创建套接字,打开网卡设备,设置套接字类型
头文件:
#include <sys/types.h>
#include <sys/socket.h>
参数:
domain: ip地址协议族 AF_INET(ipv4协议)
type : 套接字类型 SOCK_STREAM
protocol: 通常为 0
返回值:
成功:返回套接字(网卡的文件描述符)
失败:返回-1,并设置错误信息
(2) 函数原型bind()
int bind(int sockfd, struct sockaddr *addr, size_t size);
功能:
将ip地址、端口号 与 套接字进行绑定,将ip和端口共享到网络中。
头文件:
同上
参数:
sockfd: 套接字,socket函数成功的返回值
addr : 通用协议地址结构体的首地址
size : 结构体的大小
返回值:
成功:返回 0
失败:返回-1,并设置错误信息
通用协议地址结构体:
struct sockaddr {
sa_family_t sa_family; //地址协议族 AF_INET
char sa_data[14];
}
Internet协议地址结构体:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
结构体头文件: #include <arpa/inet.h>
填写ip地址和端口号
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9527);
// INADDR_ANY (0.0.0.0) means any address for binding;
addr.sin_addr.s_addr = inet_addr("0.0.0.0");
(3)函数原型listen()
int listen(int sockfd, int backlog);
功能:
设置监听套接字,设置 客户端连接请求队列的长度,
也就是设置同一时刻能接受的最大请求数。
监听完成就是启动服务器,套接字变成监听套接字
参数:
sockfd:套接字
backlog:请求队列的长度,在内核中开辟的。
返回值:
成功:返回 0
失败:返回-1,并设置错误信息
(4)函数原型accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *len);
功能:
阻塞等待,接受客户端连接,建立通信管道。
如果 请求队列中没有客户端的请求,该函数就阻塞。有就立即接受连接,建立通道。
参数:
sockfd:监听套接字
addr :结构体首地址(存储连接成功的客户端ip、端口号的结构体首地址)
len :存储结构体的大小(存储客户端信息的结构体首地址)
返回值:
成功:返回连接套接字(通信管道的id号),标识成功的客户端。
失败:返回-1,并设置错误信息
注意:
1、如果不需要保存客户端ip地址和端口号,则第2、3参数 传递 NULL。
2、该函数调用一次 就只能接受一个 客户端连接
(5)数据交互
read()
函数原型:
ssize_t read(int connfd, void *buf, size_t size);
参数:
connfd:连接套接字(通信管道id)
recv()
ssize_t recv(int connfd, void *buf, size_t len, int flags);
参数:
flags:阻塞与非阻塞模式,通常0表示阻塞。
注意:
1、read读数据,默认为阻塞模式,如果读缓冲区有数据立即返回,无数据就等待
2、recv读数据可以设置 模式
3、当 连接断开时,read或recv立即返回 0值
write()
ssize_t write(int connfd, void *buf, size_t size);
参数:
connfd:连接套接字(通信管道id)
ssize_t send(int connfd, void *buf, size_t len, int flags);
参数:
flags:阻塞与非阻塞模式,通常0表示阻塞。
(6)int close()
int close(int sockfd);