套接字通信就是网络通信
在网络通信时,客户端和服务器的比例是N:1
服务器如何处理多个客户端的请求
并发处理方式
1.多线程并发处理->线程池并发处理,线程池可以对多个线程进行管理
2.多进程->进程池
3.io多路转接,使用select或者epoch进行处理,使用io转接函数,可以在单线程的情况下处理多个客户端的请求,如果io转接搭配多线程使用就可以大大提高工作效率
4.使用开源框架:livenent开源的网络通信框架,天然支持高并发
客户端业务流程复杂
需要同时进行软件的上传和下载,在这种情况下就需要和服务器端建立多个连接,这样才能提高效率,就可以在客户端创建一个套接字连接池,每个连接对应一个要处理的业务流程,因为发起了多个连接,每个连接都需要处理,这时候就需要使用多线程,因此套接字连接池和多线程是 搭配使用的,同样的,也可以套接字连接池和线程池搭配使用
由于c++里面没有用于通信的套接字类,需要基于c语言的api封装出对应的用于通信的c++类
1.概念
局域网和广域网
局域网:局域网将一定区域内的各种计算机、外部设备和数据库连接起来形成计算机通信的私有网络。
广域网:又称广域网、外网、公网。是连接不同地区局域网或城域网计算机通信的远程公共网络。
ip:网络协议。ip地址用来表示计算机在网络中的地址
端口:用端口来标识进程地址
ip+端口就可以知道是哪台电脑的哪个进程
iso/osi模型
应用层
表示层 应用层
会话层
传输层 传输层 tcp,udp 传输层协议
网络层 网络互联层 ip协议(ipv4,ipv6)
数据链路层 网络接口层 以太网帧协议(底层协议不需要搞明白,只需要搞明白对应的套接字接口怎么去调用,以及套接字通信的流程)
物理层
物理层:负责最后将信息编码成电流脉冲或其它信号用于网上传输
数据链路层:
数据链路层通过物理网络链路供数据传输。
规定了0和1的分包形式,确定了网络数据包的形式;
网络层
网络层负责在源和终点之间建立连接;
此处需要确定计算机的位置,通过IPv4,IPv6格式的IP地址来找到对应的主机
传输层
传输层向高层提供可靠的端到端的网络数据流服务。
每一个应用程序都会在网卡注册一个端口号,该层就是端口与端口的通信
会话层
会话层建立、管理和终止表示层与实体之间的通信会话;
建立一个连接(自动的手机信息、自动的网络寻址);
表示层:
对应用层数据编码和转化, 确保以一个系统应用层发送的信息 可以被另一个系统应用层识别;
网络协议:全世界都认可的在网路通信过程中使用的一种数据的固定通信格式
数据是怎么在计算机之间进行传递的
我们要发送的数据都是应用层的数据,应用层的数据可以使用应用层的协议(比如ftp,http)进行包装,应用层包装好之后继续向下传递就到了传输层,传输层还需要继续进行打包,打包之后还需要再次向下传递就到了网络层,网络层继续向下传递就到了网络接口层,数据再次打包得到一个报文,这个报文通过网口发送给对方,对方计算机接收到这个数据之后,先对网络接口层的这个数据进行解包操作,解出来后就得到了网络层的一个数据包,网络层继续向上传递就到了传输层,数据在传输层解剖继续向上传递到达应用层,就需要由程序员去处理,先看看我们的数据有没有被应用层的协议进行封装,如果封装了,程序员自己把他解开,比如基于http进行解包才能拿到原始数据。但如果没有使用相关协议对应用层数据进行打包,那么我们从传输层拿到数据就是原始数据了,直接处理就可以了
应用层以下,程序员默认情况下不需要做任何处理的,这些都是由内核来完成的,我们只需要把应用层这个数据搞清楚就行了
应用层数据就两种情况:1.不进行数据的打包
2.打包的数据 如果说对应用层的数据进行了封装,接收到这个数据之后需要在应用层把这个数据按照发送端的协议格式再解开就能得到原始数据
在网络通信的时候, 程序猿需要负责的应用层数据的处理(最上层)
应用层的数据可以使用某些协议进行封装, 也可以不封装
程序猿需要调用发送数据的接口函数,将数据发送出去
程序猿调用的API做底层数据处理
传输层使用传输层协议打包数据
网络层使用网络层协议打包数据
网络接口层使用网络接口层协议打包数据
数据被发送到internet
接收端接收到发送端的数据
程序猿调用接收数据的函数接收数据
调用的API做相关的底层处理:
网络接口层拆包 ==> 网络层的包
网络层拆包 ==> 网络层的包
传输层拆包 ==> 传输层数据
如果应用层也 使用了协议对数据进行了封装,数据的包的解析需要程序猿做
套接字通信就是网络通信就是socket通信
socket:研发的一套接口
问题:在发送端把数据封装好后,肯定要把它先存到一块内存中,然后再通过网络进行发送,接收端收到这个数据后,也是要先把数据存到一块内存中,然后再进行解析
如果发送端A和接收端B在内存中存储数据的顺序不一致(比如发送端从低地址位到高地址位存储123456,而接收端可能是654321这样),就会导致在接收端解析不出来发送端相同的数据
所以必须要求两段在内存中处理数据的顺序是一致的,即要制定一个规则,即指定数据在发送过程中的字节序(即数据在内存中的存储顺序)
字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,也就是说对于单字符来说是没有字节序问题的,字符串是单字符的集合,因此字符串也没有字节序问题。
对于int long这些非单字节结构的数据类型,它们都需要由多个字节才能够组成一个完整的整体
数据在内存中的存储顺序主要有两种,分别是大端(网络字节序)和小端(主机字节序),通常所用的pc机在内存中的存储顺序,就是按照小端的顺序存储的,在进行网络通信的时候,数据是按照大端来存储的,比如在套接字通信的时候发送的数据需要把数据从小端转换成大端进行发送,接收到数据之后,还需要把大端转换成小端在本地主机上进行存储
小端(主机字节序):数据的低位字节存储到低地址位,高位字节存储到高地址位(低低高高)
大端(网络字节序):相反(低高高低)
大小端相互转换的操作函数
#include <arpa/inet.h>
// u:unsigned
// 16: 16位, 32:32位
// h: host, 主机字节序
// n: net, 网络字节序
// s: short
// l: int
//这组函数主要是对16位和32位的整形数进行转换
// 这套api主要用于 网络通信过程中 IP 和 端口 的 转换
// 将一个短整形从主机字节序 -> 网络字节序
uint16_t htons(uint16_t hostshort);
// 将一个整形从主机字节序 -> 网络字节序
uint32_t htonl(uint32_t hostlong); // 将一个短整形从网络字节序 -> 主机字节序
uint16_t ntohs(uint16