TCP实现文件传输【源码】

1.socket_service

import socket
import threading
import struct
import os
def socket_service(ipv4,port,stat):
#ipv4为IP地址,port为端口,stat可选择"send"或"recive"(代表文件发送或文件接收)
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口为9001
# 同一网络的不同主机
# s.bind(('192.168.0.16', 9001))
# 同一网络同一主机
s.bind((ipv4,port)) #参数为ipv4,port
# 设置监听数
s.listen(10)
print("服务器Ipv4地址是127.0.0.1,服务器的端口是80")
except socket.error as msg:
print(msg)
os.sys.exit(1)
print('服务端已启动,等待客户端连接...')
while True:
# 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程)
conn, addr = s.accept()
# 发送或接收数据
if str(stat) == 'send':
t = threading.Thread(target=deal_data_send_service, args=(conn,addr))
elif str(stat) == 'receive':
t = threading.Thread(target=deal_data_receiver_service, args=(conn,addr))
else:
print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
break
t.start()
def deal_data_receiver_service(conn, addr):
print('已连接地址为: {0}'.format(addr))
# conn.settimeout(500)
# 收到请求后的回复
conn.send('新消息:已成功连接'.encode('utf-8'))
while True:
# 申请相同大小的空间存放发送过来的文件名与文件大小信息
fileinfo_size = struct.calcsize('128sl') #创建128比特的待储存空间
# 接收文件名与文件大小信息
buf = conn.recv(fileinfo_size)#128比特的文件头信息放在待储存空间
# 判断是否接收到文件头信息
if buf:
# 获取文件名和文件大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print('数据名为: {0}, 数据大小为: {1} bytes'.format(str(fn), filesize))
recvd_size = 0 # 定义已接收文件的大小
# 存储在该脚本所在目录下面
fp = open('./receive/' + str(fn), 'wb')
print('开始接收客户端数据...'+'文件名:'+str(fn))
# 将分批次传输的二进制流依次写入到文件
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = conn.recv(1024)
recvd_size += len(data)
else:
data = conn.recv(filesize - recvd_size)
recvd_size = filesize
fp.write(data)
fp.close()
print('数据接收完成...')
break
def deal_data_send_service(conn, addr):
print('已连接地址为: {0}'.format(addr))
# conn.settimeout(500)
# 收到请求后的回复
conn.send('新消息:已成功连接'.encode('utf-8'))
while True:
print('发送数据...')
fn = input('请输入文件名') #子进程无法使用input()
path = './send/'
file_path = os.path.join(path, str(fn)).replace('\\', '/')
fp = open(file_path, 'rb')
fhead = struct.pack('128sl', os.path.basename(file_path).encode('utf-8'), os.stat(file_path).st_size)
conn.send(fhead)
while True:
data = fp.read(1024)
if not data:
print('{0} 数据传输完成...'.format(os.path.basename(file_path)))
break
conn.send(data)
# 传输结束断开连接
# conn.close()
break
def deal_data_receiver_client(ipv4, port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ipv4, port))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024).decode())
print('已连接地址为: {0}'.format(ipv4))
# conn.settimeout(500)
# 收到请求后的回复
# s.send('新消息:已成功连接'.encode('utf-8'))
while True:
# 申请相同大小的空间存放发送过来的文件名与文件大小信息
fileinfo_size = struct.calcsize('128sl') #创建128比特的待储存空间
# 接收文件名与文件大小信息
buf = s.recv(fileinfo_size)#128比特的文件头信息放在待储存空间
# 判断是否接收到文件头信息
if buf:
# 获取文件名和文件大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print('数据名为: {0}, 数据大小为: {1} bytes'.format(str(fn), filesize))
recvd_size = 0 # 定义已接收文件的大小
# 存储在该脚本所在目录下面
fp = open('./receive/' + str(fn), 'wb')
print('开始接收客户端数据...'+'文件名:'+str(fn))
# 将分批次传输的二进制流依次写入到文件
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = s.recv(1024)
recvd_size += len(data)
else:
data = s.recv(filesize - recvd_size)
recvd_size = filesize
fp.write(data)
fp.close()
print('数据接收完成...')
break
def deal_data_send_client(ipv4, port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ipv4, port))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024).decode())
print('已连接地址为: {0}'.format(ipv4))
# conn.settimeout(500)
# 收到请求后的回复
print('发送数据...')
while True:
fn = input('文件名') #子进程无法使用input()
path = './send/'
file_path = os.path.join(path, str(fn)).replace('\\', '/')
fp = open(file_path, 'rb')
fhead = struct.pack('128sl', os.path.basename(file_path).encode('utf-8'), os.stat(file_path).st_size)
s.send(fhead)
while True:
data = fp.read(1024)
if not data:
print('{0} 数据传输完成...'.format(os.path.basename(file_path)))
break
s.send(data)
# 传输结束断开连接
# conn.close()
break
def file_manager():
if os.path.exists('./receive//'):
pass
else:
os.makedirs('./receive//')
if os.path.exists('./send//'):
pass
else:
os.makedirs('./send//')
#!coding=utf-8
import socket
import os
import sys
import struct
def socket_client(ipv4,port,stat):
# if str(stat) == 'send':
# t = threading.Thread(target=deal_data_send_client, args=(ipv4,port))
# elif str(stat) == 'receive':
# t = threading.Thread(target=deal_data_receiver_client, args=(ipv4,port))
# else:
# print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
# t.start()
if str(stat) == 'send':
deal_data_send_client(ipv4,port)
elif str(stat) == 'receive':
deal_data_receiver_client(ipv4,port)
else:
print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
#打洞程序
def port_To_port():
os.system('python ./Natter-master/natter.py -c ./Natter-master/natter-config.templete.json')
"""
// 注意:JSON 配置文件不支持代码注释,此处为说明配置用途。
{
"logging": {
"level": "info", // 日志等级:可选值:"debug"、"info"、"warning"、"error"
"log_file": "./natter.log" // 将日志输出到指定文件,不需要请留空:""
},
"status_report": {
// 当外部IP/端口发生改变时,会执行下方命令。
// 大括号 {...} 为占位符,命令执行时会被实际值替换。
// 不需要请留空:""
"hook": "bash ./natter-hook.sh '{protocol}' '{inner_ip}' '{inner_port}' '{outer_ip}' '{outer_port}'",
"status_file": "./natter-status.json" // 将实时端口映射状态储存至指定文件,不需要请留空:""
},
"open_port": {
// 此处设置 Natter 打洞IP:端口。(仅打洞)
// 此处地址为 Natter 绑定(监听)的地址,Natter 仅对这些地址打洞,您需要手动设置端口转发。
// 注意:使用默认出口IP,请使用 0.0.0.0 ,而不是 127.0.0.1 。
"tcp": [
"0.0.0.0:3456",
"0.0.0.0:3457"
],
"udp": [
"0.0.0.0:3456",
"0.0.0.0:3457"
]
},
"forward_port": {
// 此处设置需要 Natter 开放至公网的 IP:端口。(打洞 + 内置转发)
// Natter 会全自动打洞、转发,您无需做任何干预。
// 注意:使用本机IP,请使用 127.0.0.1,而不是 0.0.0.0 。
"tcp": [
"127.0.0.1:80",
"192.168.1.100:443"
],
"udp": [
"127.0.0.1:53",
"192.168.1.100:51820"
]
},
"stun_server": {
// 此处设置公共 STUN 服务器。
// TCP 服务器请确保 TCP/3478 端口开放可用;
// UDP 服务器请确保 UDP/3478 端口开放可用。
"tcp": [
"stun.stunprotocol.org",
"stun.voip.blackberry.com"
],
"udp": [
"stun.miwifi.com",
"stun.qq.com"
]
},
"keep_alive": "www.qq.com" // 此处设置 HTTP Keep-Alive 服务器。请确保该服务器 80 端口开放,且支持 HTTP Keep-Alive。
}
http://www.hackdig.com/03/hack-951107.htm
"""
#同一主机采用127.0.0.1,同一路由网络采用192.168.1.100(路由分配网络)
#不同网络,尝试打洞,采用natter.py(python natter.py 80)打洞port:80
if __name__ == '__main__':
file_manager()
# port_To_port()
ipv4 = input('ipv4:127.0.0.1')
port = input('port:80')
try:
socket_service(ipv4=ipv4,port=int(port),stat='send')
# socket_client(ipv4=ipv4,port=int(port),stat='receive')
except:
pass

