2016年11月

[Project]聊天室-Python

目的:通过一个小项目练习与学习Python

服务端:

ChatServer类:
  attr:
    server:服务器Socket
    CONNECTIONS:包含所有已连接的Client Socket与Server Scoket
    host、post 主机、端口
    RCVBUF:接受缓冲区大小
  methods:
    broadcast_data:每接受一次信息,将信息发送给其它所有客户端
    run:通过select实现非阻塞监听

客户端:

Client类:
  attr:
    s:Client Socket
    host_name、ip: 本机名、本机ip
    des_host、des_port:服务器地址与端口
  methos:
    hint:刷新标准输出缓冲区
    run:监听stdin与Client Socket

Tips:

   客户端无法再Windows下使用
   "On Windows, the underlying select() function is provided by the WinSock library, and does not handle file descriptors that don’t originate from WinSock" ---Python Doucumentation

   服务端运行在远程服务器时以服务器地址做参数构造Server

GUI编程

1.通过修改text['State']='disabled'可以使文本域不可被编辑。同样当自己需要插入时需要先改变State为normal
2.如何使Scrollbar始终指向文本域底部?通过text.see(END)可实现。参见说明:
QQ截图20161205122250.png

遇到问题

  1. 点击'发送时',提示超时,发送失败。

  2. 在Ubuntu环境下测试时,发现每次连接后发送消息后会自动断开连接。
    排除客户端错误,在服务端代码对应位置插入异常输出,提示str类型异常,发现
    self.broadcast_data(set(self.CONNECTIONS)-{sock},("\r" + '<' + str(sock.getpeername()) + '> ' +data).encode('ascii'))
    data忘记做了类型转化,data改为data.decode('ascii')

  3. 回到第一个问题,发现每次提示发送超市关闭GUI时,服务端输出连接成功。原来root.mainloop()循环会阻塞run中监听循环.在点击发送时实际上并未连接至服务器.
      解决方案:将run放入另一个线程中便可解决。

  4. 使用os_exit()方法退出进程,在测试时发现服务端报错

    "\rClient {} is offline\n".format(sock.getpeername()))
    OSError: [Errno 107] Transport endpoint is not connected

    猜测os_exit()使得后面代码没有被正常执行,客户端已关闭socket,服务端调用socket方法出现错误。
    解决方法:将os._exit()去掉,使得服务端能正常关闭socket,然后通过chat.run线程退出进程。

下一步:

  1. 补全Save功能
  2. 处理非正常退出进程

更新0315

  1. 已补全Save功能
  2. 已处理非正常退出问题
  3. json打包发送数据
    代码见https://github.com/starsD/pyChatroom

Python解九连环问题

设九连环从右至左每个环编号为1,2,3,……,9
每个环只有两种状态up,down(即在环上与不在环上)

解九连环基本操作:

1.若要卸下一个环n(state[n]=up ->state[n]=down):(n>1)
必须先使state[n-1]=up,state[n-2]state[n-3]----、state[0]=down
2.若要装上一个环n(state[n]=down ->state[n]=up):(n>1)
必须先使state[n-1]=up,state[n-2]state[n-3]----、state[0]=down
3.n=1的环永远可以自由改变状态

具体思路:
假设九连环的前七个环已解,则当前九连环状态为:


 9   8   7    6    5    4   3    2    1
U  U  D  D  D  D  D  D  D


故只需卸下第九个环(一步完成),然后卸下第八个环(运用三个规则递归调用)

则总体基本流程为:

solve(n)
    solve(n-2)
    down(n)
    ddown(n-1)

具体代码如下:

    i = 0
    
    def solvejlh(n):
        if n == 1:
            ddown(1)
            return
        elif n == 2:
            ddown(2)
            ddown(1)
            return
        solvejlh(n - 2)
        ddown(n)
        down(n-1)
    
    
    def up(n):
        if n == 1:
            dup(n)
        else:
            up(n - 1)
            dup(n)
            down(n - 1)
    
    
    def down(n):
        if n == 1:
            ddown(n)
        else:
            up(n - 1)
            ddown(n)
            down(n - 1)
    
    
    def dup(n):
        global i
        print('No.{} up'.format(n))
        i += 1
    
    
    def ddown(n,):
        global i
        print('No.{} down'.format(n))
        i += 1
    
    solvejlh(9)
    print(i)