网络编程指的是:在程序中实现两台计算机之间的通信。 Python提供了大量的内置模块和第三方模块用于支持各种网络访问,而且Python语言在网络通信方面的优点特别突出,远远领先其他语言。
目录
一,网络编程基本概念
1,什么是IP地址?
2,IP地址的分类
2.1 公有地址
2.2 私有地址
3,本地服务器IP地址
4,Windows下常用的ip命令
5,什么是子网?子网掩码?
6,什么是网关?
7,什么是交换机?
8,什么是路由器?
9,什么是路由?
10,子网下的设备如何访问互联网?
11,什么是端口?
11.1 端口分配
11.2 公认端口(Well Known Ports):
11.3 注册端口(Registered Ports):
二,网络通信协议
1,一张神图
2,OSI网络协议七层模型
3,TCP/IP协议模型
4,TCP和UDP的区别?
4.1 TCP
4.2 UDP
4.3 TCP和UDP区别
5,TCP建立链接的三次握手
6,TCP断开连接的四次挥手
7,数据包与处理流程
7.1 什么是数据包?
7.2 数据包处理流程
三,socket套接字编程
1,什么是套接字编程?
2,socket()函数介绍
3,socket对象的方法一览
4,UDP编程实例
4.1 单工最简案例
4.2 单工持续通信
4.3 双工持续通信
5,TCP/IP编程实例
5.1 TCP/IP编程简介
5.2 TCP编程的实现过程
5.3 TCP单工通信服务端
5.4 TCP单工通信客户端
5.5 TCP单工持续通信服务端
5.6 TCP单工持续通信客户端
5.7 TCP双工持续通信服务端
5.8 TCP双工持续通信客户端
IP是Internet Protocol Address,即"互联网协议地址"。互联网之间的通信相当于快递收发,需要知道每个电脑的详细地址才能实现数据的准确收发。
IP地址用来标识网络中的一个通信实体的地址。通信实体可以是计算机、 路由器等。
IP地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读。
127.0.0.1本机地址。192.168.0.0--192.168.255.255为私有地址,属于非注册地址,专门为组织机构内部使用。
路由器具备WAN口和多个LAN口。它实际上是网关和交换机的结合体。wan口与宽带公司机房相连,LAN口与局域网设备相连。
通过网关设备里面的NAT技术,即网络地址转换技术。
同一台设备下有很多的应用程序,但是网卡只有一个,数据通过网卡获得和发送,如何确定接收的数据到底是哪一个程序的呢?发给QQ的数据不可能被微信接收。利用端口可以解决这个问题。
OSI模型制定的七层标准模型,分别是:应用层, 表示层,会话层,传输层,网络层,数据链路层,物理层。
三次握手建立TCP连接时的状态。
第一次: 当主机A完成数据传输后,将控制位FIN置1,提出停止TCP 连接的请求 ;
第二次: 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1;
详细流程如下图。
Socket编程封装了常见的TCP、UDP操作,可以实现非常方便的网络编程。
在Python语言标准库中,通过使用socket模块提供的socket对象,可以在计算机网络中建立可以互相通信的服务器与客户端。在服务器端需要建立一个socket对象,并等待客户端的连接。客户端使用socket对象与服务器端进行连接,一旦连接成功,客户端和服务器端就可以进行通信了。
注意:我们可以看出socket通讯中,发送和接收数据,都 是通过操作系统控制网卡来进行。因此,我们在使用之后,必须关闭socket。
socket语法格式如下:socket.socket([family[, type[, proto]]]) ;
family的参数值有:AF_UNIX 或者 AF_INET ; AF 表示ADDRESS FAMILY 地址族,AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型;而AF_UNIX 则是 Unix 系统本地通信。
type的参数值有:type : 套接字类型可以根据是面向连接的还是非连接分为 SOCK_STREAM 或 SOCK_DGRAM ;
protocol : 一般不填,默认为0。
Socket主要分为面向连接的Socket和无连接的Socket。 无连接Socket的主要协议是用户数据报协议,也就是常说的UDP, UDP Socket的名字是 SOCK_DGRAM 。创建套接字UDP/IP套接字,可以 调用 socket.socket() 。示例代码如下: udpSocket=socket.socket(AF_INET,SOCK_DGRAM)
from socket import *
# 最简化的UDP服务端代码
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字对象
s.bind(("127.0.0.1", 8888)) # 绑定端口,ip可以不写
print("等待接收数据!")
recv_data = s.recvfrom(1024) # 1024表示本次接收的最大字节数
print(f"收到远程信息:{recv_data[0].decode('gbk')},from {recv_data[1]}")
s.close()
udp客户端:
from socket import *
# 最简化的UDP客户端发送消息代码
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字
server_addr = ("127.0.0.1", 8888)
data = input("请输入:")
s.sendto(data.encode("gbk"), server_addr)
s.close()
udp服务端:
from socket import *
# 持续通信
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字
s.bind(("127.0.0.1", 8888)) # 绑定端口,ip可以不写
print("等待接收数据!")
while True:
recv_data = s.recvfrom(1024) # 1024表示本次接收的最大字节数,recvfrom一直监听知道由数据被接受
recv_content = recv_data[0].decode('gbk')
print(f"收到远程信息:{recv_content},from {recv_data[1]}")
if recv_content == "exit":
print("结束聊天!")
break
s.close()
udp客户端:
from socket import *
# UDP客户端持续发送消息代码
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字
addr = ("127.0.0.1", 8888)
while True:
data = input("请输入:")
s.sendto(data.encode("gbk"), addr)
if data == "exit":
print("结束聊天!")
break
s.close()
使用本地主机,开启两个接收和发送两个线程,实现双工通信。
udp服务端:
from socket import *
from threading import Thread
def recv_data():
while True:
recv_data = s.recvfrom(1024) # 1024表示本次接收的最大字节数
recv_content = recv_data[0].decode('gbk')
print(f"收到远程信息:{recv_content},from {recv_data[1]}")
if recv_content == "exit":
print("结束聊天!")
break
def send_data():
addr = ("127.0.0.1", 9999)
while True:
data = input("请输入:")
s.sendto(data.encode("gbk"), addr)
if data == "exit":
print("结束聊天!")
break
if __name__ == '__main__':
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字
s.bind(("127.0.0.1", 8888)) # 绑定端口,ip可以不写
# 创建两个线程
t1 = Thread(target=recv_data)
t2 = Thread(target=send_data)
t1.start()
t2.start()
t1.join()
t2.join()
udp客户端:
from socket import *
from threading import Thread
def recv_data():
while True:
recv_data = s.recvfrom(1024) # 1024表示本次接收的最大字节数
recv_content = recv_data[0].decode('gbk')
print(f"收到远程信息:{recv_content},from {recv_data[1]}")
if recv_content == "exit":
print("结束聊天!")
break
def send_data():
addr = ("127.0.0.1", 8888)
while True:
data = input("请输入:")
s.sendto(data.encode("gbk"), addr)
if data == "exit":
print("结束聊天!")
break
if __name__ == '__main__':
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP类型的套接字
s.bind(("127.0.0.1", 9999)) # 绑定端口,ip可以不写
# 创建两个线程
t1 = Thread(target=recv_data)
t2 = Thread(target=send_data)
t1.start()
t2.start()
t1.join()
t2.join()
面向连接的Socket使用的协议是TCP协议。TCP的Socket名称是SOCK_STREAM 。创建套接字TCP套接字,可以调用 socket.socket() 。示例代码如下:
tcpSocket=socket.socket(AF_INET,SOCK_STREAM)
from socket import *
server_socket = socket(AF_INET,SOCK_STREAM) #建立TCP套接字
server_socket.bind(("127.0.0.1",8899)) #本机监听8899端口
server_socket.listen(5)
print("等待接收连接!")
client_socket,client_info = server_socket.accept()
recv_data = client_socket.recv(1024) #最大接收1024字节
print(f"收到信息:{recv_data.decode('gbk')},来自:{client_info}")
client_socket.close()
server_socket.close()
from socket import *
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(("127.0.0.1",8899))
client_socket.send("hello".encode("gbk"))
client_socket.close()
#注意:
# 1. tcp客户端已经链接好了服务器,所以在以后的数据发送中,不需要填写对方的ip和port----->打电话
# 2. udp在发送数据的时候,因为没有之前的链接,所以需要在每次的发送中,都要填写接收方的ip和port--->写信
from socket import *
server_socket = socket(AF_INET,SOCK_STREAM) #建立TCP套接字
server_socket.bind(("127.0.0.1",8899)) #本机监听8899端口
server_socket.listen(5)
print("等待接收连接!")
client_socket,client_info = server_socket.accept()
print("一个客户端建立连接成功!")
while True:
recv_data = client_socket.recv(1024) #最大接收1024字节
recv_content = recv_data.decode('gbk')
print(f"客户端说:{recv_content},来自:{client_info}")
if recv_content == "end":
break
msg = input(">")
client_socket.send(msg.encode("gbk"))
client_socket.close()
server_socket.close()
from socket import *
client_socket = socket(AF_INET,SOCK_STREAM)
client_socket.connect(("127.0.0.1",8899))
while True:
#给服务端发消息
msg = input(">")
client_socket.send(msg.encode("gbk"))
if msg =="end":
break
#接收服务器端数据
recv_data = client_socket.recv(1024) #最大接收1024字节
print(f"服务器端说:{recv_data.decode('gbk')}")
client_socket.close()
from socket import *
from threading import Thread
def recv_data():
while True:
recv_data = client_socket.recv(1024) # 最大接收1024字节
recv_content = recv_data.decode("gbk")
print(f"客户端说:{recv_content},来自:{client_info}")
if recv_content == "end":
print("结束接收消息!")
break
def send_data():
while True:
msg = input(">")
client_socket.send(msg.encode("gbk"))
if msg == "end":
print("结束发送消息!")
break
if __name__ == '__main__':
server_socket = socket(AF_INET, SOCK_STREAM) # 建立TCP套接字
server_socket.bind(("127.0.0.1", 8899)) # 本机监听8899端口
server_socket.listen(5)
print("等待接收连接!")
client_socket, client_info = server_socket.accept()
print("一个客户端建立连接成功!")
t1 = Thread(target=recv_data)
t2 = Thread(target=send_data)
t1.start()
t2.start()
t1.join()
t2.join()
client_socket.close()
server_socket.close()
from socket import *
from threading import Thread
def recv_data():
while True:
# 接收服务器端数据
recv_data = client_socket.recv(1024) # 最大接收1024字节
recv_content = recv_data.decode('gbk')
print(f"服务器端说:{recv_content}")
if recv_content == "end":
print("结束接收消息")
break
def send_data():
while True:
# 给服务端发消息
msg = input(">")
client_socket.send(msg.encode("gbk"))
if msg == "end":
break
if __name__ == '__main__':
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(("127.0.0.1", 8899))
t1 = Thread(target=recv_data)
t2 = Thread(target=send_data)
t1.start()
t2.start()
t1.join()
t2.join()
client_socket.close()