python全双工聊天窗口编程学习之旅

OK,既然可以随时更新,那我就用它来记录我的学习历程啦!
2017/7/3
这个是一次学习的经历...
tkinter 中的frame容器写的那个界面我是直接在网上搜了一个范本...但是frame不会自动显示最末尾一行的内容...输入了之后超出部分无法自动显示...额解决了此问题的小伙伴可以留言讨论哇


服务器端demo

# -*- coding: utf-8 -*-
import socket
HOST = ''
PORT = 10022
     
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'connect successful'
while 1:
    data = conn.recv(1024).decode('utf-8')
    if data=="":
        conn.close()
        print 'connect successful'
    else:
        print data

客户端demo
# -*- coding: utf-8 -*-
import Tkinter as tk
import threading
import datetime
import time
import socket

def sendmessage(*func):
  #在聊天内容上方加一行 显示发送人及发送时间
  msgcontent = '我:' + time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()) + '\n '
  text_msglist,text_msg = func
  text_msglist.insert(tk.END, msgcontent, 'green')
  text_msglist.insert(tk.END, text_msg.get('0.0', tk.END))
  s.sendall(text_msg.get('0.0', tk.END).encode('utf-8'))
  text_msg.delete('0.0', tk.END)


def buttonClick():
    password='chenhao'
    if entry.get()==password:
        show_label.config(text='correct')
        password_window.destroy()
        root = tk.Tk()
        root.title(u'与xxx聊天中')
        #创建几个frame作为容器
        frame_left_top   = tk.Frame(width=380, height=270, bg='white')
        frame_left_center  = tk.Frame(width=380, height=100, bg='white')
        frame_left_bottom  = tk.Frame(width=380, height=25)
        frame_right     = tk.Frame(width=170, height=400, bg='white')
        ##创建需要的几个元素
        text_msglist    = tk.Text(frame_left_top)
        text_msg      = tk.Text(frame_left_center)
        button_sendmsg   = tk.Button(frame_left_bottom, text='发送',command=lambda:sendmessage(text_msglist,text_msg))
        #创建一个绿色的tag
        text_msglist.tag_config('green', foreground='#008B00')
        #使用grid设置各个容器位置
        frame_left_top.grid(row=0, column=0, padx=2, pady=5)
        frame_left_center.grid(row=1, column=0, padx=2, pady=5)
        frame_left_bottom.grid(row=2, column=0)
        frame_right.grid(row=0, column=1, rowspan=3, padx=4, pady=5)
        frame_left_top.grid_propagate(0)
        frame_left_center.grid_propagate(0)
        frame_left_bottom.grid_propagate(0)
        #把元素填充进frame
        text_msglist.grid()
        text_msg.grid()
        button_sendmsg.grid(sticky='e')
    else:
        show_label.config(text='error')



def buttonClick2():
    print "ok"

def main():
    password_window.mainloop()
t0 = threading.Thread(target=main)


if __name__ == '__main__':
    HOST = 'localhost'
    PORT = 10022

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    print 'connect successful'
    
    password_window = tk.Tk()  
    button=tk.Button(password_window,text="确认",command = buttonClick)
    entry=tk.Entry(password_window,show='*')
    label=tk.Label(password_window,text='Password:')
    show_label=tk.Label(password_window)
    #slider=tk.Scale(password_window,from_=0,to=100)
    label.pack()
    entry.pack()
    button.pack()
    show_label.pack()

    t0.setDaemon(True)
    t0.start()

啊...说一下目前的进度,以及已解决的问题恩...演示版本只能实现由客户端单向发送给服务器端以自娱自乐...
这个自娱自乐当中涉及到了代码编码格式转换问题
decode('utf-8')是将utf-8格式的代码自动转换成unicode。print()函数会自动识将Unicode转换成内在需要的编码格式
encode('utf-8')是将其他格式的代码转换成utf-8码,以便将字符串传递给某些内置函数
如上述demo中就需要
s.sendall(text_msg.get('0.0', tk.END).encode('utf-8'))
这样字符串经过处理之后,socket模块中的sendall()函数才能处理获得的数据,否则报错
额...这里面还有一个密码登录界面...
输入密码正确后,会关闭此页面并跳入另一个新界面。这其中mainloop()函数。
通过实验发现...一个程序只允许一个mainlooop()函数的存在。然而,第二个界面是通过第一个界面生成的,所以mainloop()函数先于第二个界面生成。我们知道mainloop作为一个循环是空占cpu的...也就是说在主任务线上的后续操作都被卡死了...所以这里我引入了一个线程,将mainloop丢到一个线程中去,这样大家就能愉快的玩耍啦!
额...涉及线程,我把最简单的事例线程也贴上来啦,大家直接用就好了


#coding=utf-8
import threading
from time import ctime,sleep

def music(func):
    for i in range(2):
        print "I was listening to %s. %s" %(func,ctime())
        sleep(1)

def move(func):
    for i in range(2):
        print "I was at the %s! %s" %(func,ctime())
        sleep(5)

threads = []
t0 = threading.Thread(target=music,args=("ok",))
threads.append(t0)
t1 = threading.Thread(target=move,args=("haha",))
threads.append(t1)


if __name__ == '__main__':
    for t in threads:
        t.setDaemon(True)
        t.start()


PS:仔细读过客户端代码的盆友可能发现,我的mainloop()是挂在password_window下的,而我紧接着明明将password_window给destory了,为什么我的后续窗口可以正常运行呢?...额,我猜是系统保留了资源供后续使用吧...谁知道呢...我嫌多开一个空的主窗口太冗余了,还要去查怎样隐藏窗口...就酱了啊...(;′⌒`)关于为啥destory了的窗口mainloop()还能正常使用...欢迎大神解惑...
额好像离全双工还远着呢,我目前的想法是做一个  客户端——服务器端——客户端  这样子的由服务器点对点转发消息的聊天机制。想法就是这样辣,我去慢慢拼积木咯
想直接跑代码的同学请先开服务器端,然后再开客户端。不然报错了,我不接受质疑╭(╯^╰)╮

更新于2017 7 12  22:46


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值