1、TCP与UDP连接模型
(1)TCP模型
(2)UDP模型
2、TCP连接代码
(1)服务端
from socket import *
IP = '0.0.0.0' #标识绑定主机所有网络接口IP地址
PORT = 50000 #端口号
BUFLEN=512 #缓冲区
#实例化一个socket对象
#AF_INET标识网络层使用IP协议
#AF_STREAM标识传输层使用TCP协议
listensocket = socket(AF_INET,SOCK_STREAM)
#socket绑定地址和端口
listensocket.bind((IP,PORT))
#使socket处于监听状态,等待客户端的连接请求
#参数5表示最多接收等待 连接的个数
listensocket.listen(5)
print(f"服务器端启动成功,在{PORT}端口等待连接")
#返回元组信息
datasocket1,addr = listensocket.accept()
print("接收一个客户端连接:",addr)
while True:
reved = data1.socket.rev(BUFLEN)
if not reved:
break
info = reved.decode()
print("接收方信息:{info}")
datasocket1.send(f"服务器接收到的信息:{info}".encode())
(2)客户端
from socket import *
IP = '127.0.0.1'
SERVER_PORT = 50000
BUFLEN = 512
#实例化一个socket对象
#AF_INET标识网络层使用IP协议
#AF_STREAM标识传输层使用TCP协议
datasocket = socket(AF_INET,SOCK_STREAM)
datasocket.connect((IP,SERVER_PORT))
while True:
tosend = input(">>>")
if tosend == 'exit':
break
datasocket.send(tosend.encode())
recved = datasocket.resv(BUFLEN)
if not recved:
break;
print(recved.decode())
datasocket.close()
3、备份服务器案例
利用TCP通信协议,采用可视化界面实现远程备份管理工具
程序流程图:
服务端:
from tkinter import *
from tkinter.ttk import *
import socket
import struct
import os
import pickle
BAK_PATH = r'E:\bak' #设定默认备份目录
#接收文件信息的函数
def recv_unit_data(clnt,infos_len):
data = b''
if 0 < infos_len <=1024:
data += clnt.recv(infos_len)
else:
while True:
if infos_len > 1024:
data +=clnt.recv(1024)
infos_len -= 1024
else:
data += clnt.recv(infos_len)
break
return data
#获取文件信息函数
def get_files_info(clnt):
fmt_str = 'Q'
headsize = struct.calcsize(fmt_str) #计算出长整型的长度
data = clnt.recv(headsize)
infos_len = struct.unpack(fmt_str,data)[0]
data = recv_unit_data(clnt,infos_len)
return pickle.loads(data)
def mk_path(filepath):
paths = filepath.split(os.path.sep)[:-1]
p = BAK_PATH
for path in paths:
p = os.path.join(p,path)
if not os.path.exists(p):
os.mkdir(p)
def recv_file(clnt,infos_len,filepath):
mk_path(filepath)
filepath = os.path.join(BAK_PATH,filepath)
f = open(filepath,"wb+")
try:
if 0 < infos_len <= 1024:
data = clnt.recv(infos_len)
f.write(data)
else:
while True:
if infos_len > 1024:
data = clnt.recv(1024)
f.write(data)
infos_len -= 1024
else:
data = clnt.recv(infos_len)
f.write(data)
break
except:
print('error')
else:
return True
finally:
f.close()
def send_echo(clnt,res):
if res:
clnt.sendall(b'success')
else:
clnt.sendall(b'failure')
def start(host,port):
if not os.path.exists(BAK_PATH):
os.mkdir(BAK_PATH)
st = socket.socket()
st.bind((host,port))
st.listen(1)
client,addr = st.accept()
file_lst = get_files_info(client)
for size,filepath in file_lst:
res = recv_file(client,size,filepath)
send_echo(client,res)
client.close()
st.close()
#定义窗体类
class MyFrame(Frame):
def __init__(self,root):
super().__init__(root)
self.root = root
self.grid()
self.local_ip = '127.0.0.1'
self.serv_ports = [10888,20888,30888]
self.init_components()
#可视化组件设置函数
def init_components(self):
proj_name = Label(self,text="远程备份服务器") #服务标签
proj_name.grid(columnspan=2)
serv_ip_label = Label(self,text="服务地址")
serv_ip_label.grid(row=1)
self.serv_ip = Combobox(self,values=self.get_ipaddr()) #将获取到的本机IP输出到选择列表中
self.serv_ip.set(self.local_ip)
self.serv_ip.grid(row=1,column=1)
serv_port_label = Label(self,text="服务端口")
serv_port_label.grid(row=2)
self.serv_port = Combobox(self,values=self.serv_ports)
self.serv_port.set(self.serv_ports[0])
self.serv_port.grid(row=2,column=1)
self.start_serv_btn = Button(self,text="启动服务",command=self.start_serv)
self.start_serv_btn.grid(row=3)
self.start_exit_btn = Button(self,text="退出服务",command=self.root.destroy)
self.start_exit_btn.grid(row=3,column=1)
def get_ipaddr(self): #通过socket模块获取本地IP信息及内容
host_name = socket.gethostname()
info = socket.gethostbyname_ex(host_name)
info = info[2] #gethostbyname_ex函数返回为('LAPTOP-5GCCVJ3P', [], ['10.10.10.2', '192.168.0.2', '192.168.184.1', '192.168.31.68']) ,将第二列复制给info
info.append(self.local_ip)
return info
def start_serv(self):
print(self.serv_ip.get(),self.serv_port.get())
start(self.serv_ip.get(),int(self.serv_port.get()))
'''
功能:
1、备份客户端的一个目录及其子目录中的所有文件
2、与客户端交互流程
'''
if __name__ == '__main__':
root = Tk()
root.title("备份服务器")
root.resizable(False,False)
app = MyFrame(root)
app.mainloop()
客户端:
#客户端
from tkinter import *
from tkinter.ttk import *
import socket
import struct
import os
import pickle
#获取文件信息函数
def get_file_info(path):
if not path or not os.path.exists(path):
return None
files = os.walk(path)
infos = []
file_paths = []
for p ,ds,fs in files:
for f in fs:
file_name = os.path.join(p,f)
file_size = os.stat(file_name).st_size
file_paths.append(file_name)
file_name = file_name[len(path)+1:]
infos.append((file_size,file_name))
return infos,file_paths
#文件发送函数
def send_files_infos(my_sock,infos):
fmt_str = 'Q'
infos_bytes = pickle.dumps(infos)
infos_bytes_len = len(infos_bytes)
infos_len_pack = struct.pack(fmt_str,infos_bytes_len)
my_sock.sendall(infos_len_pack)
my_sock.sendall(infos_bytes)
def send_files(my_sock,file_path):
f = open(file_path,'rb')
try:
while True:
data = f.read(1024)
if data:
my_sock.sendall(data)
else:
break
finally:
f.close()
def get_bak_info(my_sock,size=7): #success字节
info = my_sock.recv(size)
print(info.decode('utf-8'))
def start(host,port,src):
if not os.path.exists(src):
print("备份目标不存在")
return
s = socket.socket()
s.connect((host,port))
path = src
file_infos,file_paths = get_file_info(path)
send_files_infos(s,file_infos)
for fp in file_paths:
send_files(s,fp)
print(fp)
get_bak_info(s)
s.close()
#定义窗体类
class MyFrame(Frame):
def __init__(self,root):
super().__init__(root)
self.root = root
self.grid()
self.remote_ip = '127.0.0.1'
self.remote_ports = 10888
self.remote_ip_var = StringVar()
self.remote_ports_var = IntVar()
self.bak_src_var = StringVar()
self.init_components()
#可视化组件设置函数
def init_components(self):
proj_name = Label(self,text="远程备份客户机") #服务标签
proj_name.grid(columnspan=2)
serv_ip_label = Label(self,text="服务地址")
serv_ip_label.grid(row=1)
self.serv_ip = Entry(self,textvariable=self.remote_ip_var) #将获取到的本机IP输出到选择列表中
self.remote_ip_var.set(self.remote_ip)
self.serv_ip.grid(row=1,column=1)
serv_port_label = Label(self,text="服务端口")
serv_port_label.grid(row=2)
self.serv_port = Entry(self,textvariable=self.remote_ports_var)
self.remote_ports_var.set(self.remote_ports)
self.serv_port.grid(row=2,column=1)
src_label = Label(self,text='备份目标:')
src_label.grid(row=3)
self.bak_src = Entry(self, textvariable=self.bak_src_var) # 将获取到的本机IP输出到选择列表中
self.bak_src.grid(row=3, column=1)
self.start_serv_btn = Button(self,text="开始备份",command=self.start_send)
self.start_serv_btn.grid(row=4)
self.start_exit_btn = Button(self,text="退出程序",command=self.root.destroy)
self.start_exit_btn.grid(row=4,column=1)
def start_send(self):
print(self.remote_ip_var.get(),self.remote_ports_var.get())
print('start....')
print(self.bak_src_var.get())
start(self.remote_ip_var.get(),int(self.remote_ports_var.get()),self.bak_src_var.get())
if __name__ == '__main__':
root = Tk()
root.title('远程备份客户机')
root.resizable(False,False)
app = MyFrame(root)
app.mainloop()