感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:
① 2000多本Python电子书(主流和经典的书籍应该都有了)
② Python标准库资料(最全中文版)
③ 项目源码(四五十个有趣且经典的练手项目及源码)
④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)
⑤ Python学习路线图(告别不入流的学习)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
随着时代的发展,人们开始尝试在私有网络上搭建更大的私有网络,逐渐又发展演变为互联网,现在我们每个人几乎都能够享有互联网带来的便利
计算机网络就是把各个计算机相互连接,让网络中的计算机能够互相通信传递数据,而网络编程就是实现程序如何在两台计算机之间进行通信
既然网络编程能让两个程序进行通信,在网络中,程序是通过什么来找到另一个程序的?
套接字(socket),表示方式为点分十进制的lP地址后面写上端口号,中间用冒号或逗号隔开(IP地址:端口号)
有了套接字,不同计算机之间的程序就可以进行双向通信
一般两个程序间的通信对应的软件开发架构有两种——C/S 架构和 B/S 架构
C/S 架构
Client 与 Server
客户端与服务器端架构,这种架构是从用户层面(也可以是物理层面)来划分的
这里的客户端一般泛指客户端应用程序,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大
例如:QQ、微信、网盘
B/S 架构
Browser 与 Server
浏览器端与服务器端架构,这种架构也是从用户层面来划分的
浏览器,其实也是一种 Client,只是这个 Client 不需要大家去安装什么应用程序,只需在浏览器上通过 HTTP 请求 server 相关的资源(网页资源)
例如:百度、各种应用的网页版
socket
Python 提供了两个级别的网络服务模块:
- socket
- 低级别的网络服务模块,提供了标准的 BSD Sockets API,可以访问底层操作系统 Socket 接口的全部方法
- socketserver
- 高级别的网络服务模块,它提供了服务器中心类,可以简化网络服务器的开发
今天我们主要介绍 socket 模块
先导入 socket 模块
import socket
#语法
socket.socket([family[, type[, proto]]])
- family:套接字家族;可以是 AF_UNIX 或者 AF_INET
- type:套接字类型;可以根据是面向连接(TCP)的还是非连接(UDP)分为 SOCK_STREAM 或 SOCK_DGRAM
- protocol:一般不填默认为 0
server 端 socket 函数
函数 | 描述 |
---|---|
s.bind() | 绑定地址(host,port)到套接字在 AF_INET 中,以元组(host,port)的形式表示地址 |
s.listen() | 开始 TCP 监听backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量该值至少为 1,大部分应用程序设为 5 就可以了 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
client 端 socket
函数 | 描述 |
---|---|
s.connect() | 主动初始化 TCP 服务器连接一般 address 的格式为元组(hostname,port),如果连接出错返回socket.error 错误。 |
s.connect_ex() | connect()函数的扩展版本出错时返回出错码,而不是抛出异常 |
公共用途的 socket
函数 | 描述 |
---|---|
s.recv() | 接收 TCP 数据,数据以字符串形式返回,bufsize 指定要接收的最大数据量flag 提供有关消息的其他信息,通常可以忽略。 |
s.send() | 发送 TCP 数据,将 string 中的数据发送到连接的套接字返回值是要发送的字节数量,该数量可能小于 string 的字节大小。 |
s.sendall() | 完整发送 TCP 数据将 string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据成功返回 None,失败则抛出异常。 |
s.recvfrom() | 接收 UDP 数据,与 recv() 类似,但返回值是(data,address)其中 data 是包含接收数据的字符串,address 是发送数据的套接字地址。 |
s.sendto() | 发送 UDP 数据,将数据发送到套接字,address 是形式为(ip,port)的元组,指定远程地址。返回值是发送的字节数。 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址返回值通常是元组(ip,port)。 |
s.getsockname() | 返回套接字自己的地址通常是一个元组(ip,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout 是一个浮点数,单位是秒。值为None表示没有超时期。一般超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒如果没有设置超时期,则返回None。 |
s.fileno() | 返回套接字的文件描述符 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关连的文件 |
TCP 编程
如上图左边所示,server 进程首先要绑定一个端口并监听来自 client 的连接,如果某个 client 的连接过来了,server 就与 该 client 建立 socket 连接
所以 server 会打开端口(比如 80)监听,每来一个 client ,就创建该 socket 连接
考虑到会有大量的 client 与 server 进行连接,server要能够区分一个 socket 连接对应哪个 client
一个 socket 由四个元素组成:
- server 地址(目标地址)
- client 地址(源地址)
- server 端口(目标端口)
- client 端口(源端口)
除此之外,server 还需要同时响应多个 client 的请求,所以每个连接都需要一个新的进程或者新的线程来处理,否则 server 一次就只能处理一个 client 的请求了
我们来编写一个简单的 server 程序,它接受 client 连接,把 client 发过来的数据加上 hello 再返回给 client
首先创建一个基于 ipv4 和 TCP 协议的 socket 对象
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
然后我们绑定监听的地址和端口(可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0
绑定到所有的网络地址,还可以用127.0.0.1
绑定到本机地址)
这里我们是通过本机来实现 C/S 架构,所以绑定到 127.0.0.1 上,而且不要绑定端口号小于 1024 的端口(要有管理员权限才能绑定)
ps:端口复用
我们知道 TCP 关闭连接有一个四次挥手的过程,当 server 主动关闭连接时,会有一个TIME_WAIT(时间等待)状态,等待 2MSL(最长报文段寿命)后进入关闭状态
那么在这个 TIME_WAIT 状态下,端口还处于被别的进程绑定的状态之中,那么其他进程就会拿不到这个端口,产生报错
我们可以通过端口复用来解决这个问题
#提示:socket.setsockopt()方法要在 socket.bind()之前设置
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
level:设置哪个级别的 socket, socket.SOL_SOCKET 表示当前socket
option:设置什么内容(权限) socket.SO_REUSEADDR 端口复用
value:True:表示复用,False,表示不复用
#绑定本地9999端口
s.bind(('127.0.0.1', 9999))
接着开始监听端口,参数为指定等待连接的最大数量
#监听的连接数最多为5
s.listen(5)
print('Waiting for connection...')
server 程序通过一个 while 循环来接受来自 client 的连接,accept()
会等待并返回一个 client 的连接
当有 client 来连接时,就创建一个线程来处理会话
while True:
sock, addr = s.accept()
t = threading.Thread(target=tcplink, args=(sock,addr))
t.start()
连接建立后,server 首先返回一条欢迎消息,然后等待 client 的数据,收到数据之后并加上 hello 再发送给 client
如果没有数据或者 client 发送了 exit 字符串就关闭连接
def tcplink(sock,addr):
print('Accept new connection from %s:%s...' % addr)
#返回欢迎信息
sock.send(b'hello!')
#当 client 发送数据时,返回 hello+数据给 client
while True:
data = sock.recv(1024)
time.sleep(1)
#如果 client 不发送数据或者发送 exit,退出连接
if not data or data.decode('utf-8') == 'exit':
break
else:
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
接下来我们编写一个 client 程序
创建一个基于 ipv4 和 TCP 协议的 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
客户端要主动发起 TCP 连接,必须知道服务器的 IP 地址和端口号
#注意参数是一个tuple,包含地址和端口号
s.connect(('127.0.0.1', 9999))
TCP 连接创建的是双向通道,双方都可以同时给对方发数据。但是谁先发谁后发,怎么协调,要根据具体的协议来决定
例如,HTTP协议规定 client 必须先发请求给 server,server 收到后才发数据给 client
接收数据时,调用 recv(max) 方法,一次最多接收指定的字节数
mes = s.recv(1024)
#接收到的数据是 byte 格式,需要转码
print(mes.decode('utf-8'))
我们将数据发送给 server,并接收 server 返回的数据
如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费学习大礼包,带大家一起学习,给大家剖析Python兼职、就业行情前景的这些事儿。
一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、学习软件
工欲善其必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
三、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
四、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
四、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
五、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!