Python聊天室程序-----美化

对前边的工作Python聊天室程序Python聊天室程序---客户端的改进的进一步更新。

客户端和服务器之间的消息传递格式为

struct.Struct('I 50s 100s')
‘I’带表消息类型,在Struct中表示整型数据;‘50s’代表发送消息的用户名,'s'代表字符,用户名最多为50个字符;‘100s’代表所发送的消息,最多为100个字符。

如果需要对发送信息的字体进行一些设置,或者想发送一些表情,可以在消息格式中添加一些新的内容即可。

struct的更详细的信息可以查询《Python标准库》一书。另外json据说也能做相关工作,这个以后再进行尝试。

在客户端里,从接收到的内容中提取具体信息方法为:

data = self.sock.recv(200)
s = struct.Struct('I 50s 100s')
unpacked_data = s.unpack(data)

extra = b'\x00'

infoType = unpacked_data[0]
username = (unpacked_data[1].decode()).strip(extra.decode())
info = (unpacked_data[2].decode()).strip(extra.decode())

extra是客户端接收到的空字符,比如用户名有50个字符,我们只占用了30个,剩下的20个空的。

unpacked_data是二进制数据,所以转换为字符串时需要使用decode()。strip(rm)是将字符串开头和结尾的rm字符都去除掉。

infoType,username,info就是从提取出的消息类型,用户名,信息。

下面是客户端的示意图,略丑,勿拍。

客户端代码:

# Filename: socket_client.py    
from tkinter import *    
import Pmw    
import threading    
import socket
import struct

MESSAGE             = 1
NEWPARTICIPANT      = 2
PARTICIPANTLEFT     = 3
REFUSE              = 4

    
class ChatFrame:  
      
    def __init__(self, master=None):  
          
        # Create a TCP/IP socket And connect the socket to the port where    
        # the server is listening    
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    
        self.server_address = ('localhost', 10000)    
        print (sys.stderr, 'connecting to %s port %s' % self.server_address)      
        self.sock.connect(self.server_address)

        # 将主机hostname当做用户名
        self.username = socket.gethostname()
          
        # Client GUI  
        self.master = master  
        ## Base frame for the widgets  
        self.frame = Frame(master)

        # 界面左区域的Frame
        self.leftFrame = Frame(self.frame)
        ## Message Display widget  
        self.textDisplay = Text(self.leftFrame,height=20,width=40)
        ## Text Input widget  
        self.textInput = Text(self.leftFrame,height=10,width=40)
        ## 发送消息按钮
        self.sendBtn = Button(self.leftFrame, text='发送')  
        self.sendBtn.bind('<Button-1>', self.sendMsg)

        ## 界面右区域的Frame
        self.rightFrame = Frame(self.frame)
        ## 在线人数标签
        self.onlineNumLabel = Label(self.rightFrame,text='在线用户:x人',bg='gray')
        ## 在线用户列表
        self.userList = Listbox(self.rightFrame)
        ## 退出按钮
        self.exitBtn = Button(self.rightFrame, text='退出')
         
        # 接受消息 
        receiveThread = threading.Thread(name='waitForMSG', target=self.receiveMsg)  
        receiveThread.start()
        
        # 上线通知
        self.sendInfo(NEWPARTICIPANT)

    # 发送消息
    def sendInfo(self,infoType):
        # 消息类型为新用户上线
        if infoType == NEWPARTICIPANT:
            info = 'online\n'
            ## 信息格式为(消息类型,用户名,信息)
            values = (NEWPARTICIPANT,self.username.encode(),info.encode())
            ## 用户名最多为50个字符,信息最多为100个字符
            packer = struct.Struct('I 50s 100s')
            packed_data = packer.pack(*values)
            
        # 消息类型为文本输入信息
        elif infoType == MESSAGE:
            info = self.textInput.get(1.0,END) 
            print('sending message is %s' % info)
            ## 信息格式为(消息类型,用户名,信息)
            values = (MESSAGE,self.username.encode(),info.encode())
            packer = struct.Struct('I 50s 100s')
            packed_data = packer.pack(*values)
            self.textInput.delete(1.0,END)
            
        elif infoType == PARTICIPANTLEFT:
            pass

        self.sock.sendall(packed_data)

    # 接受消息并处理
    def receiveMsg(self):    
        while True:    
            data = self.sock.recv(200)
            s = struct.Struct('I 50s 100s')
            unpacked_data = s.unpack(data)

            extra = b'\x00'
            
            ## 从接受到的信息中提取具体的信息
            infoType = unpacked_data[0]
            username = (unpacked_data[1].decode()).strip(extra.decode())
            info = (unpacked_data[2].decode()).strip(extra.decode())
            
            print('Infomation Type is')
            print(infoType)
            print('client received "%s"' % info)
            
            if infoType == MESSAGE:
                message = username + ':' + info
                self.textDisplay.insert(END, message)

            elif infoType == NEWPARTICIPANT:
                message = username + 'online\n'
                self.textDisplay.insert(END, message)
                self.newParticipant(username)

    # 发送消息按钮事件处理
    def sendMsg(self,event):
        self.sendInfo(MESSAGE)

    # 处理新用户加入
    def newParticipant(self,username):
        self.userList.insert(END,username)

 
if __name__ == '__main__':  
    root = Tk()
    root.title('Chat Room')  
    tt = ChatFrame(root)

    # left frame
    tt.textDisplay.pack(fill=X,expand=1,padx=3,pady=3)
    tt.textInput.pack(fill=X,expand=1,padx=3,pady=3)
    tt.sendBtn.pack(side=LEFT)
    tt.leftFrame.pack(side=LEFT,fill=BOTH,padx=3,pady=3,expand=1)  
    # right frame
    tt.onlineNumLabel.pack(fill=X)
    tt.userList.pack(fill=Y,expand=1)
    tt.exitBtn.pack(side=RIGHT,anchor=CENTER)
    tt.rightFrame.pack(side=LEFT,fill=BOTH,pady=3)
    
    tt.frame.pack(fill=BOTH, padx=3, pady=3,expand=1)  
    root.mainloop()
服务器代码:

# Filename: socketServer.py  
  
import socket  
import sys
import struct
  
# Create a TCP/IP socket  
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
  
# Bind the socket to the port  
server_address = ('localhost', 10000)  
print (sys.stderr, 'starting up on %s port %s' % server_address)  
sock.bind(server_address)  
  
# Listen for incoming connections  
sock.listen(1)

# 消息格式
unpacker = struct.Struct('I 50s 100s')
  
while True:  
    # Wait for a connection  
    print (sys.stderr, 'waiting for a connection')  
    connection, client_address = sock.accept()  
  
    try:  
        print (sys.stderr, 'connection from', client_address)  
  
        # Receive the data in small chunks and retransmit it  
        while True:  
            data = connection.recv(1000)  
            print (sys.stderr, 'received "%s"' % data)  
            if data:  
                print (sys.stderr, 'sending data back to the client')  
                connection.sendall(data)  
            else:  
                print (sys.stderr, 'no data from', client_address)  
                break  
    finally:  
        # Clean up the connection  
        connection.close()


  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值