文章目录
- 前言
- 一、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这两个都用到了,可以给你们一个参考。他们的具体区别和使用可以参考:
三、使用步骤
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发送并且不中断聊天(如需双方都发送文件功能需要自己加写代码)
总结
这份代码是我自己写的一个测试版本,很多功能和需要优化的地方还没有进行优化,需要用的同学可以自己参考然后进行修改。
经过测试可以实现两台电脑一起聊天和发送文件,前提是对方电脑能够在cmd里面ping的通你的ip,ip和端口可以使用cmd然后输入netstat进行查看,如果是192.168.12.3:2020,那么你需要在代码写为192.168.12.3:2021。
127.0.0.1是本地ip的意思,本地测试可以使用。