socket
socket基础
socket入门示例(发送简单数据)
##server端:
import socket #导入模块 server = socket.socket() server.bind(('localhost',6969)) #绑定地址和端口 server.listen() conn,addr = server.accept() #等待接受数据,conn为客户端连过来时在服务器端为其生成的实例 print (conn,addr) data = conn.recv(1024) #接收数据 print("rece:",data) #打印接收的数据
conn.send(data.upper()) #将接收的数据大写后发送给客户端 server.close() #关闭链接
###client端 import socket client = socket.socket() #声明socket类型,同时生成socket连接对象,默认地址簇为ipv4 client.connect(("localhost",6969)) client.send(b"this is my first socket test") #发送数据,python3.x只能发bytes类型,如果为中文的话,需要转换为bytes类型,"中文".encode("utf-8") data = client.recv(1024) #设置接收1024字节数据,默认也是1024 print ("receive:",data) #打印接收的数据 client.close() 打印结果: ##server端: <socket.socket fd=352, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 28301)> ('127.0.0.1', 28301) rece: b'this is my first socket test' ##client端: receive: b'THIS IS MY FIRST SOCKET TEST'
socket 入门进阶示例
说明:实现一个server对一个client会话保持,此时如果有多个client链接回陷入等待状态,等第一个client断开后,第二个client与server继续进行会话
#server端
#-*-coding:utf-8-*- import socket server = socket.socket() server.bind(('localhost',6969)) server.listen() while True: #使程序不停的接收数据 conn,addr = server.accept() #等待接受数据,conn为客户端连过来时在服务器端为其生成的实例 print (" receive data") while True: data = conn.recv(1024) #接收数据 print("rece:",data) if not data: #表示数据为空则为断开,因为在客户端已经对输出的命令做了限制, print ("client lost") break conn.send(data.upper()) server.close() #client端 import socket client = socket.socket() #声明socket类型,同时生成socket连接对象,默认地址簇为ipv4 client.connect(("localhost",6969)) while True: msg = input(">>:").strip() if len(msg) == 0: #不能send空数据 continue client.send(msg.encode("utf-8")) #发送数据,这里只能发bytes类型 data = client.recv(1024) #默认只收1024字节数据 print ("receive:",data) client.close()
socket入门示例之ssh执行命令
#server端 #-*-coding:utf-8-*- import socket,os,time
server = socket.socket() server.bind(('0.0.0.0',6979)) server.listen() while True: #使server持续保持连接,即使有一个客户端断开了,其余的客户端也能链接 conn,addr = server.accept() #等待接受数据,conn为客户端连过来时在服务器端为其生成的实例 print (" waiting data") while True: #不断接受客户端发来的命令 print(" reveive data") data = conn.recv(1024) #接收客户端发来的命令 print("rece:",data) if not data: print ("client lost") break res = os.popen(data.decode()).read() #执行命令,结果为字符串 if len(res) == 0: print (data.decode(),"get no any data get") conn.send(str(len(res.encode())).encode("utf-8")) #这里先将res(字符串)转化为bytes类型,然后获取bytes类型的长度,在通过str命令,encode为bytes类型发送个客户端
#这里直接获取str的长度(与bytes类型的长度不一样,导致客户端一次性不能完全接收所有数据,然后报错,所以不使用,仅作记录),转化为str然后encode为bytes发送给客户端
#conn.send(str(len(res)).encode("utf-8"))
#粘包问题:程序将多个要分开发送的数据合并成一条数据发送,致使客户端处理时发生错误 #time.sleep(0.5) #可解决粘包的问题,但是不实际 client_ack = conn.recv(1024) #彻底解决粘包的问题,客户端接受到数据后,返回一个确认信息,这里收到client的应答后继续执行下面的发送命令 conn.send(res.encode("utf-8")) print ("数据发送完成 ") server.close() #client端
import socket client = socket.socket() client.connect(("192.168.132.130",6979)) while True: msg = input(">>:").strip() if len(msg) == 0: continue client.send(msg.encode("utf-8")) #发送命令,这里只能发bytes类型 cmd_res_size = client.recv(1024) #默认只收1024字节数据,返回执行命令的结果的长度 print ("命令结果大小 :",cmd_res_size) client.send("准备接收".encode()) #客户端发送一个确认收到的应答,解决粘包的问题 receive_size = 0 received_data = b'' while receive_size < int(cmd_res_size.decode()): #这里使用循环判断接收的数据长度是否等于执行命令结果的总长度,用于一次性接收所有数据 data = client.recv(1024) receive_size += len(data) received_data += data else: #这里while 和else配合使用 print("data receive done",receive_size) print (received_data.decode()) client.close()
socket文件传输及md5校验
#红色代码为md5相关操作
#server端 #-*-coding:utf-8-*- import socket,os,time server = socket.socket() server.bind(('0.0.0.0',6970)) server.listen() import os import hashlib while True: conn,addr = server.accept() #等待接受数据,conn为客户端连过来时在服务器端为其生成的实例 print (" waiting data") while True: print(" reveive data") data = conn.recv(1024) #接收数据 print("rece:",data) if not data: print ("client lost") break cmd,filename = data.decode().split() #对接收的数据进行处理,得到filename(数据格式 get xxx) print (filename) #判断是否为文件 if os.path.isfile(filename): f = open(filename,"rb") #以bytes打开文件 m = hashlib.md5() #初始化md5实例
file_size = os.stat(filename).st_size #得到想要获取的文件大小 conn.send(str(file_size).encode("utf-8")) #将得到的文件大小发送给 客户端 conn.recv(1024) #获取客户端收到响应后的应答
#获取文件的md5操作 for line in f: #每读一行就获取一下md5 m.update(line) conn.send(line) print ("file md5:",m.hexdigest()) #打印最终的文件的md5,并发送给客户端 f.close() conn.send(m.hexdigest().encode()) server.close() ##client端 #-*-coding:utf-8-*- import socket
import hashlib client = socket.socket() #声明socket类型,同时生成socket连接对象,默认地址簇为ipv4 client.connect(("192.168.132.130",6970)) while True: msg = input(">>:").strip() if len(msg) == 0: continue if msg.startswith("get"): #判断命令是否以get开头 client.send(msg.encode()) server_response = client.recv(1024) #将命令发送给服务端后获取到的文件大小 print ("文件大小:",server_response) client.send(b"ready to recv file") #告诉服务端响应收到,准备接收数据(解决文件接收的粘包问题) file_total_size = int(server_response.decode()) #对接收到的文件大小数据类型进行处理 recived_size = 0 filename = msg.split()[1] #获取命令的 文件名称 f = open(filename + '.new',"wb") #对接收过来的文件重新命名 m = hashlib.md5() #md5比对的相关代码 while recived_size < file_total_size: if file_total_size - recived_size > 1024: #解决文件传输和md5 传输时遇到的粘包问题,如果咩有md5比对,可以省去此处代码 size = 1024 else: size = file_total_size - recived_size print ("last receive:",size) data = client.recv(1024) recived_size += len(data) f.write(data) m.update(data) # print (file_total_size,recived_size) else: print ("recv done",received_size,file_total_size) f.close() new_file_md5 = m.hexdigest() server_file_md5 = client.recv(1024) print (server_file_md5,new_file_md5) client.close()
效果如图:
socketserver
socketserver基础示例(单线程版):
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): #继承BaseRequestHandler方法 def handle(self): # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() #socketserver 通过self.request 来接收和发送数据 print("{} wrote:".format(self.client_address[0])) #打印客户端的ip地址,可通过源码查看 print(self.data) #打印从客户端收到的数据 self.request.sendall(self.data.upper()) #将收到的数据大写处理后发送给客户端 if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) ##单线程 server.serve_forever()
#client端:
import socket client = socket.socket() #声明socket类型,同时生成socket连接对象,默认地址簇为ipv4 client.connect(("localhost",9999)) while True: msg = input(">>:").strip() if len(msg) == 0: #不能send空数据 continue client.send(msg.encode("utf-8")) #发送数据,这里只能发bytes类型 data = client.recv(1024) #默认只收1024字节数据 print ("receive:",data) client.close()
通过socketserver编写模拟多线程ssh
#-*-coding:utf-8-*- import socketserver #导入相关的模块 import os class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): print("connection from {}:".format(self.client_address[0])) while True: #不断接收客户端链接 self.data = self.request.recv(1024).strip() #接收数据 if not self.data: #如果命令为空就提示断开,因为在客户端已经做好设置,输入的命令不为空 print ("client lost") break #跳出循环从新开始接收数据
print("get cmd {}:".format(self.data.decode())) #如果命令不为空,就打印命令 cmd_result_size = os.popen(self.data.decode()).read() #打印命令执行结果,类型为str if len(cmd_result_size) == 0: #如果命令的执行结果长度为0,表示命令为错误命令或者执行的命令结果为空 print ("命令错误或执行结果为空") self.request.sendall(str(len(cmd_result_size)).encode()) #将执行的结果长度发送给客户端,客户端判断是否为错误,然后决定是否从新输入 else: print (cmd_result_size) self.request.send(str(len(cmd_result_size.encode())).encode()) #将执行命令结果大小发给客户端,客户端收到数据后返回一个确认收到的应答 client_ack = self.request.recv(1024) #这边收到应答会进行下一步 self.request.send(str(cmd_result_size).encode()) #将执行命令的结果发给客户端 # self.request.sendall(self.data.upper()) if __name__ == '__main__': HOST,PORT = "0.0.0.0" , 9999 #server = socketserver.TCPServer((HOST,PORT),MyTCPHandler) #单线程 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler) #多线程,可也允许多个客户端同时链接 server.serve_forever() ##client端: import socket client = socket.socket() #声明socket类型,同时生成socket连接对象,默认地址簇为ipv4 client.connect(("192.168.132.130",9999)) while True: msg = input(">>:").strip() if len(msg) == 0: continue client.send(msg.encode("utf-8")) #发送数据,这里只能发bytes类型 cmd_res_size = client.recv(1024) #默认只收1024字节数据,这里接收服务端执行命令的结果的字节长度 if cmd_res_size == b'0': #判断服务端发过来的命令执行的结果的字节长度,为0则。。 print ("命令不正确或者 文件/目录为空") continue else: print ("命令执行结果大小 :",cmd_res_size) #不为0 就执行 client.send(b"receive size ok")
###设定初始值 received_data = b'' received_size = 0 while received_size < int(cmd_res_size.decode()): ##接收大数据,如果接收到的数据小于数据的总大小,就循环接收 data = client.recv(1024) received_size += len(data) #因为接收到的数据不一定与设置的数据大小一致 received_data += data
#while else用法:只有while执行成功后,最后才会执行else else: print ("data received done",received_size) #打印接收的数据的总大小 print (received_data.decode()) client.close()
socketserver.BaseRequestHandler源码
class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish() def setup(self): pass def handle(self): pass def finish(self): pass
#说明:
由源码发现,socketserver的数据处理均有handle函数完成,而setup和finish函数表示在处理数据前后分别可以什么事,这里可以自定义