输出结果:
ipv4:127.0.0.1192.168.1.100
port:8080
服务器Ipv4地址是127.0.0.1,服务器的端口是80
服务端已启动,等待客户端连接…
已连接地址为: (‘192.168.1.103’, 49907)
发送数据…
请输入文件名爬虫数据.rar
爬虫数据.rar 数据传输完成…

2 socket_client

import socket
import threading
import struct
import os
def socket_service(ipv4,port,stat):
#ipv4为IP地址,port为端口,stat可选择"send"或"recive"(代表文件发送或文件接收)
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口为9001
# 同一网络的不同主机
# s.bind(('192.168.0.16', 9001))
# 同一网络同一主机
s.bind((ipv4,port)) #参数为ipv4,port
# 设置监听数
s.listen(10)
print("服务器Ipv4地址是127.0.0.1,服务器的端口是80")
except socket.error as msg:
print(msg)
os.sys.exit(1)
print('服务端已启动,等待客户端连接...')
while True:
# 等待请求并接受(程序会停留在这一旦收到连接请求即开启接受数据的线程)
conn, addr = s.accept()
# 发送或接收数据
if str(stat) == 'send':
t = threading.Thread(target=deal_data_send_service, args=(conn,addr))
elif str(stat) == 'receive':
t = threading.Thread(target=deal_data_receiver_service, args=(conn,addr))
else:
print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
break
t.start()
def deal_data_receiver_service(conn, addr):
print('已连接地址为: {0}'.format(addr))
# conn.settimeout(500)
# 收到请求后的回复
conn.send('新消息:已成功连接'.encode('utf-8'))
while True:
# 申请相同大小的空间存放发送过来的文件名与文件大小信息
fileinfo_size = struct.calcsize('128sl') #创建128比特的待储存空间
# 接收文件名与文件大小信息
buf = conn.recv(fileinfo_size)#128比特的文件头信息放在待储存空间
# 判断是否接收到文件头信息
if buf:
# 获取文件名和文件大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print('数据名为: {0}, 数据大小为: {1} bytes'.format(str(fn), filesize))
recvd_size = 0 # 定义已接收文件的大小
# 存储在该脚本所在目录下面
fp = open('./receive/' + str(fn), 'wb')
print('开始接收客户端数据...'+'文件名:'+str(fn))
# 将分批次传输的二进制流依次写入到文件
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = conn.recv(1024)
recvd_size += len(data)
else:
data = conn.recv(filesize - recvd_size)
recvd_size = filesize
fp.write(data)
fp.close()
print('数据接收完成...')
break
def deal_data_send_service(conn, addr):
print('已连接地址为: {0}'.format(addr))
# conn.settimeout(500)
# 收到请求后的回复
conn.send('新消息:已成功连接'.encode('utf-8'))
while True:
print('发送数据...')
fn = input('请输入文件名') #子进程无法使用input()
path = './send/'
file_path = os.path.join(path, str(fn)).replace('\\', '/')
fp = open(file_path, 'rb')
fhead = struct.pack('128sl', os.path.basename(file_path).encode('utf-8'), os.stat(file_path).st_size)
conn.send(fhead)
while True:
data = fp.read(1024)
if not data:
print('{0} 数据传输完成...'.format(os.path.basename(file_path)))
break
conn.send(data)
# 传输结束断开连接
# conn.close()
break
def deal_data_receiver_client(ipv4, port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ipv4, port))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024).decode())
print('已连接地址为: {0}'.format(ipv4))
# conn.settimeout(500)
# 收到请求后的回复
# s.send('新消息:已成功连接'.encode('utf-8'))
while True:
# 申请相同大小的空间存放发送过来的文件名与文件大小信息
fileinfo_size = struct.calcsize('128sl') #创建128比特的待储存空间
# 接收文件名与文件大小信息
buf = s.recv(fileinfo_size)#128比特的文件头信息放在待储存空间
# 判断是否接收到文件头信息
if buf:
# 获取文件名和文件大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print('数据名为: {0}, 数据大小为: {1} bytes'.format(str(fn), filesize))
recvd_size = 0 # 定义已接收文件的大小
# 存储在该脚本所在目录下面
fp = open('./receive/' + str(fn), 'wb')
print('开始接收客户端数据...'+'文件名:'+str(fn))
# 将分批次传输的二进制流依次写入到文件
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = s.recv(1024)
recvd_size += len(data)
else:
data = s.recv(filesize - recvd_size)
recvd_size = filesize
fp.write(data)
fp.close()
print('数据接收完成...')
break
def deal_data_send_client(ipv4, port):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ipv4, port))
except socket.error as msg:
print(msg)
sys.exit(1)
print(s.recv(1024).decode())
print('已连接地址为: {0}'.format(ipv4))
# conn.settimeout(500)
# 收到请求后的回复
print('发送数据...')
while True:
fn = input('文件名') #子进程无法使用input()
path = './send/'
file_path = os.path.join(path, str(fn)).replace('\\', '/')
fp = open(file_path, 'rb')
fhead = struct.pack('128sl', os.path.basename(file_path).encode('utf-8'), os.stat(file_path).st_size)
s.send(fhead)
while True:
data = fp.read(1024)
if not data:
print('{0} 数据传输完成...'.format(os.path.basename(file_path)))
break
s.send(data)
# 传输结束断开连接
# conn.close()
break
def file_manager():
if os.path.exists('./receive//'):
pass
else:
os.makedirs('./receive//')
if os.path.exists('./send//'):
pass
else:
os.makedirs('./send//')
#!coding=utf-8
import socket
import os
import sys
import struct
def socket_client(ipv4,port,stat):
# if str(stat) == 'send':
# t = threading.Thread(target=deal_data_send_client, args=(ipv4,port))
# elif str(stat) == 'receive':
# t = threading.Thread(target=deal_data_receiver_client, args=(ipv4,port))
# else:
# print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
# t.start()
if str(stat) == 'send':
deal_data_send_client(ipv4,port)
elif str(stat) == 'receive':
deal_data_receiver_client(ipv4,port)
else:
print("warning:stat参数错误,服务端未能启动,请选择send 或者 receive")
#打洞程序
def port_To_port():
os.system('python ./Natter-master/natter.py -c ./Natter-master/natter-config.templete.json')
"""
// 注意:JSON 配置文件不支持代码注释,此处为说明配置用途。
{
"logging": {
"level": "info", // 日志等级:可选值:"debug"、"info"、"warning"、"error"
"log_file": "./natter.log" // 将日志输出到指定文件,不需要请留空:""
},
"status_report": {
// 当外部IP/端口发生改变时,会执行下方命令。
// 大括号 {...} 为占位符,命令执行时会被实际值替换。
// 不需要请留空:""
"hook": "bash ./natter-hook.sh '{protocol}' '{inner_ip}' '{inner_port}' '{outer_ip}' '{outer_port}'",
"status_file": "./natter-status.json" // 将实时端口映射状态储存至指定文件,不需要请留空:""
},
"open_port": {
// 此处设置 Natter 打洞IP:端口。(仅打洞)
// 此处地址为 Natter 绑定(监听)的地址,Natter 仅对这些地址打洞,您需要手动设置端口转发。
// 注意:使用默认出口IP,请使用 0.0.0.0 ,而不是 127.0.0.1 。
"tcp": [
"0.0.0.0:3456",
"0.0.0.0:3457"
],
"udp": [
"0.0.0.0:3456",
"0.0.0.0:3457"
]
},
"forward_port": {
// 此处设置需要 Natter 开放至公网的 IP:端口。(打洞 + 内置转发)
// Natter 会全自动打洞、转发,您无需做任何干预。
// 注意:使用本机IP,请使用 127.0.0.1,而不是 0.0.0.0 。
"tcp": [
"127.0.0.1:80",
"192.168.1.100:443"
],
"udp": [
"127.0.0.1:53",
"192.168.1.100:51820"
]
},
"stun_server": {
// 此处设置公共 STUN 服务器。
// TCP 服务器请确保 TCP/3478 端口开放可用;
// UDP 服务器请确保 UDP/3478 端口开放可用。
"tcp": [
"stun.stunprotocol.org",
"stun.voip.blackberry.com"
],
"udp": [
"stun.miwifi.com",
"stun.qq.com"
]
},
"keep_alive": "www.qq.com" // 此处设置 HTTP Keep-Alive 服务器。请确保该服务器 80 端口开放,且支持 HTTP Keep-Alive。
}
http://www.hackdig.com/03/hack-951107.htm
"""
#同一主机采用127.0.0.1,同一路由网络采用192.168.1.100(路由分配网络)
#不同网络,尝试打洞,采用natter.py(python natter.py 80)打洞port:80
if __name__ == '__main__':
file_manager()
# port_To_port()
ipv4 = input('ipv4:127.0.0.1')
port = input('port:80')
try:
socket_client(ipv4=ipv4,port=int(port),stat='receive')
except:
pass
posted @   kuanleung  阅读(141)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2022-06-29 DID的使用指南,原理
点击右上角即可分享
微信分享提示