飞鸽传书-完整版
main.py
import socket
import time
import threading
import multiprocessing
import FeiQCoreData
import FeiQRecv
import FeiQSend
import FeiQTcp
def create_udp_socket():
"""创建udp套接字"""
FeiQCoreData.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
FeiQCoreData.udp_socket.bind(("", FeiQCoreData.feiq_port))
FeiQCoreData.udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
def print_online_user():
"""打印在线用户列表"""
for i, user_info in enumerate(FeiQCoreData.user_list):
print(i, user_info)
def print_all_waiting_files():
"""显示可以下载的文件"""
for i, file_info in enumerate(FeiQCoreData.download_file_list):
print(i, file_info)
def print_menu():
"""显示飞鸽传书的功能"""
print(" 飞鸽传书v1.0")
print("1:上线广播")
print("2:下线广播")
print("3:给指定的ip发送数据")
print("4:显示在线用户信息")
print("5:给指定的ip发送文件")
print("6:显示可以下载文件")
print("7:下载文件")
print("0:退出")
def main():
FeiQCoreData.file_queue = multiprocessing.Queue()
tcp_process = multiprocessing.Process(target=FeiQTcp.tcp_main, args=(FeiQCoreData.file_queue,))
tcp_process.start()
create_udp_socket()
recv_msg_thread = threading.Thread(target=FeiQRecv.recv_msg)
recv_msg_thread.start()
while True:
print_menu()
command_num = input("请输入要进行的操作:")
if command_num == "1":
FeiQSend.send_broadcast_online_msg()
elif command_num == "2":
FeiQSend.send_broadcast_offline_msg()
elif command_num == "3":
FeiQSend.send_chat_msg()
elif command_num == "4":
print_online_user()
elif command_num == "5":
FeiQSend.send_file_msg()
elif command_num == "6":
print_all_waiting_files()
elif command_num == "7":
FeiQSend.download_file()
elif command_num == "0":
FeiQSend.send_broadcast_offline_msg()
FeiQCoreData.udp_socket.close()
exit()
if __name__ == "__main__":
main()
FeiQRecv.py
import FeiQCoreData
import FeiQSend
def deal_with_recv_msg(recv_msg):
"""处理接收到的数据"""
recv_msg = recv_msg.decode("gbk", errors="ignore")
feiq_info_list = recv_msg.split(":", 5)
feiq_data = dict()
feiq_data['version'] = feiq_info_list[0]
feiq_data['packet_id'] = feiq_info_list[1]
feiq_data['user_name'] = feiq_info_list[2]
feiq_data['host_name'] = feiq_info_list[3]
feiq_data['command_num'] = feiq_info_list[4]
feiq_data['option'] = feiq_info_list[5]
return feiq_data
def get_command_option(command_num):
"""提取命令以及命令选项"""
command = int(command_num) & 0x000000ff
option = int(command_num) & 0xffffff00
return command, option
def recv_msg():
"""接收数据"""
while True:
recv_data, dest_addr = FeiQCoreData.udp_socket.recvfrom(1024)
feiq_data = deal_with_recv_msg(recv_data)
command, option = get_command_option(feiq_data['command_num'])
if command == FeiQCoreData.IPMSG_BR_ENTRY:
print("%s上线" % feiq_data['user_name'])
find_position = feiq_data['option'].find("\0")
if find_position != -1:
user_name = feiq_data['option'][:find_position]
else:
user_name = feiq_data['option']
new_user_info = dict()
new_user_info['ip'] = dest_addr[0]
new_user_info['user_name'] = user_name
if new_user_info not in FeiQCoreData.user_list:
FeiQCoreData.user_list.append(new_user_info)
answer_online_msg = FeiQSend.build_msg(FeiQCoreData.IPMSG_ANSENTRY)
FeiQSend.send_msg(answer_online_msg, dest_addr[0])
elif command == FeiQCoreData.IPMSG_BR_EXIT:
print("%s下线" % feiq_data['user_name'])
for user_info in FeiQCoreData.user_list:
if dest_addr[0] == user_info['ip']:
FeiQCoreData.user_list.remove(user_info)
break
elif command == FeiQCoreData.IPMSG_ANSENTRY:
print("%s已经在线" % feiq_data['user_name'])
find_position = feiq_data['option'].find("\0")
if find_position != -1:
user_name = feiq_data['option'][:find_position]
else:
user_name = feiq_data['option']
new_user_info = dict()
new_user_info['ip'] = dest_addr[0]
new_user_info['user_name'] = user_name
if new_user_info not in FeiQCoreData.user_list:
FeiQCoreData.user_list.append(new_user_info)
elif command == FeiQCoreData.IPMSG_SENDMSG:
if option & 0x00f00000 == FeiQCoreData.IPMSG_FILEATTACHOPT:
file_info_msg = dict()
file_info_list = feiq_data['option'][1:].split(":", 5)
file_info_msg['packet_id'] = int(feiq_data['packet_id'])
file_info_msg['file_id'] = int(file_info_list[0])
file_info_msg['file_name'] = file_info_list[1]
file_info_msg['file_size'] = int(file_info_list[2], 16)
file_info_msg['dest_ip'] = dest_addr[0]
FeiQCoreData.download_file_list.append(file_info_msg)
else:
print("%s(%s)>>>%s" % (feiq_data['user_name'], str(dest_addr), feiq_data['option']))
recv_ok_msg = FeiQSend.build_msg(FeiQCoreData.IPMSG_RECVMSG)
FeiQSend.send_msg(recv_ok_msg, dest_addr[0])
FeiQCoreData.py
udp_socket = None
feiq_version = 1
feiq_user_name = "dong-test"
feiq_host_name = "ubuntu-64-1604"
broadcast_ip = "255.255.255.255"
feiq_port = 2425
IPMSG_BR_ENTRY = 0x00000001
IPMSG_BR_EXIT = 0x00000002
IPMSG_SENDMSG = 0x00000020
IPMSG_ANSENTRY = 0x00000003
IPMSG_RECVMSG = 0x00000021
IPMSG_GETFILEDATA = 0x00000060
IPMSG_FILEATTACHOPT = 0x00200000
IPMSG_FILE_REGULAR = 0x00000001
user_list = list()
send_file_list = list()
download_file_list = list()
file_queue = None
packet_id = 0
FeiQSend.py
import FeiQCoreData
import time
import os
def build_msg(command_num, option=""):
"""构建飞鸽传书的数据包"""
FeiQCoreData.packet_id = int(time.time())
msg = "%d:%d:%s:%s:%d:%s" % (FeiQCoreData.feiq_version, FeiQCoreData.packet_id,
FeiQCoreData.feiq_user_name, FeiQCoreData.feiq_host_name,
command_num, option)
return msg
def send_msg(msg, dest_ip):
"""发送飞鸽传书数据"""
FeiQCoreData.udp_socket.sendto(msg.encode("gbk"), (dest_ip, FeiQCoreData.feiq_port))
def send_broadcast_online_msg():
"""发送上线提醒"""
online_msg = build_msg(FeiQCoreData.IPMSG_BR_ENTRY, FeiQCoreData.feiq_user_name)
send_msg(online_msg, FeiQCoreData.broadcast_ip)
def send_broadcast_offline_msg():
"""发送下线提醒"""
offline_msg = build_msg(FeiQCoreData.IPMSG_BR_EXIT, FeiQCoreData.feiq_user_name)
send_msg(offline_msg, FeiQCoreData.broadcast_ip)
def send_chat_msg():
"""发送聊天信息"""
dest_ip = input("请输入对方的ip(输入0显示当前所有的在线用户):")
if dest_ip == "0":
print("="*30)
for i, user_info in enumerate(FeiQCoreData.user_list):
print(i, user_info)
print("="*30)
try:
num = int(input("请输入用户对应的序号:"))
except:
print("输入有误...")
return
else:
dest_ip = FeiQCoreData.user_list[num]['ip']
send_data = input("请输入要发送的内容:")
if dest_ip and send_data:
chat_msg = build_msg(FeiQCoreData.IPMSG_SENDMSG, send_data)
send_msg(chat_msg, dest_ip)
def send_file_msg():
"""给指定的ip发送文件"""
dest_ip = input("请输入对方的ip(输入0显示当前所有的在线用户):")
if dest_ip == "0":
print("="*30)
for i, user_info in enumerate(FeiQCoreData.user_list):
print(i, user_info)
print("="*30)
try:
num = int(input("请输入用户对应的序号:"))
except:
print("输入有误...")
return
else:
dest_ip = FeiQCoreData.user_list[num]['ip']
file_name = input("请输入要发送的文件名:")
if dest_ip and file_name:
try:
file_size = os.path.getsize(file_name)
file_ctime = os.path.getctime(file_name)
except:
print("没有此文件。。。。")
else:
option = "%d:%s:%x:%x:%x:" % (0, file_name, file_size, int(file_ctime), FeiQCoreData.IPMSG_FILE_REGULAR)
option = "\0" + option
file_msg = build_msg(FeiQCoreData.IPMSG_SENDMSG|FeiQCoreData.IPMSG_FILEATTACHOPT, option)
send_msg(file_msg, dest_ip)
send_file_info = dict()
send_file_info['packet_id'] = FeiQCoreData.packet_id
send_file_info['file_id'] = 0
send_file_info['file_name'] = file_name
queue_info = dict()
queue_info['type'] = "send_file"
queue_info['data'] = send_file_info
FeiQCoreData.file_queue.put(queue_info)
def download_file():
"""下载文件"""
for i, file_info in enumerate(FeiQCoreData.download_file_list):
print(i, file_info)
try:
num = int(input("请输入要下载的文件序号:"))
except:
print("输入数据有误....")
return
else:
file_info = FeiQCoreData.download_file_list[num]
queue_info = dict()
queue_info['type'] = "download_file"
queue_info['data'] = file_info
FeiQCoreData.file_queue.put(queue_info)
FeiQTcp.py
import socket
import threading
import FeiQCoreData
import FeiQSend
def deal_with_recv_msg(recv_msg):
"""处理接收到的数据"""
recv_msg = recv_msg.decode("gbk", errors="ignore")
feiq_info_list = recv_msg.split(":", 5)
feiq_data = dict()
feiq_data['version'] = feiq_info_list[0]
feiq_data['packet_id'] = feiq_info_list[1]
feiq_data['user_name'] = feiq_info_list[2]
feiq_data['host_name'] = feiq_info_list[3]
feiq_data['command_num'] = feiq_info_list[4]
feiq_data['option'] = feiq_info_list[5]
return feiq_data
def deal_with_file_option(option_data):
file_info_list = option_data.split(":", 3)
return int(file_info_list[0], 16), int(file_info_list[1])
def send_file(client_socket):
request_info = client_socket.recv(1024)
feiq_data = deal_with_recv_msg(request_info)
packet_id, file_id = deal_with_file_option(feiq_data['option'])
print("下载的文件包编号是:%d, 文件序号:%d" % (packet_id, file_id))
file_name = ""
for file_info in FeiQCoreData.send_file_list:
if file_info['packet_id'] == packet_id and file_info['file_id'] == file_id:
file_name = file_info['file_name']
break
else:
print("对方需要下载的文件不存在")
f = open(file_name, "rb")
while True:
content = f.read(1024)
if content:
client_socket.send(content)
else:
break
f.close()
client_socket.close()
def download_file(file_info):
"""下载文件"""
client_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
option = "%x:%x:%x" % (file_info['packet_id'], file_info['file_id'], 0)
request_info = FeiQSend.build_msg(FeiQCoreData.IPMSG_GETFILEDATA, option)
client_tcp_socket.connect((file_info['dest_ip'], FeiQCoreData.feiq_port))
client_tcp_socket.send(request_info.encode("gbk"))
f = open(file_info['file_name'] ,"wb")
recv_data_length = 0
while True:
recv_data = client_tcp_socket.recv(1024)
if recv_data:
f.write(recv_data)
else:
break
recv_data_length += len(recv_data)
if recv_data_length >= file_info['file_size']:
break
f.close()
print("下载(%s)ok" % file_info['file_name'])
def get_file_msg_from_queue(file_queue):
"""从Queue 获取需要下载或者发送的文件信息"""
while True:
data_info = file_queue.get()
if data_info['type'] == "download_file":
print("需要下载。。。。", data_info['data'])
download_file(data_info['data'])
elif data_info['type'] == "send_file":
print("发送文件......", data_info['data'])
FeiQCoreData.send_file_list.append(data_info['data'])
def tcp_main(file_queue):
get_file_thread = threading.Thread(target=get_file_msg_from_queue, args=(file_queue,))
get_file_thread.start()
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.bind(("", FeiQCoreData.feiq_port))
tcp_server_socket.listen(128)
while True:
client_socket, client_addr = tcp_server_socket.accept()
send_file_thread = threading.Thread(target=send_file, args=(client_socket,))
send_file_thread.start()
if __name__ == '__main__':
tcp_main()