python17-socket网络编程基础

Posted liangjiongyao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python17-socket网络编程基础相关的知识,希望对你有一定的参考价值。

一、客户端/服务器架构

1.硬件(你的电脑跟打印机)

2.软件C/S架构

淘宝首页是服务器端,你的电脑的浏览器是客户端(这种也叫B/S架构)

百度云上的资源跟你的百度云客户端

 

你扯这么多,到底C/S架构跟socket有什么关系?

学习socket就是为了完成C/S架构的开发,阿拉索。

 

二、OSI七层协议

互联网的核心就是由一堆协议组成,协议就是标准,要想开发一款基于网络通信的软件,就必须遵循这些标准

技术分享图片

先要回顾一些概念:

ip:标识一台机器位于哪个子网

mac:标识子网中的某台机器

端口号:标识某个应用

ip+端口号:标识互联网中唯一一个应用程序

程序的PID:标识同一台机器上不同的进程或者线程,不能用来区分应用程序,因为有些程序不止一个进程

 

咦,奇怪了,上面那个图找来找去都没有看到socket?莫急,待我优化优化

技术分享图片

socket位于应用层与传输层之间,为什么?

你想想,数据最先产生于应用层,然后往下层层封装,最后发出去。既然应用层的数据要发出去,必须要遵循tcp/ip协议的,那是不是意味着你也要弄懂tcp/ip协议?No!没那么多精力和时间,考虑到这一点,socket层应运而生。

 

三、什么是socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

 

四、套接字的发展史

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

注意:进程间是不能直接通信(你的QQ能直接发信息给你的微信吗)

 

基于文件类型的套接字家族:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

 

基于网络类型的套接字家族:AF_INET

还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET

 

五、套接字工作流程

一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。

技术分享图片

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

 

六、最简单socket客户端和服务端

服务器端

技术分享图片
import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买电话
phone.bind(("127.0.0.1",800)) #买电话卡
phone.listen(5) #开机,其实这里是设置最大连接数
print("等待电话中...")
conn,addr=phone.accept() #等待电话连接,直达拿到一个电话连接

msg=conn.recv(1024) #接收消息
print("客户端发来的消息是:",msg)
conn.send(msg.upper()) #返回消息

conn.close() #挂电话
phone.close() #关机
View Code

客户端

技术分享图片
import socket

phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买个电话

phone.connect(("127.0.0.1",800)) #拨通电话
phone.send("hello".encode("utf-8")) #发送消息
data=phone.recv(1024) #接收消息
print("收到服务端发来的消息:",data)

#注意:客户端没有conn连接
View Code

有些时候我们在重启服务端的时候会出现这种情况:

技术分享图片

表面原因:前面关闭的时候程序清理得不干净

深层原因:你的服务端仍然存在四次挥手的time_wait状态在占用地址

 

七、TCP/IP三次握手四次挥手

技术分享图片

 

TCP/IP三次握手

step1:客户端发起第一次握手,请求建立连接
step2:服务端发送确认并请求建立连接(客户端到服务端链接已建立完毕)
step3:客户端发送确认给服务端(服务端到客户端链接已建立完毕)

什么是syn洪水攻击

黑客利用tcp/ip的漏洞,模拟一大堆假客户端发送SYN请求之后就跑路,由于服务端对这些SYN请求进行一一回应,占用了大量的资源,最后导致新的请求无法响应。

 

什么是半连接

只要没到“客户端发送确认给服务端”这一步都统称“半连接”

 

什么是半连接池

每来一个请求放到backlog,服务端每次从backlog取出一个连接,再做syn响应

conn.listen(5)就是半连接池,表示最大挂起的连接数为5。由于黑客可以模仿大量连接挤爆你的半连接池,所以,该值需要根据实际情况调。

conn.accept()相当于拿到一个TCP连接,就是服务端与客户端的双向连接

conn.close()触发的是四次挥手

phone.close()是关闭socket

 

注意:第一,服务端是可以主动发消息的;第二,TCP连接的可靠在于数据不丢失

 

TCP/IP四次挥手

客户端到服务端的数据发完了,客户端到服务端的连接就会断开
服务端到客户端的数据发完了,服务端到客户端的连接就会断开

 

为什么断开是四次,而握手是三次?

其实三次和四次的区别取决于中间那两步能够合并。挥手的时候是不可以合并的,以防服务端到客户端的数据还没发完就断开,导致数据丢失。但是三次握手还没涉及到数据传输,不存在数据丢失的问题,所以中间的那两步可以合并成一步。

 

服务器time_wait原因的分析

首先要知道的一点是:FIN_wait表示断开的主动发起方,有time_wait状态的代表的主动断开的一方

在大并发的场景中,服务器会存在大量的time_wait。这是由于服务端是不会保留客户端的连接,一旦完成服务端到客户端的数据传输后,服务端就会首先断开连接,因为多等你一分钟就是浪费自身的资源。现实生产中的多数情况都是服务器首先断开连接。

为了方便你理解,我画了一个服务器端断开的挥手图,跟TCP的四次挥手的两端是反过来的,因为是服务器先开始断开的。正因为服务器先断开了,所以一直收不到客户端发过来的断开请求,也就是“客户端到服务器端”这一条连接还在。所以你在关闭服务端后,在间隔很短后再起服务,就会出现地址被占用。

技术分享图片

 




以上是关于python17-socket网络编程基础的主要内容,如果未能解决你的问题,请参考以下文章

20155201 李卓雯 《网络对抗技术》实验一 逆向及Bof基础

20155307刘浩《网络对抗》逆向及Bof基础

20155311高梓云《网络对抗》逆向及Bof基础

20145301赵嘉鑫《网络对抗》逆向及Bof基础

RK3399平台开发系列讲解(网络篇)5.17Socket内核数据结构

RK3399平台开发系列讲解(网络篇)5.17Socket内核数据结构