一、客户端/服务器架构
1.硬件C/S架构(打印机)
打印机作为一个服务端,电脑连接打印机进行打印
2.软件C/S架构
互联网中处处是C/S架构
如谷歌网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种)
腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看它的视频)
C/S架构与socket的关系:
我们学习socket就是为了完成C/S架构的开发
二、什么是tcp/ip协议
计算机之间通讯需要遵循一定的互联网协议,比如tcp/ip协议,大量的计算机之间进行通讯组成了计算机网络,网络的核心即一堆协议,协议即标准,由于tcp/ip协议太过于复杂,这时需要用socket层对tcp/ip协议进行精简,提供相应的接口以便更加方便的调用。所以学习socket一定要先学习互联网协议。
互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层
每层运行常见物理设备
TCP/IP 是一类协议系统,它是用于网络通信的一套协议集合,传统上来说 TCP/IP 被认为是一个四层协议。
1) 网络接口层:
物理层:主要是指物理层次的一些接口,比如电缆等.
提供计算机互通的物理介质, 基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0
数据链路层:
定义电信号的分组方式,使用以太网协议封装数据格式(数据报头(18个字节双方地址+数据类型)+数据)
2) 网络层:
提供独立于硬件的逻辑寻址,实现物理地址与逻辑地址的转换.
在 TCP / IP 协议族中,网络层协议包括 IP 协议(网际协议),ICMP 协议( Internet 互联网控制报文协议),以及 IGMP 协议( Internet 组管理协议).
网络层引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址(IPV4/IPV6)
3) 传输层:
为网络提供了流量控制,错误控制和确认服务.
在 TCP / IP 协议族中有两个互不相同的传输协议: TCP(传输控制协议)和 UDP(用户数据报协议).
建立端口到端口的通信(应用软件使用的端口号)。
4) 应用层:
为网络排错,文件传输,远程控制和 Internet 操作提供具体的应用程序
数据包在 TCP / IP 协议中数据先由上往下将数据装包,然后由下往上拆包
在装包的时候,每一层都会增加一些信息用于传输,这部分信息就叫报头,当上层的数据到达本层的时候,会将数据加上本层的报头打包在一起,继续往下传递.
在拆包的时候,每一层将本层需要的报头读取后,就将剩下的数据往上传.
这个过程有点像俄罗斯套娃,所以有时候人们也会用俄罗斯套娃来形容这个过程.
tcp的三次握手四次挥手
三次握手:1.客户端对服务端发送同步请求(建立连接通道);2.服务端响应后,发送同步请求(建立连接通道)和发送确认数据(这里的两个请求被合并成一个了);3.客户端向服务端发送确认数据。
四次挥手:1.客户端发送端口结束包给服务端,2.服务端收到以后返回确认信息给客户端;3.服务端发送端口结束包给客户端;4.客户端确认信息返回给服务端。
区别:四次挥手的过程中,服务端返回给客户端的确认信息之后不会立刻关闭,有可能会继续给客户端发送数据,所以必须得有四次挥手
三、socket是什么
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。
没有socket之前
有socket之后
为什么socket翻译为套接字?
socket中文翻译为套接字,socket英文本义为孔和插座的意思。
套接字发展史及分类
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
*基于文件类型的套接字家族*
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
*基于网络类型的套接字家族*
套接字家族的名字:AF_INET
还有AF_INET6被用于ipv6,还有一些其他的地址家族,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族.
*family(socket家族)*
- socket.AF_UNIX:用于本机进程间通讯,为了保证程序安全,两个独立的程序(进程)间是不能互相访问彼此的内存的,但为了实现进程间的通讯,可以通过创建一个本地的socket来完成
- socket.AF_INET:(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)
*socket type类型*
- socket.SOCK_STREAM #for tcp
- socket.SOCK_DGRAM #for udp
- socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
- socket.SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
- socket.SOCK_SEQPACKET #废弃了
套接字工作流程
一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。
服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束.
socket函数
服务端套接字函数
- s.bind() 绑定(主机,端口号)到套接字
- s.listen() 开始TCP监听
- s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
- s.connect() 主动初始化TCP服务器连接
- s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
- s.recv() 接收数据
- s.send() 发送数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完,可后面通过实例解释)
- s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
- s.sendto() 发送UDP数据
- s.recvfrom()接收UDP数据 Receive data from the socket. The return value is a pair (bytes, address)
- s.getpeername() 连接到当前套接字的远端的地址
- s.close() 关闭套接字
- socket.setblocking(flag) #True or False,设置socket为非阻塞模式,以后讲io异步时会用
- socket.getaddrinfo(host, port, family=0, type=0, proto=0, flags=0) 返回远程主机的地址信息,例子 socket.getaddrinfo('google.com',80)
- socket.getfqdn() 拿到本机的主机名
- socket.gethostbyname() 通过域名解析ip地址
- s.getsockopt() 返回指定套接字的参数
- s.setsockopt() 设置指定套接字的参数
面向锁的套接字方法
- s.setblocking() 设置套接字的阻塞与非阻塞模式
- s.settimeout() 设置阻塞套接字操作的超时时间
- s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
- s.fileno() 套接字的文件描述符
- s.makefile() 创建一个与该套接字相关的文件
参考链接
https://www.zhihu.com/question/21383903