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函数表示在处理数据前后分别可以什么事,这里可以自定义

posted @ 2018-04-18 17:20  FRESHMANS  阅读(209)  评论(0编辑  收藏  举报