程序需要一步步改进,解决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\nMem:        3992388     1881176      579816      390708     1531396     1436396\nSwap:       3998716           0     3998716\n'
>>> 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\nudev             1976928        0   1976928   0% /dev\ntmpfs             399240     6432    392808   2% /run\n/dev/sda5       49082176 13552096  33013756  30% /\ntmpfs            1996192    24840   1971352   2% /dev/shm\ntmpfs               5120        4      5116   1% /run/lock\ntmpfs            1996192        0   1996192   0% /sys/fs/cgroup\n/dev/sda6         967320    56100    844868   7% /boot\ntmpfs             399240       80    399160   1% /run/user/1000')
>>> cm=commands.getstatusoutput('df')
>>> cm[0]
0
>>> cm[1]
'Filesystem     1K-blocks     Used Available Use% Mounted on\nudev             1976928        0   1976928   0% /dev\ntmpfs             399240     6432    392808   2% /run\n/dev/sda5       49082176 13552096  33013756  30% /\ntmpfs            1996192    24840   1971352   2% /dev/shm\ntmpfs               5120        4      5116   1% /run/lock\ntmpfs            1996192        0   1996192   0% /sys/fs/cgroup\n/dev/sda6         967320    56100    844868   7% /boot\ntmpfs             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-program的更多相关文章

  1. Release Python Program as exe

    py2exe 可以用来将python program 以exe的形式发布. 安装py2exe 对于python 3.x pip install py2exe 可以直接安装 对于python 2.7, ...

  2. java exec python program

    I find three methods, the first is using jython, the module of jython can transform the type of data ...

  3. My first Python program(附增加清屏方法)

    #TempConvert.py TempStr = input("请输入带有符号的温度值:") if TempStr[-1] in ['F', 'f']: C = (eval(Te ...

  4. Day1 -Python program

    采用python 3.5 用PyCharm编译 第一串代码 print ("hello,world!") 练习1 输入一个用户名和密码,如果输入正确,就欢迎登陆,否则就显示错误. ...

  5. Writing an Hadoop MapReduce Program in Python

    In this tutorial I will describe how to write a simpleMapReduce program for Hadoop in thePython prog ...

  6. 用Python语言写Hadoop MapReduce程序Writing an Hadoop MapReduce Program in Python

    In this tutorial I will describe how to write a simple MapReduce program for Hadoop in the Python pr ...

  7. Python列表和元组

    Python是没有数组的概念,但是和数组比较相近的概念是列表和元素. 下面两个例子展示列表和元组. # coding=utf-8 # 元组 students = ('小明', '小黄', '小李', ...

  8. python与shell的3种交互方式介绍

    [目录] 1.os.system(cmd) 2.os.popen(cmd) 3.利用subprocess模块 4.subprocessor模块进阶 [概述] 考虑这样一个问题,有hello.py脚本, ...

  9. python学习笔记系列----(七)类

    7.1 python类和相关术语的简介 Python 通过最小的新语法和语义在语言中实现了类. 它是 C++ 或者 Modula-3 语言中类机制的混合.类的大多数重要特性都被完整的保留下来:类继承机 ...

  10. 多线程的学习与python实现

    学习了进程与线程,现对自己的学习进行记录. 目录: 一.进程与线程的概念,以及联系与区别 二.多线程 三.python中多线程的应用 四.python实例 五.参考文献 一.进程与线程的概念.以及联系 ...

随机推荐

  1. sql转db,后台坑货

    打开 创建一个db文件然后点击文件--新建---Sqlite 导入空db成功后点击左侧栏 点击表 点击右上角+号把sql文件的语句复制粘贴到 然后点击运行,运行完成后保存ok

  2. “用户、组或角色'XXX'在当前数据库中已存在”问题

    一般在还原数据库后,给这个数据库添加一个登录名时出现. 例如数据库备份文件中已经包含了用户abc,现在还原了数据库,然后发现现有数据库中没有abc这个用户,想要新建一个abc用户,作为该数据库的own ...

  3. 用户、角色、权限三者多对多用hibernate的一对多注解配置

    用户.角色.权限三者多对多用hibernate的一对多注解配置 //权限表@Table(name = "p")public class P { @Id @GeneratedValu ...

  4. WebGL中添加天空盒的两种方法

    天空盒 的添加可以让模型所在的场景非常漂亮,而其原理也是非常简单的,相信看完下面代码就可以明白了. 说到天空盒的两种方法,倒不如说是两种写法,分别用了纹理加载的两个方法:loadTexture和loa ...

  5. 字符串strcpy

    strcpy函数的表达方式: //把一个char组成的字符串循环右移n个,如:“abcdefghi",n=2,移动后"hiabcdefgh" #include <i ...

  6. Visual C# 代码段

    代码段是现成的代码段,您可以快速将其插入到您的代码中. 例如,for 代码段创建一个空的 for 循环. 有些代码段为外侧代码段,这些代码段允许您先选择代码行,然后选择要并入选定代码行的代码段. 例如 ...

  7. No.1 CAS 之LDAP认证服务端集群配置

    建档日期:   2016/08/31 最后修改日期:   2016/12/09   1 概述 本文描述了CAS单点登录服务端配置的大概流程,希望抛砖引玉,帮助你完成CAS服务端的配置. 本文采用apa ...

  8. [转]python问题:IndentationError:expected an indented block错误解决

    分类: python学习笔记2012-07-07 17:59 28433人阅读 评论(4) 收藏 举报 python语言 原文地址:http://hi.baidu.com/delinx/item/17 ...

  9. Activity packagename has leaked window android.widget.PopupWindow$PopupDecorView{4f92660 V.E...... .......D 0,0-455,600} that was originally added here

    原因是在销毁Activity时,Activity中的popupwindow还处于显示状态. 解决方法是重写Activity的onDestroy()方法,在Activity销毁前调用popupWindo ...

  10. linux中模块的构建,传参,和printk函数的简单使用

    静态编译,动态加载应用想访问内核需要通过系统调用 驱动:1.模块(打包,加入内核)2.内核机制3.操作硬件 在Kconfig里面配置menuconfig的时候,不同的类型会在图形化界面的终端显示不用的 ...