分享

Python3的socket和socketserver网络编程(聊天和文件传输功能)...

 大傻子的文渊阁 2021-02-23

前言

接触了Python黑帽子一本书,看到了网络编程socket这一章,觉得挺有意思的,花了一点时间去学了一下,写了一份代码,主要是实现同一ip和端口下用cmd进行聊天和传输文件,很多大神写的没有注释看起来有点吃力,我在代码中已经详细给出了注释。


提示:以下是本篇文章正文内容,下面案例可供参考

一、TCP以及UDP的选择

TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。

所以我写了一个TCP服务器和客户端。都是可以直接拿下来用的。因为只是测试版本还有很多地方没有优化,仅供参考。

二、socket以及socketserver

Python提供了两个基本的socket模块。一个是socket,它提供了标准的BSD Socket API;另一个是socketServer,它提供了服务器中心类,可以简化网络服务器的开发。我的TCP这两个都用到了,可以给你们一个参考。他们的具体区别和使用可以参考:https://www.cnblogs.com/panwenbin-logs/p/5655130.html

三、使用步骤

1.打开cmd输入python total_sever.py,创建服务器

代码如下(示例):

import socket
import threading # 导入多线程模块
import socketserver,struct,os

Hostport=('127.0.0.1',12303)
hostport=('127.0.0.1',12304)
true = True

#聊天功能
def chatsend():
global true
print("Watiing to be connected....")
global Hostport
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)# 创建socket实例
s.bind(Hostport)
s.listen(1)
conn,addr = s.accept()
addr = str(addr)
print("Connecting by: "+addr)
def Receve(conn):# 将接收定义成一个函数
global true # 声明全局变量,当接收到的消息为quit时,则触发全局变量 true = False,则会将socket关闭
while true:

data = conn.recv(1024).decode('utf8')
if data == "quit":# 当接收的值为'quit'时,退出接收线程,否则,循环接收并打印
true = False
print("You have receve: "+data)
thrd=threading.Thread(target=Receve,args=(conn,))# 线程实例化,target为方法,args为方法的参数
thrd.start()# 启动线程
while true:
uesr_input = input("请输入>>> \n")
conn.send(uesr_input.encode('utf8'))# 循环发送消息
if uesr_input == 'quit':                                    # 当发送为‘quit’时,关闭socket
true = False
elif uesr_input == "文件发送":
filesend()# 输入为文件发送时调用filesend()


# 文件传输功能
def filesend():
try:
class MyTCP(socketserver.BaseRequestHandler):
def handle(self):
try:
print("已成功连接上: ",self.client_address)
file_define_size = struct.calcsize('128sl')# 定义文件大小信息,128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
self.file=self.request.recv(file_define_size)# 接受信息并且将文件信息大小代入
global true
while true:
if self.file:# 如果文件大小存在
self.file_name,self.file_size=struct.unpack('128sl',self.file)# 根据128sl解包信息,与client端的打包规则相同,开始解包。
self.file_name=self.file_name.decode('utf8').strip('\00')# 使用strip()删除打包时附加的多余空字符
'''网络通信的一个数据包中,包含了文件类型、文件名、文件长度三项其中文件名默认是32字,用struct进行解包
虽然文件名输出出来是File,但实际上剩下的28个字用"\0"进行补全'''
print('文件内容大小: ',self.file_size,'文件名字: ',self.file_name)
self.file_new_name = os.path.join("d:\\",self.file_name)#文件路径
print('文件存储的路径为',self.file_new_name)
recvd_filesize = 0 # 定义了接收的文件大小
files = open(self.file_new_name,"wb")# 写入文件
print("开始接收文件...")
while not recvd_filesize == self.file_size:
if self.file_size==0:
break
elif self.file_size - recvd_filesize > 10:
rdata = self.request.recv(10)# 这里设置为10,方便cmd看文件过大如何进行增加size的
recvd_filesize += len(rdata)
print(str(recvd_filesize)+"被传输")
else:
rdata = self.request.recv(self.file_size - recvd_filesize)# 这里将剩下的内容补上
recvd_filesize = self.file_size # 退出while循环
print(str(recvd_filesize)+"补全")
tcpSever.shutdown()# 相当于结束线程
files.write(rdata)
files.close()# 关闭open
print("接收完毕")
chatsend()
except:
pass
tcpSever = socketserver.ThreadingTCPServer(hostport,MyTCP)# TCPServer是接收到请求后执行handle方法,这里是相当于建立新线程的方法运行handle
tcpSever.serve_forever()# 相当于循环启动线程
except:
pass

