代码拉取完成,页面将自动刷新
#!/usr/bin/env python
import os
import gzip
import errno
import time
import select
import socket
import os.path
import collections
''' TODO: set BASEPATH '''
ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)
BASEPATH = '/home/idd/hotmocha'
ERR_FMT_ERR = -1
ERR_TOO_LONG = -2
ERR_INTERNAL_ERR = -3
ERR_PERR_CLOSED = -4
ERR_READ_ERR = -5
ERR_WRITE_ERR = -6
ERR_OPEN_ERR = -7
ERR_RESP_ERR = -8
PROMPT_ENDS = '>'
CDOK = 'CDOK'
CDFAIL = 'CDFAIL'
CMD_PUT = 1
CMD_GET = 2
CMD_CD = 3
CMD_LS = 4
MUTIIO_READ = 0x01
MUTIIO_WRITE = 0x02
MUTIIO_ERROR = 0x04
def readfile(filename, start = None, end = None):
with open(filename, "rb") as file:
if start is not None:
file.seek(start)
if end is not None:
remaining = end - (start or 0)
else:
remaining = None
while True:
chunk_size = 8 * 1024
if remaining is not None and remaining < chunk_size:
chunk_size = remaining
chunk = file.read(chunk_size)
if chunk:
if remaining is not None:
remaining -= len(chunk)
yield chunk
else:
if remaining is not None:
raise TypeError('')
return
class log(object):
def __init__(self, logfilename):
self.logfilename = logfilename
def log(self, str):
print str
with open(self.logfilename, "ab+") as file:
file.write(str + '\n')
file.flush()
L = log("./server.log")
def geterrnofrome(e):
if hasattr(e, 'errno'):
return e.errno
elif e.args:
return e.args[0]
else:
return None
def mergeprefix(deque, size):
if len(deque) == 1 and len(deque[0]) <= size:
return
prefix = []
remaining = size
while deque and remaining > 0:
chunk = deque.popleft()
if len(chunk) > remaining:
deque.appendleft(chunk[remaining:])
chunk = chunk[:remaining]
prefix.append(chunk)
remaining -= len(chunk)
if prefix:
deque.appendleft(type(prefix[0])().join(prefix))
if not deque:
deque.appendleft(b"")
# bufdeque is a collections.deque
'''
RETURN:
0 : peer closed
ERR_READ_ERR :
>0 : read len
'''
def readfromsock(sock, bufdeque):
chunklen = 0
chunkdata = ''
l = ''
while True:
try:
chunkdata = sock.recv(8 * 1024)
l = len(chunkdata)
chunklen += l
if l == 0: return 0
except (IOError, OSError) as e:
if geterrnofrome(e) in ERRNO_WOULDBLOCK:
break
else:
return ERR_READ_ERR
#L.log('readfrom sock, data: ' + chunkdata + ' len: ' + str(chunklen))
if chunklen != 0:
bufdeque.append(chunkdata)
return chunklen
# bufdeque is a collections.deque
'''
RETURN:
0 : peer closed
ERR_WRITE_ERR :
>0 : send len
'''
def sendtosock(sock, bufdeque):
sendlen = 0
numbytes = 100
while bufdeque:
try:
if bufdeque[0] is None or len(bufdeque[0]) == 0:
mergeprefix(bufdeque, numbytes)
bufdeque.popleft()
numbytes = sock.send(bufdeque[0])
if numbytes == 0: return ERR_WRITE_ERR # attention: error
sendlen += numbytes
mergeprefix(bufdeque, numbytes)
bufdeque.popleft()
except (IOError, OSError) as e:
if geterrnofrome(e) in ERRNO_WOULDBLOCK:
break
else:
return ERR_WRITE_ERR
return sendlen
# sync write
'''
RETURN: write len
'''
def writetofile(file, bufdeque):
writelen = 0
while bufdeque:
if bufdeque[0] is None or len(bufdeque[0]) == 0:
bufdeque.popleft()
continue
file.write(bufdeque[0])
writelen += len(bufdeque[0])
bufdeque.popleft()
file.flush()
return writelen
'''
RETURN: read len
'''
def readfromfile(file, bufdeque):
readdata = file.read(8 * 1024)
bufdeque.append(readdata)
return len(readdata)
class commandaction(object):
def __init__(self, cmdtype, session, cmdline):
self.cmdtype = cmdtype
self.session = session
self.cmdline = cmdline
self.callback = None
def start(self):
raise NotImplementedError("not implements start function")
def parsecmdline(self):
raise NotImplementedError("not implements parse commandline function")
def startaction(self):
raise NotImplementedError("not implements startaction function")
def endaction(self, successflag = True):
if successflag == True:
L.log(self.session.cmdline + ' SUCCESS!')
else:
L.log(self.session.cmdline + ' FAILED!')
''' force clear command line buf '''
self.session.regetcommand()
MUTIIO.register(self.session.sockfd, MUTIIO_READ)
MUTIIO.unregister(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.session.handler_receivecmdline
def sendreponse(self):
numbytes = sendtosock(self.session.sock, self.session.outbuf)
if numbytes <= 0:
return ERR_WRITE_ERR
''' base class member:
cmdtype, session, cmdline, callback
1. client send command [put filename] and client waiting for server's getfileinfo response
2. server parse command
3. server send get fileinfo ok ['FILEINFO OK']
4. client get fileinfo's response and block to send server filedata
5. server receive filedata
6. when sendlen == filelen, server send response 'FILETRANSFER OK' to client
'''
class putfileaction(commandaction):
RESPONSE_GETFILEINFO_OK = 'FILEINFO OK\n'
RESPONSE_TRANSFERDATA_OK = 'FILETRANSFER OK\n'
def __init__(self, cmdname, session, cmdline):
super(putfileaction, self).__init__(cmdname, session, cmdline)
self.file = None
self.filename = ''
self.filelen = 0
def parsecmdline(self):
L.log('putfile parsecmdline: ' + self.cmdline)
x = self.cmdline.split(' ')
if len(x) <= 1:
L.log('command:' + self.cmdline + 'format error')
return ERR_FMT_ERR
else:
fileinfo = x[1].split(':')
if len(fileinfo) <= 1:
L.log('command:' + self.cmdline + 'format error')
return ERR_FMT_ERR
else:
self.filename = fileinfo[0]
self.filelen = int(fileinfo[1])
L.log('put cmdline: ' + self.filename + " " + str(self.filelen))
L.log('filename:' + self.filename + ' filelen: ' + str(self.filelen))
def startaction(self):
L.log('putfile startaction start :' + self.filename + ' : ' + str(self.filelen))
try:
self.file = open(self.filename, 'wb+')
except Exception as e:
L.log('open ' + self.filename + ' error')
return ERR_OPEN_ERR
self.session.outbuf.append(putfileaction.RESPONSE_GETFILEINFO_OK)
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.handler_respgetfileinfook
def handler_respgetfileinfook(self):
# call parent's public sendreponse function
L.log('putfile handler_respgetfileinfook')
if self.sendreponse() is not None:
L.log('sendreponse error ')
return ERR_RESP_ERR
# next stage
if not self.session.outbuf:
MUTIIO.unregister(self.session.sockfd, MUTIIO_WRITE)
MUTIIO.register(self.session.sockfd, MUTIIO_READ)
self.callback = self.handler_recvingfiledata
def handler_recvingfiledata(self):
L.log('putfile handler_recvingfiledata')
readlen = readfromsock(self.session.sock, self.session.inbuf)
if readlen <= 0:
L.log(" recving file data transfer error")
return ERR_READ_ERR
else:
# sync
writelen = writetofile(self.file, self.session.inbuf)
if readlen != writelen:
L.log('ERROR: write disk not corrent!')
self.filelen -= readlen
if self.filelen <= 0:
self.session.outbuf.append(putfileaction.RESPONSE_TRANSFERDATA_OK)
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.handler_resprecvdataok
def handler_resprecvdataok(self):
L.log('putfile handler_resprecvdataok: ' + self.session.outbuf[0])
# call parent's public sendreponse function
if self.sendreponse() is not None:
L.log('sendreponse error ')
return ERR_RESP_ERR
if not self.session.outbuf:
self.endaction()
return
'''
process stage:
1. client send command [get filename] and client waiting for server's getfileinfo
2. server parse command
3. server send fileinfo[filename filelen]
4. client get fileinfo and block to receive server filedata
5. server send filedata
6. when sendlen == filelen, client stop to send and server stop to receive
'''
class getfileaction(commandaction):
RESPONSE_SENDFILEINFO_OK = 'FILEINFO OK\n'
RESPONSE_TRANSFERDATA_OK = 'FILETRANSFER OK\n'
def __init__(self, cmdname, session, cmdline):
super(getfileaction, self).__init__(cmdname, session, cmdline)
self.file = None
self.filename = ''
self.filelen = 0
self.filedata = None
self.eof = False
def parsecmdline(self):
L.log('getfile parsecmdline:' + self.cmdline)
x = self.cmdline.split(' ')
if len(x) <= 1:
L.log('command:' + self.cmdline + 'format error')
return ERR_FMT_ERR
else:
self.filename = x[1]
L.log('get cmdline: ' + self.filename)
def startaction(self):
L.log('getfile startaction start :' + self.filename)
try:
statres = os.stat(self.filename)
self.file = open(self.filename)
except Exception as e:
L.log('stat ' + self.filename + ' error')
return ERR_OPEN_ERR
self.filelen = statres.st_size
responsefileinfo = self.filename + ' ' + str(self.filelen) + '\n'
L.log('getfile responsefileinfo: ' + responsefileinfo)
self.session.outbuf.append(responsefileinfo)
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.handler_sendfileinfo
def handler_sendfileinfo(self):
# call parent's public sendreponse function
L.log('getfile handler_sendfileinfo: ' + self.session.outbuf[0])
if self.sendreponse() is not None:
L.log('sendreponse error ')
return ERR_RESP_ERR
if not self.session.outbuf:
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.filedata = readfile(self.filename)
if self.filedata is None:
return ERR_READ_ERR
self.callback = self.handler_sendingfiledata
def handler_sendingfiledata(self):
L.log('getfile handler_sendingfiledata')
if not self.session.outbuf and self.eof == False and self.filelen > 0:
try:
tmpdata = self.filedata.next()
except StopIteration as e:
self.eof = True
except Exception as e:
return ERR_READ_ERR
if self.eof == False:
self.session.outbuf.append(tmpdata)
sendlen = sendtosock(self.session.sock, self.session.outbuf)
if sendlen <= 0:
L.log(self.clientip + " " + self.filename + " transfer error")
return ERR_WRITE_ERR
else:
self.filelen -= sendlen
if self.filelen <= 0:
self.endaction()
return
### cd command
'''
if cd ok: send "CDOD 'newabspath' 'promptends' \n"
else cd failed: send "CDFAIL path not exists\n"
'''
class cdaction(commandaction):
def __init__(self, cmdname, session, cmdline):
super(cdaction, self).__init__(cmdname, session, cmdline)
self.relpath = ''
def parsecmdline(self):
L.log('cdaction parsecmdline: ' + self.cmdline)
x = self.cmdline.split(' ')
if len(x) == 1:
self.relpath = BASEPATH
else:
self.relpath = x[1]
def startaction(self):
L.log('cd startaction: ' + self.relpath)
''' join currentpath with relpath '''
tmppath = os.path.join(self.session.currentpath, self.relpath)
abspath = os.path.abspath(tmppath)
if not os.path.exists(abspath):
self.session.outbuf.append(CDFAIL + ' ' + 'path not exists\n')
else:
self.session.currentpath = abspath
self.session.outbuf.append(CDOK + ' ' + self.session.currentpath + PROMPT_ENDS + '\n')
L.log('now currentpath' + self.session.currentpath)
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.handler_respcdresult
def handler_respcdresult(self):
L.log('cd handler_respcdresult: ' + self.session.outbuf[0])
if self.sendreponse() is not None:
L.log('sendreponse error ')
return ERR_RESP_ERR
if not self.session.outbuf:
self.endaction()
return
class lsaction(commandaction):
def __init__(self, cmdname, session, cmdline):
super(lsaction, self).__init__(cmdname, session, cmdline)
self.lspath = ''
self.isabspath = False
def parsecmdline(self):
L.log('lsaction parsecmdline: ' + self.cmdline)
x = self.cmdline.split(' ')
if len(x) != 1:
self.lspath = x[1]
if x[1][0] == '/':
self.isabspath = True
def startaction(self):
if self.isabspath == False:
self.lspath = os.path.join(self.session.currentpath, self.lspath)
self.lsabspath = os.path.abspath(self.lspath)
L.log('cd startaction: ' + self.lsabspath + str(self.isabspath))
try:
files = os.listdir(self.lsabspath)
for x in files:
self.session.outbuf.append(x + ' ')
except OSError as e:
self.session.outbuf.append('path error!')
self.session.outbuf.append('\n')
MUTIIO.unregister(self.session.sockfd, MUTIIO_READ)
MUTIIO.register(self.session.sockfd, MUTIIO_WRITE)
self.callback = self.handler_resplsresult
L.log('+++++startaction end++++')
def handler_resplsresult(self):
L.log('cd handler_resplsresult: ' + self.session.outbuf[0])
if self.sendreponse() is not None:
L.log('sendreponse error ')
return ERR_RESP_ERR
if not self.session.outbuf:
self.endaction()
return
COMMANDMAP = { 'put' : [CMD_PUT, putfileaction],
'get' : [CMD_GET, getfileaction],
'ls' : [CMD_LS, lsaction],
'cd' : [CMD_CD, cdaction] }
class session(object):
def __init__(self, sock, clientip, clientport):
self.clientip = clientip
self.clientport = clientport
self.sock = sock
self.sockfd = self.sock.fileno()
self.currentpath = BASEPATH
self.cmdact = None
self.cmdline = ''
self.cmddeque = collections.deque()
self.outbuf = collections.deque()
self.inbuf = collections.deque()
self.callback = None
def closesession(self):
MUTIIO.unregister(self.sockfd, MUTIIO_READ)
MUTIIO.unregister(self.sockfd, MUTIIO_WRITE)
MUTIIO.unregister(self.sockfd, MUTIIO_ERROR)
if self.sock is not None:
self.sock.close()
def regetcommand(self):
self.cmdact = None
self.cmdline = ''
self.cmddeque.clear()
self.outbuf.clear()
self.inbuf.clear()
MUTIIO.unregister(self.sockfd, MUTIIO_WRITE)
MUTIIO.unregister(self.sockfd, MUTIIO_ERROR)
MUTIIO.register(self.sockfd, MUTIIO_READ)
self.callback = self.handler_receivecmdline
def handler_respconnectok(self):
numbytes = sendtosock(self.sock, self.outbuf)
if numbytes <= 0:
L.log('handler_respconnectok sendtosock error')
return ERR_WRITE_ERR
if not self.outbuf:
MUTIIO.unregister(self.sockfd, MUTIIO_WRITE)
MUTIIO.register(self.sockfd, MUTIIO_READ)
self.callback = self.handler_receivecmdline
def respconnectok(self):
self.outbuf.append(BASEPATH + PROMPT_ENDS + '\n')
MUTIIO.register(self.sockfd, MUTIIO_WRITE)
MUTIIO.unregister(self.sockfd, MUTIIO_READ)
self.callback = self.handler_respconnectok
def handler_receivecmdline(self):
readlen = readfromsock(self.sock, self.cmddeque)
if readlen <= 0:
L.log(self.clientip + ' read command line error')
return ERR_READ_ERR
mergeprefix(self.cmddeque, 1000)
self.cmdline = self.cmddeque[0]
if self.cmdline.find('\n') != -1:
if len(self.cmdline) > 256:
self.recvcmdlinetolong()
L.log('command line too long\n')
return ERR_TOO_LONG
# earse \n
self.cmdline = self.cmdline[ : len(self.cmdline) - 1 ]
L.log('RECV new cmdline: ' + self.cmdline)
cmd = self.cmdline.split(' ')
cmdmap = COMMANDMAP.get(cmd[0])
print cmd[0]
if cmdmap is None:
L.log('Unknow command:(' + cmd[0] + ')')
return ERR_FMT_ERR
else:
self.cmdact = cmdmap[1](cmdmap[0], self, self.cmdline)
if self.cmdact.parsecmdline() is not None:
L.log('parse command line error: ' + self.cmdline)
self.regetcommand()
return ERR_FMT_ERR
self.callback = None
if self.cmdact.startaction() is not None:
L.log('start command action error: ' + self.cmdline)
self.regetcommand()
L.log('cmdtype :' + str(cmd))
else:
if len(self.cmdline) > 256:
self.recvcmdlinetolong()
L.log('command line too long\n')
return ERR_TOO_LONG
def sessioncontrol(self):
L.log('<<<<sessioncontrol start>>>>> ' + str(self.callback))
L.log('<<<<<commandaction start>>>>> ' + 'None' if self.cmdact is None else str(self.cmdact.callback))
if self.callback is not None:
ret = self.callback()
if ret is not None:
L.log(str(self.callback) + 'callback error, errno:' + str(ret))
return ERR_INTERNAL_ERR
else:
assert self.cmdact is not None
ret = self.cmdact.callback()
if ret is not None:
L.log('command action error: ' + self.cmdline + str(ret))
self.cmdact.endaction(successflag = False)
L.log('<<<<<sessioncontrol end>>>>>> ' + str(self.callback))
L.log('<<<<<commandaction start>>>>> ' + ('None' if self.cmdact is None else str(self.cmdact.callback)))
class selectio(object):
def __init__(self):
self.read_fds = set()
self.write_fds = set()
self.error_fds = set()
self.fd_sets = (self.read_fds, self.write_fds, self.error_fds)
def register(self, fd, events):
if fd in self.read_fds or fd in self.write_fds or fd in self.error_fds:
return
if events & MUTIIO_READ:
self.read_fds.add(fd)
if events & MUTIIO_WRITE:
self.write_fds.add(fd)
if events & MUTIIO_ERROR:
self.error_fds.add(fd)
def unregister(self, fd, events):
if events & MUTIIO_READ:
self.read_fds.discard(fd)
if events & MUTIIO_WRITE:
self.write_fds.discard(fd)
if events & MUTIIO_ERROR:
self.error_fds.discard(fd)
def poll(self, timeout = 0):
readable, writeable, errors = select.select( self.read_fds, self.write_fds, self.error_fds, timeout / 1000)
events = {} # {fd, READ | WRITE | ERROR}
for fd in readable:
events[fd] = events.get(fd, 0) | MUTIIO_READ
for fd in writeable:
events[fd] = events.get(fd, 0) | MUTIIO_WRITE
for fd in errors:
events[fd] = events.get(fd, 0) | MUTIIO_ERROR
return events.items()
class socketserver(object):
workingsession = {}
listensockets = []
def __init__(self, port = 19898):
self.port = port
def init(self):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
except socket.error as e:
return ERR_OPEN_ERR
sockaddr = ('', self.port)
sock.setblocking(0)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(sockaddr)
sock.listen(self.port)
socketserver.listensockets.append(sock)
def accepthandler(self, connection, address):
L.log('client[' + address[0] + ':' + str(address[1]) + ' ] accept')
newsess = session(connection, address[0], address[1])
socketserver.workingsession[connection.fileno()] = newsess
connection.setblocking(0)
connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
newsess.respconnectok()
L.log('client[' + address[0] + ':' + str(address[1]) + ' ] session inited')
def loop(self):
while True:
for sock in socketserver.listensockets:
while True:
try:
connection, address = sock.accept()
self.accepthandler(connection, address)
except Exception as e:
if geterrnofrome(e) in ERRNO_WOULDBLOCK:
break
if geterrnofrome(e) == errno.ECONNABORTED:
continue;
else:
raise
events = MUTIIO.poll(100) #ms
for event in events:
sess = socketserver.workingsession[event[0]]
print '++++++++++++++++++++++++++++++++++++++++++++++++'
if event[1] & MUTIIO_ERROR:
print 'get error'
L.log('ERROR event: ' + str(event[0]))
sess.closesession()
socketserver.workingsession.pop(event[0])
else:
if event[1] & MUTIIO_READ:
L.log('READ event: ' + str(event[0]))
else:
L.log('WRITE event: ' + str(event[0]))
if sess.sessioncontrol() is not None:
print 'error:' + sess.clientip + str(sess.clientport) + ': error'
sess.closesession()
socketserver.workingsession.pop(event[0])
print '------------------------------------------------'
if not socketserver.workingsession:
time.sleep(1)
MUTIIO = selectio()
if __name__ == '__main__':
if os.access(BASEPATH, os.R_OK | os.W_OK) == False:
L.log('ERROR: basepath: ' + BASEPATH + ' not correct!')
exit(0)
serverfile = socketserver()
if serverfile.init() is not None:
L.log('server init error!')
L.log('server init ok')
serverfile.loop()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。