1 网络
1.1 使用网路的目的
使用网络可以把多方链接在一起,然后可以进行数据传递
所谓的网络编程,实现的是进程之间的通信
1.2 ip地址
ip地址可以理解为家庭地址。快递员通过家庭地址,进行转发货物,那么,ip地址在网络上就是标志你所在的网络和主机
ip地址分为网络号和主机号
在这么多ip地址中,国际规定有一部分ip地址是用于我们的局域网使用,也就属于私网ip,不属于公网,他们的范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
ip地址 127.0.0.1~172.255.255.255用于回路测试
如:127.0.0.1可以代表本机ip地址
1.3 端口
ip是用来标志网络主机,而端口是用来标志主机中的一个唯一的应用程序。
知名端口:小于1024,
动态端口:大于1024,我们在发送数据,可以指定自己的应用程序的动态端口,也可以由操作系统随机分配一个端口,当我们结束链接时,由操作系统分配的动态端口会被回收,下次使用该应用程序,又会分配一个新的随机端口
注:在主机中,不同应用程序,不能用相同端口
1.4 利用socket进行数据传输
1.4.1
发送数据步骤:
- 创建socket
- 发送数据
- 关闭socket
import socket
def main():
#创建一个套接字
udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#使用套接字接发数据
udp_socket.sendto("内容",("192.168.10.25",8080))
#关闭套接字
udp_socket.close()
if __name__ =="__main__":
main()
接受数据步骤:
1. 创建套接字
2. 绑定本地套接字
3. 使用套接字接受数据
4. 打印数据
5. 关闭套接字
代码:
import socket
def main():
# 1.创建套接字
udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 2.绑定套接字
local=('',7878)
udp_socket.bind(local)
# 3.接受数据
info=udp_socket.recvfrom(1024)
# info接受的是一个元组(接收的数据,(发送方的ip,端口号))
# 4.输出接受的内容
str_add=info[1]
str_msg=info[0]
print(info)
print("%s:%s"%(str(str_add),str_msg.decode("gbk")))
# 单独打印接受的内容和数据
# 5.关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
> 套接字属于全双工
1.5 手机通讯系统案例
利用套接字实现既能发数据也能收数据的一个小代码。
import socket
def send(udp_socket):
"""发送数据"""
socket_ip=input("请输入IP:")
socket_port=int(input("请输入port:"))
socket_info=input("请输入您要发送的内容:")
udp_socket.sendto(socket_info.encode("utf-8"),(socket_ip,socket_port))
def rmcv(udp_socket):
"""接收数据"""
msg=udp_socket.recvfrom(1024)
print("%s:%s" % (str(msg[1]),msg[0].decode("utf-8")))
def main():
# 创建套接字
udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定套接字
local_add=("",2550)
udp_socket.bind(local_add)
while True:
print("-------手机通讯系统--------")
print("1.发送数据")
print("2.接受数据")
print("3.退出系统")
num=input("请输入您要选择的功能")
if num == "1":
# 调用发送数据函数
send(udp_socket)
elif num == "2":
# 调用接受数据函数
rmcv(udp_socket)
elif num == "3":
break
else:
print("您输入的有误,请重新输入")
if __name__ == "__main__":
main()
2 Tcp
2.1 Tcp介绍
Udp通信模型:
Udp通信模型中,在通信开始之前,不需要建立连接,只需要发送数据即可。(不安全,但快速)
Tcp协议:传输控制协议(速度慢,但传输可靠):
Tcp通信经过三个步骤:建立连接,收发数据,关闭连接
2.2 Tcp客户端
所谓的客户端:就是需要被服务的一方,所谓的服务器就是,提供服务的一方
Tcp客户端连接服务器流程:
创建套接字
连接服务器
发送数据
关闭套接字
案例:
import socket
def main():
# 创建tcp套接字
tcp_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 为本机绑定端口
tcp_socket.bind(("",55007))
# 建立连接
server_ip=input("请输入您要连接的服务器IP:")
server_port=int(input("请输入服务器的Port:"))
tcp_socket.connect((server_ip,server_port))
# 发送数据
data=input("请输入您要发送的数据")
tcp_socket.send(data.encode("gbk"))
# 关闭tcp套接字
tcp_socket.close()
if __name__ == "__main__":
main()
2.3 tcp服务器
tcp服务器的步骤:
1. 建立套接字
tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
2. 绑定本地的信息
tcp_server_socket.bind(("",55014)) #55014为端口号,自己设定
3. 监听(监听是否有客户端建立连接)
tcp_server_socket.listen()
4. 接受连接
new_tcp_socket,client_socket =tcp_server_socket.accept()
在接受连接时,会有俩个返回值,第一个返回值是,新的套接字,主要为了与该用户进行数据之间的传递,而另一个返回值是代表客户端的ip和端口号。
案例:
import socket
def main():
# 创建套接字
tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定端口
tcp_server_socket.bind(("",55014))
# 被动监听,让默认的套接字由主动变为被动listen
tcp_server_socket.listen()
# 循环目的:调用多次accept,从而为多个客户端服务
while True:
print("正在等待连接。。。")
# 接受链接
new_tcp_socket,client_socket =tcp_server_socket.accept()
print("连接成功")
# 向服务器发送提示数据
new_tcp_socket.send("连接成功,请发送数据给服务器".encode("gbk"))
# 循环目的:为同一个客户端 服务多次
while True:
# 接受客户端的数据
data=new_tcp_socket.recv(1024)
print(data.decode("gbk"))
# 当客户端关闭连接时,服务器端自动断开与该用户的连接
if data:
# 向服务器发送数据
new_tcp_socket.send("您发送的数据已经收到,请问还有其他需求吗?".encode("gbk"))
else :
break
# 关闭服务器与客户机之间连接产生的套接字,既关闭accept返回的套接字,不为这个用户服务
new_tcp_socket.close()
# 关闭被动监听的套接字,既不等待新的用户的到来
tcp_server_socket.close()
if __name__ == "__main__" :
main()
案例:文件下载器
1. f=open(“xxx”)
try :
f.read()
except:
f.close
这个语句可以这样写:
with open(“xxxx”) as f
f.read()
如果f.read()出现异常,会自动关闭文件,不需要自己f.close()
客户端代码:
import socket
def main():
# 创建tcp套接字
tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定ip 端口
tcp_client_socket.bind(("",54621))
# 连接服务器
tcp_client_socket.connect(("192.168.3.1",52548))
print("连接服务器成功")
# 向服务器发送要下载的文件名
download_filename=input("请输入要下载的文件名")
tcp_client_socket.send(download_filename.encode("utf-8"))
# 接受服务传过来的数据
download_data=tcp_client_socket.recv(1024*1024)
print("打印一下接受的数据")
print(download_data)
# 将数据写入本地
with open("【新】"+download_filename,"wb") as f :
f.write(download_data)
# 关闭套接字
tcp_client_socket.close()
if __name__ == "__main__":
main()
服务端代码:
import socket
def send(filename):
data = None
try :
f=open(filename,"rb")
data=f.read()
f.close()
except Exception as ret :
print("你要下载的文件不存在")
return data
def main():
# 创建服务器套接字
tcp_server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定ip和port
tcp_server_socket.bind(("",52548))
# 将主动改为被动监听
tcp_server_socket.listen(128)
# 接受连接
new_socket,client_ip_socket=tcp_server_socket.accept()
while True:
# 接受要下载的文件名
download_filename=new_socket.recv(1024*1024)
if download_filename:
# 打开文件
data=send(download_filename)
# 将数据发送给客户端
if data :
new_socket.send(data)
new_socket.close()
# 关闭套接字
tcp_server_socket.close()
if __name__ == "__main__":
main()
2.4 tcp复习知识点
1. tcp服务器一般情况下都需要绑定,否则客户端都找不到这个服务器
2. tcp客户端一般不绑定,因为是主动连接服务器,所以只要绑定好服务器的ip、port等信息就好,本地客户极端可以随机
3. tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
4. 当客户端需要连接服务器时,就需要使用connect进行链接,udp时不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
5. 当一个tco客户端连接服务器时,服务器就会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
6. Listen后的套接字是被动套接字,用来接受新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
7. 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信
8. 关闭accpet返回的套接字意味着这个客户端已经服务完毕
9. 当客户端的套接字调用后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回的数据的长度来区别客户端是否已经下线