if __name__ == '__main__':
print('''
请选择功能:
1.聊天(附带文件发送功能。输入文件发送)
''')
sda=True
while sda:
keyboard_input=input()
if keyboard_input=="1":
chatsend()
sda=False
else:
print("输入选择项错误请重新输入")
continue

2.打开cmd输入python total_client.py,创建客户端

代码如下(示例):


# -*- coding: UTF-8 -*-
import socket,os,struct
import threading
import time
true=True
#聊天
def chatsend():
global true
hostport=('127.0.0.1',12303)# 这是本地的可以采用cmd的netstat查看IP和端口,端口数字往后移动一位
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)# 创建socket实例
s.connect(hostport)# 连接IP和端口
def Receve(s):
global true
while true:
data=s.recv(1024).decode("utf8")
if data == "quit":
true = False
elif data == "文件发送":
sendfile()
print('receve news: '+data)
thrd=threading.Thread(target=Receve,args=(s,))# 线程实例化,target为方法,args为方法的参数
thrd.start()# 启动线程
while true:
uesr_input=input("请输入: \n")
s.send(uesr_input.encode("utf8"))
if uesr_input == "quit":# 当发送为‘quit’时,关闭socket
true = False



#发送文件
def sendfile():
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',12304))
true = True
def xunhuanchuanshu(s):
filepath = input("对方请求发送文件,请输入文件的绝对路径:\r\n")# 换行符为各系统默认的换行符(\n, \r, or \r\n, )
if os.path.isfile(filepath):
file_pack =struct.pack('128sl',os.path.basename(filepath).encode('utf8'),os.stat(filepath).st_size) # pack需要定义文件头信息,包含文件名和文件大小
s.send(file_pack)# 发送包
print('客户端传输文件绝对路径: ', filepath)
open_file = open(filepath,'rb')# 读取成二进制格式数据
while True:
file_data = open_file.read(1024)
if not file_data:# 判断文件是否存在,并且进行传输
break
s.send(file_data)# 发送数据
open_file.close()
print('传输完成!')
thrd=threading.Thread(target=xunhuanchuanshu,args=(s,))# 线程实例化,target为方法,args为方法的参数
thrd.start()



if __name__ == '__main__':
print('''
请选择功能:
1.聊天(附带文件发送功能。输入文件发送)
''')
sda=True
while sda:
keyboard_input=input()
if keyboard_input=="1":
chatsend()
sda=False
else:
print("输入选择项错误请重新输入")
continue

四、使用截图

1.先要打开cmd运行total_sever.py文件打开服务器等待连接。在这里插入图片描述
2.然后打开cmd运行total_client.py文件连接服务器。在这里插入图片描述
3.实现聊天在这里插入图片描述在这里插入图片描述
4.实现聊天中用total_client实现请求文件,total_client发送并且不中断聊天(如需双方都发送文件功能需要自己加写代码)
在这里插入图片描述
在这里插入图片描述

五、参考

https://blog.csdn.net/Dyy8686/article/details/79356189?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

https://blog.csdn.net/weixin_37579123/article/details/85841251

总结

这份代码是我自己写的一个测试版本,很多功能和需要优化的地方还没有进行优化,需要用的同学可以自己参考然后进行修改。
经过测试可以实现两台电脑一起聊天和发送文件,前提是对方电脑能够在cmd里面ping的通你的ip,ip和端口可以使用cmd然后输入netstat进行查看,如果是192.168.12.3:2020,那么你需要在代码写为192.168.12.3:2021。
127.0.0.1是本地ip的意思,本地测试可以使用。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多