4. 网络编程

0. 大纲:

网络编程三要素: IP地址、端口、协议、3次握手、4次挥手;
Socket套接字与TCP开发流程 :服务器端程序流程、客户端程序流程;
TCP编程:服务器端程序、客户端程序编写;

1. 网络编程三要素: IP、端口、协议

1.1 TCP协议 和 UDP协议:

TCP提供一种面向连接的、可靠的字节流服务。
① TCP是面向连接的 ;UDP是无连接的即发送数据前不需要建立连接;
② TCP提供可靠的服务 ,也就是说,通过 TCP连接传输的数据不会丢失、没有重复,并且按顺序到达;UDP没有可靠性;
③ TCP是面向字节流的,实际上是 TCP把数据看成一连串无结构的字节流;UDP是面向报文的。

1.2 TCP建立连接三次握手:

三次握手 就是指建立TCP连接 时,需要客户端和服务端总共发送3个包以确认连接的建立。
第一次握手 : 客户端向服务端发送请求,等待服务端确认;
第二次握手 : 服务端收到请求后知道客户端请求建立连接,回复给客户端以确认连接请求
第三次握手: 客户端收到确认后 ,再次发送请求给服务端,服务端收到正确请求后,如果正确则连接建立成功,完成三次握手,随后客户端与服务端之间可以开始传输数据了。

(详述第一次握手 : 建立连接时,客户端发送 syn包(syn=j)到服务器,并进入 SYN=SENT状态,等待服务器确认;(SYN:同步序列编号 Synchronize Sequence Numbers)
第二次握手 : 服务器收到 syn包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN包(SYN=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV状态;
第三次握手 : 客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=k+1),此时包发送完毕,客户端和服务器进入 ESTABLISHED(TCP连接成功)状态,完成第三次握手;

完成三次握手,客户端与服务器开始传送数据。)(下图红线指的是三次握手建立连接)

1.3 TCP断开连接四次挥手:

四次挥手 是指断开TCP链接 时需要经过4次确认。TCP连接是双向,A连接B、B连接A都要断开
第一次挥手 : 当主机A(可以是客户端也可以是服务端)完成数据传输后,提出停止TCP连接的请求;
第二次挥手 : 主机B收到请求后对其作出响应,确认这一方向上的TCP连接 将关闭;
第三次挥手 : 主机B端再提出反方向的连接 关闭请求;
第四次挥手 : 主机A对主机B的请求进行确认,双方向的关闭结束。(黑色线指四次挥手断开链接)

2. Socket套接字 与 TCP开发流程

2.1 Socket套接字:

网络编程 :也叫网络通信,Socket通信,即:通信 双方都独有自己的Socket对象 ,数据在Socket之间通过 数据报包(UDP协议) 或者 字节流(TCP协议) 的形式进行传输。

①定义:socket(简称套接字)是进程之间通信一个工具 ,好比现实生活中的插座,所有的家用电器要想工作都是基于插座进行,而进程之间进行网络通信需要基于socket

②语法:socket(套接字)能实现不同主机之间的进程间通信。Python中有专门的socket类:import socket;要使用socket,则通常要使用到socket模块下的socket类创建socket对象:tcp_socket= socket.socket(socket.AF_INET, socket.SOCK_STREAM)

函数名/参数 含义
socket(AddressFamily, Type) 用于创建一个socket对象。其中,参数AddressFamily(地址族)可以选择AF_INET 用于Internet进程间通信,实际工作中常用它; 参数Type表示套接字类型,可以是SOCK_STREAM流式套接字,主要用于TCP协议。
参数1:AddressFamily 地址族 。即:Ipv4 还是 Ipv6 ;默认值:AF_INET(Ipv4);AF_INET6(Ipv6)
参数2:Type 通信方式socket类型;即TCP 还是 UDP ;默认值:SOCK_STREAM(TCP);SOCK_DGRAM(UDP)

③示例:

python 复制代码
#演示socket对象的创建
import socket   #导入模块

#创建socket对象
tcp_socket= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#输出内容
print(tcp_socket)

#运行结果:
    # <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('0.0.0.0', 0)>

2.2 TCP开发流程:

服务器端程序流程、客户端程序流程图:

详述: socket()服务器端有socket,客户端也有socket;多个客户端对应一个服务器端,bind()绑定服务端的IP和端口号(以元组的形式),即服务器端指定了IP和端口;客户端connect()时根据此IP和端口连接;listen()最大监听数:允许最多有多少人等待即多个客户端同时申请的情况下,服务器端最多只能服务几个,如单线程的则服务一个,如5个则最多5个客户端连接,第6个过来需要等待连接;accept()等待监听即如果没有客户端与服务端连接则等待(如 开店老板没有顾客时等待),会返回一个元组:(元组的第一个参数是 负责和客户端交互的socket , 第二个参数是 客户端信息 ),(和客户端交互的socket 的理解:服务端socket()的socket是店主,当客户端socket()的socket来交互时,由accept()返回的元组的第一个参数 和客户端交互的socket 的socket与客户端的socket进行交互的,并不是由服务端socket()的socket与之交互的,因为(店主)它的职责是负责等待,真正交互的不是它);一直等到connect()连接;send()发送数据;recv()接收数据:客户端发服务端收,以及服务端发客户端收;客户端close()关闭客户端,服务端close()关闭的是与客户端交互的socket、不是socket()的socket (关闭接待完的店员,不是关店);

