• python-program


    程序需要一步步改进,解决bug,尽量从源头判断,并给出处理措施。

    1.客户端执行一次,程序就退出,

    2.客户端空值,错误命令,程序会死掉

    3.收发缓冲区大小,即recv(1024)的问题,如果收一个100M的文件就又是问题

    4.多线程问题,同时能处理多个客户端的请求问题

    第一次创建了原型

    socket单进程服务器
    
    [root@localhost ~]# cat echoserver.py
    import socket
    host='192.168.10.101'
    port=9657
    s=socket.socket()
    s.bind((host,port))
    s.listen(1)
    conn,addr=s.accept()
    print 'connected by',addr
    while 1:
      data=conn.recv(20)
      if not data:break
      conn.sendall(data)
    s.close()
    
    python echoserver.py
    
    
    fgy@fgy-QTH6:~/Documents/python$ cat echoclient.py
    import socket
    host='192.168.10.101'
    port=9657
    s=socket.socket()
    s.connect((host,port))
    s.sendall('hello,world')
    data=s.recv(1024)
    print 'received',repr(data)
    s.close()
    
    python echoclient.py

    第二次修改,加入了循环,并持续接收并返回数据

    [root@mysql python]# cat echoserver.py
    import socket,time,os
    host='192.168.10.114'
    port=9657
    s=socket.socket()
    s.bind((host,port))
    s.listen(1)
    while 1:
      conn,addr=s.accept()
      while 1:
      	print 'connected by',addr
      	print time.ctime()
      	data=conn.recv(1024)
      	if not data:break
    	result=os.popen(data).read()
      	conn.sendall(result)
    s.close()
    
    
    
    fgy@fgy-QTH6:~/Documents/python$ cat echoclient.py
    import socket,time,os
    host='192.168.10.114'
    port=9657
    s=socket.socket()
    s.connect((host,port))
    while 1:
    	  cmd=raw_input('your cmd: ').strip()
    	  s.sendall(cmd)
    	  data=s.recv(1024)
    	  print time.ctime()
    	  print data
    #	  time.sleep(5)
    s.close()


    os.system(df)不能保存,所以需要用下面的这个
    aa=os.popen(df).read()

        system(...)
            system(command) -> exit_status
            Execute the command (a string) in a subshell.

        popen(...)
            popen(command [, mode='r' [, bufsize]]) -> pipe        
            Open a pipe to/from a command returning a file object.

    >>> ab=os.popen('free')
    >>> ab.read()
    '              total        used        free      shared  buff/cache   available Mem:        3992388     1881176      579816      390708     1531396     1436396 Swap:       3998716           0     3998716 '
    >>> os.system('free')
                  total        used        free      shared  buff/cache   available
    Mem:        3992388     1879964      581108      390580     1531316     1437732
    Swap:       3998716           0     3998716
    0
    >>> ac=os.system('free')
                  total        used        free      shared  buff/cache   available
    Mem:        3992388     1880560      576808      394256     1535020     1433448
    Swap:       3998716           0     3998716

    第三次,客户端输空值,错误命令的解决办法

    针对客户端空值问题

    在客户端判断或者在服务器端判断 空值不发过去(在客户端判断),加入下面着色一行就行了
    while 1:
          cmd=raw_input('your cmd: ').strip()
         if len(cmd) == 0:continue
          s.sendall(cmd)
          data=s.recv(1024)

    错误命令问题分析
    在server端,发现下面这个语句不好使
    #    result=os.popen(data).read()
    所以就换成下面这个模块的一个方法,非常方便简单。
    >>> import commands
    >>> commands.getstatusoutput('df')
    (0, 'Filesystem     1K-blocks     Used Available Use% Mounted on udev             1976928        0   1976928   0% /dev tmpfs             399240     6432    392808   2% /run /dev/sda5       49082176 13552096  33013756  30% / tmpfs            1996192    24840   1971352   2% /dev/shm tmpfs               5120        4      5116   1% /run/lock tmpfs            1996192        0   1996192   0% /sys/fs/cgroup /dev/sda6         967320    56100    844868   7% /boot tmpfs             399240       80    399160   1% /run/user/1000')
    >>> cm=commands.getstatusoutput('df')
    >>> cm[0]
    0
    >>> cm[1]
    'Filesystem     1K-blocks     Used Available Use% Mounted on udev             1976928        0   1976928   0% /dev tmpfs             399240     6432    392808   2% /run /dev/sda5       49082176 13552096  33013756  30% / tmpfs            1996192    24840   1971352   2% /dev/shm tmpfs               5120        4      5116   1% /run/lock tmpfs            1996192        0   1996192   0% /sys/fs/cgroup /dev/sda6         967320    56100    844868   7% /boot tmpfs             399240       80    399160   1% /run/user/1000'
    >>> cm=commands.getstatusoutput('dfef')
    >>> cm[0]
    32512
    >>> cm[1]
    'sh: 1: dfef: not found'


    >>> status,result=commands.getstatusoutput('dfef')
    >>> status
    32512
    >>> result
    'sh: 1: dfef: not found'
    >>>


    针对错误命令问题,所以服务端修改为
          data=conn.recv(1024)
          if not data:break
    #     result=os.popen(data).read()
         status,result=commands.getstatusoutput(data)
          conn.sendall(result)



    针对客户端如果创建文件或目录的话,客户端程序会死掉,所以服务端修改为
    加入以下着色部分就可以了
          if not data:break
    #     result=os.popen(data).read()
         status,result=commands.getstatusoutput(data)
         if len(result) != 0:
              conn.sendall(result)
         else:
             conn.sendall('DONE')


    commands.getstatusoutput(data)解决了一些问题,
    但是不能执行诸如vmstat 1,top,等有持续输出的命令。
    所以还需要考虑另外一些方法

    最后成型的程序

    fgy@fgy-QTH6:~/Documents/python$ cat echoclient.py
    import socket,time,os,commands
    host='192.168.10.114'
    port=9657
    s=socket.socket()
    s.connect((host,port))
    while 1:
        cmd=raw_input('your cmd: ').strip()
        if len(cmd) == 0:continue
        s.sendall(cmd)
        data=s.recv(1024)
        print time.ctime()
        print data
    #    time.sleep(5)
    s.close()
    
    
    [root@mysql python]# cat echoserver.py
    import socket,time,os,commands
    host='192.168.10.114'
    port=9657
    s=socket.socket()
    s.bind((host,port))
    s.listen(1)
    while 1:
      conn,addr=s.accept()
      while 1:
          print 'connected by',addr
          print time.ctime()
          data=conn.recv(1024)
          if not data:break
    #    result=os.popen(data).read()
        status,result=commands.getstatusoutput(data)
        if len(result) != 0:
              conn.sendall(result)
        else:
            conn.sendall('done')
    s.close()

     第四次,循环不等于多线程,与并发也不是一回事,所以需要修改为同时支持多个连接

    python有socket模块,还有一个SocketServer多线程模块,有了这个就不需要自己去管理多线程了
    
    
    RequestHandler.setup()
    RequestHandler.handler()
    BaseServer.serve_forever(poll-interval=0.5)
    
    
    重新改写的服务端,还用上面的客户端。但虽然可以允许多个连接过来,但只能交互一次,随后客户端就死掉了,不能循环交互
    因为服务端只做了三件事,打印两行,再将数据以大写方式返回给客户端,只能进行一次
    所以还需要自己再写循环来实现多次交互。
    import SocketServer class Mytcp(SocketServer.BaseRequestHandler): def handle(self): self.data=self.request.recv(1024).strip() print "{} wrote:".format(self.client_address[0]) print self.data self.request.sendall(self.data.upper()) if __name__=="__main__": host,port="192.168.10.114",9657 server=SocketServer.ThreadingTCPServer((host,port),Mytcp) server.serve_forever() __main__的用途是 当自行调用时,即在命令行主动启动执行的话,才会去执行if下面的内容 如果被当作一个python模块导入的话,不会执行if里的内容。


    所以重新修改一下服务端为下面的内容,如果不加if 语句的话,在客户端都退出后,服务器会死循环,搞死服务器。
    def handle(self):
        while 1:
            self.data=self.request.recv(1024).strip()
            print "{} wrote:".format(self.client_address[0])
            print self.data
            if not self.data:break
            self.request.sendall(self.data.upper())

    第五次修改,文件的传输

    下面的客服程序实现了文件下载,与2个并发连接服务器,下载同一个大小为2G的文件,会造成下面的内存报错,并且报错的那条连接下载不成功,如果大小为1G的话,则成功。
    原来报错与内存有关系,服务器内存为2G,增加到4G后,3个并发成功。
    192.168.10.116 wrote:
    get ub
    192.168.10.115 wrote:
    get ub
    ----------------------------------------
    Exception happened during processing of request from ('192.168.10.115', 55444)
    Traceback (most recent call last):
      File "/usr/lib64/python2.7/SocketServer.py", line 593, in process_request_thread
        self.finish_request(request, client_address)
      File "/usr/lib64/python2.7/SocketServer.py", line 334, in finish_request
        self.RequestHandlerClass(request, client_address, self)
      File "/usr/lib64/python2.7/SocketServer.py", line 649, in __init__
        self.handle()
      File "sock.py", line 14, in handle
        self.request.sendall(ff.read())
    MemoryError

    然后需要做的就是上传文件与认证


    [root@mysql python]# cat sock.py import SocketServer,commands,time class Mytcp(SocketServer.BaseRequestHandler): def handle(self): while 1: self.data=self.request.recv(1024).strip() print "{} wrote:".format(self.client_address[0]) print self.data if not self.data: print "client is dead %s" %self.client_address[0] break input=self.data.split() if input[0] =='get': with open(input[1],'rb') as ff: self.request.sendall(ff.read()) time.sleep(2) self.request.send('file transfer finished') continue status,result=commands.getstatusoutput(self.data) if len(result) != 0: self.request.sendall(result) else: self.request.sendall('done') #self.request.sendall(self.data.upper()) if __name__=="__main__": host,port="192.168.10.114",9657 server=SocketServer.ThreadingTCPServer((host,port),Mytcp) server.serve_forever() fgy@fgy-QTH6:~/Documents/python/ff$ cat echoclient.py import socket,time,os,commands host='192.168.10.114' port=9657 s=socket.socket() s.connect((host,port)) while 1: cmd=raw_input('your cmd: ').strip() if len(cmd) == 0:continue s.sendall(cmd) if cmd.split()[0] == 'get': with open(cmd.split()[1],'wb') as w : while 1: data=s.recv(1024) if data=="file transfer finished":break w.write(data) continue else: print time.ctime() print s.recv(1024) s.close()
  • 相关阅读:
    开博的缘由
    听了一节公开课 课后感
    python中的函数、变量和递归函数
    迭代器和生成器
    字符串的格式化
    html和htm的区别
    基本数据类型总结
    数据类型-----集合
    基础测试题(字符串、列表、元组、字典)
    基本数据类型-----字典(Dictionary)
  • 原文地址:https://www.cnblogs.com/createyuan/p/5742092.html
Copyright © 2020-2023  润新知