文章目录
网络编程
文章目录
前言
计算机网络编程
一、计算机网络基础
1.计算机基础
应用软件
操作系统
计算机硬件
2.什么是网络
互联网协议
osi七层:
应
表
会
传
网
数
物
3.五层协议详解
应用层
传输层 tcp/udbc
网络层 ip
数据链路层 Ethernet head(18个字节)|data
物理层
4.传输层详解
tcp协议
三次握手,四次断开
二、什么是socket
1.基于socket实现简单的套接字通信
服务端
# -*- coding: utf-8 -*-
import socket
#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
#2.绑定手机卡
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
#3.开机
phone.listen(5)
#4.等电话链接
print("starting")
conn,client_addr = phone.accept()
#5.收发消息
data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
print(f"客户端数据:{data}")
conn.send(data.upper())
#6.挂电话
conn.close()
#7.关机
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
#1.买手机
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)
#2.拨号
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
#3.发收消息
phone.send("hello".encode("utf-8"))
data = phone.recv(1024)
print(data)
#4.关闭
phone.close()
2.在简单的套接字通信基础上加上通信循环
服务端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
print(f"客户端数据:{data}")
conn.send(data.upper())
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
msg = input(">>:").strip()
phone.send(msg.encode("utf-8"))
data = phone.recv(1024)
print(data)
phone.close()
3.客户端与服务端bug修复
服务端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
if not data:break #适用于linux操作系统
print(f"客户端数据:{data}")
conn.send(data.upper())
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
msg = input(">>:").strip()
phone.send(msg.encode("utf-8"))
if not msg:
continue
print("has send")
data = phone.recv(1024)
print("has recv")
print(data.decode("utf-8"))
phone.close()
4.实现服务端可以对多个客户端提供服务
服务端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
data = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
if not data:break #适用于linux操作系统
print(f"客户端数据:{data}")
conn.send(data.upper())
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
5.模拟ssh远程执行命令-项目
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
cmd = conn.recv(1024) #1.单位:bytes 2.最大接收1024个bytes
if not cmd:break #适用于linux操作系统
#2.执行命令,拿到结果
obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
#3.把命令的结果返回给客户端
conn.send(stdout+stderr) #+是一个可以优化的点
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
cmd = input(">>:").strip()
phone.send(cmd.encode("utf-8"))
if not cmd:
continue
#2.拿到命令的结果并打印
data = phone.recv(1024) #1024是一个坑
print(data.decode("gbk"))
phone.close()
补充
#windows
#dir:查看某个文件夹下的子文件名与子文件夹
#ipconfig:查看本地网卡的ip信息
#tacklist:查看运行的进程
#linux
#ls
#config
#ps aux
#执行系统命令,并且拿到命令的结果
# import os
# res = os.system("dir c:")
# print(res)
import subprocess
obj = subprocess.Popen("dir c:",shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
print(obj)
print("stdout:",obj.stdout.read().decode("gbk"))
print("stderr:",obj.stderr.read().decode("gbk"))
三、粘包现象
1.send与receive对比
1.不管是receive还是send都不是直接接收对方的数据,而是操作自己的操作系统内存——》不是一个send对应一个receive
2.recv:
wait data 耗时长
copy data
send:
copy data
2.底层原理分析
服务端
# -*- coding: utf-8 -*-
import socket
import time
import subprocess
sever = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sever.bind(('127.0.0.1',8081))#0-1024操作系统用
sever.listen(5)
conn,addr = sever.accept()
#第一次接收
res1 = conn.recv(1)
res2 = conn.recv(3)
print("first time:",res1+res2)
#第二次接收
res3 = conn.recv(1024)
print("first time:",res3)
客户端
# -*- coding: utf-8 -*-
import socket
import time
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8081))#0-1024操作系统用
client.send("hello".encode("utf-8"))
time.sleep(5)
client.send("world".encode("utf-8"))
3.解决粘包问题伪代码实现
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
if not cmd:break #适用于linux操作系统
#2.执行命令,拿到结果
obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
#3.把命令的结果返回给客户端
#第一步把报头(固定长度)发送给客户端
total_size = len(stdout)+len(stderr)
conn.send(str(total_size).encode("utf-8"))
#第二步再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
cmd = input(">>:").strip()
phone.send(cmd.encode("utf-8"))
if not cmd:
continue
#2.拿到命令的结果并打印
#第一步:先收报头
total_size =
#第二步:接收真实的数据
receive_size = 0
receive_data = b""
while receive_size < total_size:
res = phone.recv(1024) #1024是一个坑
receive_data += res
receive_size += len(res)
print(receive_data.decode("gbk"))
phone.close()
2.解决粘包问题-简单版本
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
if not cmd:break #适用于linux操作系统
#2.执行命令,拿到结果
obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
#3.把命令的结果返回给客户端
#第一步:制作固定长度的报头
total_size = len(stdout)+len(stderr)
header = struct.pack("i",total_size)
#第二步把报头(固定长度)发送给客户端
conn.send(header)
#第三步再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
import struct
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
cmd = input(">>:").strip()
phone.send(cmd.encode("utf-8"))
if not cmd:
continue
#2.拿到命令的结果并打印
#第一步:先收报头
header = phone.recv(4)
#第二步:从报头中解析出对真实数据的描述信息(数据的长度)
total_size = struct.unpack("i", header)[0]
#第三步:接收真实的数据
receive_size = 0
receive_data = b""
while receive_size < total_size:
res = phone.recv(1024) #1024是一个坑
receive_data += res
receive_size += len(res)
print(receive_data.decode("gbk"))
phone.close()
3.解决粘包问题-最终版本
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
cmd = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
if not cmd:break #适用于linux操作系统
#2.执行命令,拿到结果
obj = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = obj.stdout.read()
stderr = obj.stderr.read()
#3.把命令的结果返回给客户端
#第一步:制作固定长度的报头
header_dict = {
"filename":"a.txt",
"md5":"xxx",
"total_size":len(stdout)+len(stderr)
}
header_json = json.dumps(header_dict)
# total_size = len(stdout)+len(stderr)
header_bytes=header_json.encode("utf-8")
#第二步:先发送报头的长度
conn.send(struct.pack("i",len(header_bytes)))
#第三步:再发报头
conn.send(header_bytes)
#第四步:再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
import struct
import json
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
cmd = input(">>:").strip()
phone.send(cmd.encode("utf-8"))
if not cmd:
continue
#2.拿到命令的结果并打印
#第一步:先收报头的长度
obj = phone.recv(4)
header_size = struct.unpack("i",obj)[0]
#第二步:再收报头
header_bytes = phone.recv(header_size)
#第三步:从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode("utf-8")
header_dict = json.loads(header_json)
print(header_dict)
total_size = header_dict["total_size"]
#第四步:接收真实的数据
receive_size = 0
receive_data = b""
while receive_size < total_size:
res = phone.recv(1024)
receive_data += res
receive_size += len(res)
print(receive_data.decode("gbk"))
phone.close()
四、文件传输功能
1.文件传输功能实现
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
import os
share_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\sever\share"
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
res = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
if not res:break #适用于linux操作系统
#2.解析命令,提取相应命令参数
cmds = res.decode("utf-8").split()
filename = cmds[1]
#3.以读的方式打开文件,读取文件内容发送给客户端
#第一步:制作固定长度的报头
header_dict = {
"filename":filename,
"md5":"xxx",
"file_size":os.path.getsize(r"%s/%s" %(share_dir,filename))
}
header_json = json.dumps(header_dict)
# total_size = len(stdout)+len(stderr)
header_bytes=header_json.encode("utf-8")
#第二步:先发送报头的长度
conn.send(struct.pack("i",len(header_bytes)))
#第三步:再发报头
conn.send(header_bytes)
#第四步:再发送真实的数据
with open("%s/%s" %(share_dir,filename),"rb") as f:
for line in f:
conn.send(line)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
客户端
# -*- coding: utf-8 -*-
import socket
import struct
import json
download_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\client\download"
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
cmd = input(">>:").strip()
phone.send(cmd.encode("utf-8"))
if not cmd:
continue
#2.以写的方式打开新文件,接收服务端发来的文件内容写入客户端的新文件
#第一步:先收报头的长度
obj = phone.recv(4)
header_size = struct.unpack("i",obj)[0]
#第二步:再收报头
header_bytes = phone.recv(header_size)
#第三步:从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode("utf-8")
header_dict = json.loads(header_json)
print(header_dict)
total_size = header_dict["file_size"]
filename = header_dict["filename"]
#第四步:接收真实的数据
with open("%s/%s" %(download_dir,filename),"wb") as f:
receive_size = 0
while receive_size < total_size:
line = phone.recv(1024)
f.write(line)
receive_size += len(line)
print(f"总大小:{total_size},已下载大小:{receive_size}")
phone.close()
2.文件传输功能-函数版
服务端
# -*- coding: utf-8 -*-
import socket
import subprocess
import struct
import json
import os
share_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\优化版本\sever\share"
def get(conn,cmds):
filename = cmds[1]
# 3.以读的方式打开文件,读取文件内容发送给客户端
# 第一步:制作固定长度的报头
header_dict = {
"filename": filename,
"md5": "xxx",
"file_size": os.path.getsize(r"%s/%s" % (share_dir, filename))
}
header_json = json.dumps(header_dict)
# total_size = len(stdout)+len(stderr)
header_bytes = header_json.encode("utf-8")
# 第二步:先发送报头的长度
conn.send(struct.pack("i", len(header_bytes)))
# 第三步:再发报头
conn.send(header_bytes)
# 第四步:再发送真实的数据
with open("%s/%s" % (share_dir, filename), "rb") as f:
for line in f:
conn.send(line)
def put(conn,cmds):
pass
def run():
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8081))#0-1024操作系统用
phone.listen(5)
print("starting")
while True: #链接循环
conn,client_addr = phone.accept()
print(client_addr)
while True: #通信循环
try:
#1.收命令
res = conn.recv(8096) #1.单位:bytes 2.最大接收1024个bytes
if not res:break #适用于linux操作系统
#2.解析命令,提取相应命令参数
cmds = res.decode("utf-8").split()
if cmds[0] == "get":
get(conn,cmds)
elif cmds[0] == "put":
put(conn,cmds)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
if __name__ == '__main__':
run()
客户端
# -*- coding: utf-8 -*-
import socket
import struct
import json
download_dir = r"D:\pyfile\路飞学城就业课程\第三模块-面向对象&网络编程基础\第二章-网络编程\课堂练习\05文件传输\优化版本\client\download"
def get(phone,cmds):
# 2.以写的方式打开新文件,接收服务端发来的文件内容写入客户端的新文件
# 第一步:先收报头的长度
obj = phone.recv(4)
header_size = struct.unpack("i", obj)[0]
# 第二步:再收报头
header_bytes = phone.recv(header_size)
# 第三步:从报头中解析出对真实数据的描述信息(数据的长度)
header_json = header_bytes.decode("utf-8")
header_dict = json.loads(header_json)
print(header_dict)
total_size = header_dict["file_size"]
filename = header_dict["filename"]
# 第四步:接收真实的数据
with open("%s/%s" % (download_dir, filename), "wb") as f:
receive_size = 0
while receive_size < total_size:
line = phone.recv(1024)
f.write(line)
receive_size += len(line)
print(f"总大小:{total_size},已下载大小:{receive_size}")
def put(phone,cmds):
pass
def run():
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8081))#0-1024操作系统用
while True:
#1.发命令
inp = input(">>:").strip()
if not inp:continue
phone.send(inp.encode("utf-8"))
cmds = inp.split()
if cmds[0] == "get":
get(phone,cmds)
elif cmds[0] == "put":
put(phone,cmds)
phone.close()
if __name__ == '__main__':
run()
3.文件传输功能-面向对象版
五、基于udp协议套接字介绍
1.基本功能
服务端
# -*- coding: utf-8 -*-
from socket import *
sever = socket(AF_INET,SOCK_DGRAM)
sever.bind(("127.0.0.1",8881))
while True:
data,client_addr = sever.recvfrom(1024)
print(data)
sever.sendto(data.upper(),client_addr)
sever.close()
客户端
# -*- coding: utf-8 -*-
from socket import *
client = socket(AF_INET,SOCK_DGRAM)
while True:
msg = input(">>:").strip()
client.sendto(msg.encode("utf-8"),("127.0.0.1",8881))
data,sever_addr = client.recvfrom(1024)
print(data,sever_addr)
client.close()
2.udp协议不会粘包
服务端
from socket import *
sever = socket(AF_INET,SOCK_DGRAM)
sever.bind(("127.0.0.1",8881))
res1 = sever.recvfrom(1024)
print(f"第一次:{res1}")
res2 = sever.recvfrom(1024)
print(f"第二次:{res2}")
sever.close()
客户端
from socket import *
client = socket(AF_INET,SOCK_DGRAM)
client.sendto(b"hello",("127.0.0.1",8881))
client.sendto(b"world",("127.0.0.1",8881))
client.close()
总结
网络编程