TCP服务器端:
TCP客户端:

代码:

server_socket.py

python 复制代码
"""
网编案例:服务端给客户端发送消息,客户端给服务端回执信息
服务器端开发流程:
    1.创建服务端socket对象
    2.绑定IP和端口号
    3.设置最大监听数
    4.等待客户端申请建立连接
    5.给客户端发送消息
    6.接收客户端的信息并打印
    7.释放资源
注意:客户端与服务端是通过 字节流(bytes) 的形式实现的!
"""
#导包
import socket

# 1.创建服务端socket对象:ipv4,字节流(TCP)
server_socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定IP和端口号
server_socket.bind(('127.0.0.1',8080))
# 3.设置最大监听数
server_socket.listen(5)
# 4.等待客户端申请建立连接
print(111)
accept_socket,client_info=server_socket.accept()
# 5.给客户端发送消息
accept_socket.send(b'Welcome to Python')
# 6.接收客户端的信息并打印
data=accept_socket.recv(1024).decode('utf-8')
print(f"服务器端收到来自{client_info}的数据:"+data)
# 7.释放资源
accept_socket.close()
# server_socket.close()  # 服务器端一般不关闭

client_socket.py

python 复制代码
"""
网编案例:服务端给客户端发送消息,客户端给服务端回执信息
客户端开发流程:
    1.创建客户端socket对象
    2.连接服务器端,指定:服务器端IP、端口号
    3.接收服务端的信息并打印
    4.给服务器端发送消息
    5.释放资源
注意:客户端与服务端是通过 字节流(bytes) 的形式实现的!
"""
#导包
import socket

# 1.创建客户端socket对象:ipv4,字节流(TCP)
client_socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.连接服务器端,指定:服务器端IP、端口号
client_socket.connect(('127.0.0.1', 8080))
# 3.接收服务端的信息并打印
data=client_socket.recv(1024).decode('utf-8')
print(f"客户端收到数据:"+data)
# 4.给服务器端发送消息
client_socket.send("Socket很有趣,很喜欢!".encode('utf-8'))
# 5.释放资源
client_socket.close()

2.3 字符串 str 与二进制 bytes 类型转换:

在网络中,数据是以二进制数据类型bytes的形式进行传递 的,所以在我们向网络传输数据的时候需要把数据转化成二进制,从网络中接受到的数据默认也是二进制类型的数据,想要正常使用 这些数据也需要 把这些数据从二进制类型数据转为字符串str型
①字符串str数据转换为二进制bytes类型 时,可使用如下函数:

encode(encoding) 用于把字符串编码转换为二进制数据,其中encoding表示编码格式,常设置为utf-8

②二进制bytes数据转换为字符串str类型 时,可使用如下函数:

decode(encoding) 用于把二进制数据解码转换为宇符串,其中encoding表示编码格式,常设置为utf-8

③说明:

1.编码(encode) 是把我们看懂的转成看不懂的:字符串.encode(码表);(不写默认utf-8编码)

2.解码(decode) 是把我们看不懂的转成看懂的:二进制.decode(码表);(不写默认utf-8编码)

3.只要是乱码了,原因一定是编解码不同;

4.数字、字母、特殊符号无论什么码表都只占一个字节,中文在gbk中占两个字节、utf-8中占三个字节;

5.二进制特殊写法:b'数字/ 字母/ 特殊符号',但该方式针对中文无效;

④代码示例:

python 复制代码
# 1.编码
s1="aB啦2@#"
print(s1.encode())       #运行结果:b'aB\xe5\x95\xa62@#'
print(s1.encode('utf-8'))#运行结果:b'aB\xe5\x95\xa62@#'
print(s1.encode('gbk'))  #运行结果:b'aB\xc0\xb22@#'

# 2.解码
bys=b'aB\xe5\x95\xa62@#'
print(type(bys))            #运行结果:<class 'bytes'>
print(bys.decode())         #运行结果:aB啦2@#
print(bys.decode('utf-8'))  #运行结果:aB啦2@#
print(bys.decode('gbk'))    #运行结果:报错
相关推荐
2301_814809861 小时前
PHP源码开发用二手硬件划算吗_性价比与稳定性权衡【操作】
jvm·数据库·python
Yyyyy123jsjs1 小时前
轻松通过Python调用外汇api获取汇率数据
开发语言·python
阿荻在肝了1 小时前
Agent学习五:LangGraph学习-节点与可控性
人工智能·python·学习·agent
2301_782659182 小时前
C#怎么操作PostgreSQL数据库 C#如何用Npgsql连接和操作PostgreSQL进行数据读写【数据库】
jvm·数据库·python
2401_897190552 小时前
CSS如何处理层级混乱问题_利用z-index与Stacking Context原理
jvm·数据库·python
m0_748839492 小时前
Golang怎么实现配置校验_Golang如何在启动时检查必填配置项是否缺失【技巧】
jvm·数据库·python
西西弗Sisyphus2 小时前
在 Python 中使用 Pydantic 的 BaseModel 进行数据验证
python·pydantic·basemodel
xcbrand2 小时前
政府事业机构品牌全案公司有哪些
大数据·人工智能·python
HP-Patience2 小时前
【Python爬虫】验证码识别技术
爬虫·python