(2条消息) Python3的socket和socketserver网络编程(聊天和文件传输功能)
文章目录
- 前言
- 一、TCP以及UDP的选择
- 二、socket以及socketserver
- 三、使用步骤
- 1.打开cmd输入python total_sever.py,创建服务器
- 2.打开cmd输入python total_client.py,创建客户端
- 四、使用截图
- 五、参考
- 总结
前言
接触了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 socketimport threading # 导入多线程模块import socketserver,struct,osHostport=('127.0.0.1',12303)hostport=('127.0.0.1',12304)true = True#聊天功能def chatsend():global trueprint("Watiing to be connected....")global Hostports = 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 = Falseprint("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’时,关闭sockettrue = Falseelif 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 truewhile 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:breakelif 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()# 关闭openprint("接收完毕")chatsend()except:passtcpSever = socketserver.ThreadingTCPServer(hostport,MyTCP)# TCPServer是接收到请求后执行handle方法,这里是相当于建立新线程的方法运行handletcpSever.serve_forever()# 相当于循环启动线程except:passif __name__ == '__main__':print('''请选择功能:1.聊天(附带文件发送功能。输入文件发送)''')sda=Truewhile sda:keyboard_input=input()if keyboard_input=="1":chatsend()sda=Falseelse:print("输入选择项错误请重新输入")continue
2.打开cmd输入python total_client.py,创建客户端
代码如下(示例):
# -*- coding: UTF-8 -*-import socket,os,structimport threadingimport timetrue=True#聊天def chatsend():global truehostport=('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 truewhile true:data=s.recv(1024).decode("utf8")if data == "quit":true = Falseelif 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’时,关闭sockettrue = False#发送文件def sendfile():s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect(('127.0.0.1',12304))true = Truedef 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:# 判断文件是否存在,并且进行传输breaks.send(file_data)# 发送数据open_file.close()print('传输完成!')thrd=threading.Thread(target=xunhuanchuanshu,args=(s,))# 线程实例化,target为方法,args为方法的参数thrd.start()if __name__ == '__main__':print('''请选择功能:1.聊天(附带文件发送功能。输入文件发送)''')sda=Truewhile sda:keyboard_input=input()if keyboard_input=="1":chatsend()sda=Falseelse: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的意思,本地测试可以使用。