基于TCP协议网上聊天程序(python)带界面

基于TCP协议网上聊天程序(python)带界面

1 设计目标
基于TCP协议网上聊天程序
实现一简单的聊天程序实现网上聊天,包括服务器和客户端。
(1)支持多人聊天;
(2)客户端具有图形化用户界面;
(3)客户端之间具有群发和私聊的功能。

2 用python实现的TCP通信模型
TCP客户端:通过connect((ip, port))来请求连接,send()进行发送消息,recv()进行接受消息。
TCP服务器: 通过bind((ip, port))绑定ip和端口,ip不写则代表默认本机所有地址,listen()控制客服端的连接数量,accept()等待阻塞,一直到客户端的到来,recv()接受消息,send()发送消息。
具体过程如下:
在这里插入图片描述

3 实现了简单的TCP聊天程序实现网上聊天,通过对服务器和端口的输入,可以在不同的主机上运行并将其服务器与客户端连接,用多线程可以支持多人同时聊天,客户端具有图形化用户界面,客户端之间具有群发和私聊的功能并且能知道实时的用户在线名单,界面显示效果良好,整体完成效果良好。

客户端client:

# -*- coding: utf-8 -*-
"""
Created on Tue May 12 23:49:20 2020

@author: LENOVO
"""
import tkinter
import socket
import threading
import time

win = tkinter.Tk()
win.title("客户端")
win.geometry("400x300+300+200")
ck = None


def getInfo():
    while True:
        data = ck.recv(1024)#用于接受服务其发送的信息
        #接收消息时同步获取系统时间并显示在消息显示框上
        text.insert(tkinter.INSERT, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n')
        text.insert(tkinter.INSERT, data.decode("utf-8"))


def connectServer():
    global ck#全局
    ipStr = eip.get()
    portStr = eport.get()
    userStr = euser.get()
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#socked所准守ipv4相关协议
    client.connect((ipStr, int(portStr)))#连接服务器
    client.send(userStr.encode("utf-8"))#将自己的登录名发送给服务器,函数会附带自己的IP信息
    ck = client
    t = threading.Thread(target=getInfo)
    t.start()


def sendMail():
    friend = None
    friend = efriend.get()
    sendStr = esend.get()
    #自己发出的消息服务器不会重发会给自己,所以在客户端定义界面显示自己发送的消息
    if friend !="":
       text.insert(tkinter.INSERT, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'我对'+friend+'说:' + sendStr+'\n')
    else:
        text.insert(tkinter.INSERT, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + '\n'+'我(群发)说:' + sendStr+'\n')
    #将消息发给服务器,添加“:”分割是要方便服务器端用正则表达式分出要发送的用户名和要发送的消息
    sendStr = friend + ":" + sendStr+"\n"
    ck.send(sendStr.encode("utf-8"))
    
def Exit():
    #我在服务器端定义了接收到“exit”就判定该用户下线,并删掉该用户的资料
    sendStr = "exit" + ":" + ""
    ck.send(sendStr.encode("utf-8"))
    text.insert(tkinter.INSERT, "您已下线,如需接收信息请重新登录。\n")


#下面是界面
labelUse = tkinter.Label(win, text="userName").grid(row=0, column=0)
euser = tkinter.Variable()
entryUser = tkinter.Entry(win, textvariable=euser).grid(row=0, column=1)

labelIp = tkinter.Label(win, text="服务器ip").grid(row=1, column=0)
eip = tkinter.Variable()
entryIp = tkinter.Entry(win, textvariable=eip).grid(row=1, column=1)

labelPort = tkinter.Label(win, text="port").grid(row=2, column=0)
eport = tkinter.Variable()
entryPort = tkinter.Entry(win, textvariable=eport).grid(row=2, column=1)


button = tkinter.Button(win, text="登录", command=connectServer).grid(row=0, column=2)

text = tkinter.Text(win, height=10, width=40)
labeltext= tkinter.Label(win, text="显示消息").grid(row=4, column=0)
text.grid(row=4, column=1)

esend = tkinter.Variable()
labelesend = tkinter.Label(win, text="发送的消息").grid(row=5, column=0)
entrySend = tkinter.Entry(win, textvariable=esend).grid(row=5, column=1)

efriend = tkinter.Variable()
labelefriend= tkinter.Label(win, text="发给谁").grid(row=6, column=0)
entryFriend = tkinter.Entry(win, textvariable=efriend).grid(row=6, column=1)

button2 = tkinter.Button(win, text="发送", command=sendMail).grid(row=6, column=2)
button2 = tkinter.Button(win, text="下线", command=Exit).grid(row=2, column=2)
win.mainloop()

服务器server:

# -*- coding: utf-8 -*-
"""
Created on Tue May 12 23:46:03 2020

@author: LENOVO
"""

import tkinter
import socket, threading

win = tkinter.Tk()  # 创建主窗口
win.title('服务器')
win.geometry("400x300+200+20")
users = {}#用户字典,也可以连接数据库


def run(connect, addrss):
#接收客户端登陆的信息
 userName = connect.recv(1024) 
#解码并储存用户的信息
 users[userName.decode("utf-8")] = connect 
#在连接显示框中显示是否连接成功
 printStr = "" + userName.decode("utf-8") + "连接\n"
 text.insert(tkinter.INSERT, printStr)
#向当前登录的客户端反馈登录信息并提供在线用户列表
 printStr ="登录成功!\n"+"当前在线的好友有:"+str(list(users.keys()))+"\n"
 connect.send(printStr.encode())
#向所有在线的客户端反馈新的好友登录信息并提供在线用户列表
 printStr = userName.decode("utf-8") + "已上线\n"+"当前在线的好友有:"+str(list(users.keys()))+"\n"
 for key in users:
     if key !=userName.decode("utf-8"):
        users[key].send(printStr.encode())
#接受客户端发送的信息
 while True:
  rData = connect.recv(1024) 
  dataStr = rData.decode("utf-8")
#分割字符串得到所要发送的用户名和客户端所发送的信息
  infolist = dataStr.split(":")
#通过客户端要发送的信息中是否指定要发送到的用户,如果没有选择要发送的用户,则默认为群发消息
  if infolist[0] == "" :   
      for key in users:        
          if key !=userName.decode("utf-8"):
             users[key].send((userName.decode("utf-8") + "说(群发):" + infolist[1]).encode("utf")) 
#如果接收到的消息为客户端退出函数发送的“exit”则删掉该用户在users字典中的信息,并通知其他用户该用户已下线
  elif infolist[0] == "exit":
      del users[userName.decode("utf-8")]#删掉该用户信息
      printStr = "" + userName.decode("utf-8") + "下线\n"
      text.insert(tkinter.INSERT, printStr)
      for key in users:
          printStr = userName.decode("utf-8") + "已下线\n"+"当前在线的好友有:"+str(list(users.keys()))+"\n"
          users[key].send(printStr.encode())
 #要发送信息的客户端向目标客户端发送信息        
  else:      
      if infolist[0] in users:
          users[infolist[0]].send((userName.decode("utf-8") + "说(私聊):" + infolist[1]).encode("utf"))
      else:
          printStr =infolist[0]+"不在线,上条消息未发出"+"\n"
          connect.send(printStr.encode())
          



#界面启动按钮连接的函数
def startSever():
#启用一个线程开启服务器
 s = threading.Thread(target=start) 
 s.start()
#开启线程
 
 
def start():
#从输入端中获取ip和端口号
 ipStr = eip.get()
 portStr = eport.get()
# socket嵌套字TCP的ipv4和相关协议
 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
#绑定ip和端口号
 server.bind((ipStr, int(portStr))) 
#设置监听和连接的最大的数量
 server.listen(10) 
#服务器启动信息显示在信息窗口中
 printStr = "服务器启动成功!\n" 
 text.insert(tkinter.INSERT, printStr) 
#模拟服务器要一直运行所以使用死循环
 while True: 
#接受所连接的客户端的信息
  connect, addrss = server.accept()
#每连接一个客户端就开启一个线程
  t = threading.Thread(target=run, args=(connect, addrss))
  t.start()


#下面是关于界面的操作
labelIp = tkinter.Label(win, text='ip').grid(row=0, column=0)
eip = tkinter.Variable()

labelPort = tkinter.Label(win, text='port').grid(row=1, column=0)
eport = tkinter.Variable()

entryIp = tkinter.Entry(win, textvariable=eip).grid(row=0, column=1)
entryPort = tkinter.Entry(win, textvariable=eport).grid(row=1, column=1)
button = tkinter.Button(win, text="启动", command=startSever).grid(row=1, column=2)
text = tkinter.Text(win, height=15, width=40)
labeltext = tkinter.Label(win, text='连接消息').grid(row=3, column=0)
text.grid(row=3, column=1)

win.mainloop()

开启后界面效果:(这里开启一个服务器和三个客户端)

登陆在这里插入图片描述
群聊在这里插入图片描述
私聊在这里插入图片描述
用户下线在这里插入图片描述
参考文章实现了多用户私聊,奠定了框架基础,其本文链接:
https://blog.csdn.net/qq_41682681/article/details/80939682

  • 34
    点赞
  • 198
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
服务端: 服务端程序启动之后弹出窗口,管理员输入IP、端口等信息之后点击启动按钮,服务器启动,服务端窗口自动关闭,之后跳转至服务端信息展示界面,包含用户上线提醒,用户发送信息记录展示。 客户端: 客户端程序启动之后,需要弹出登录界面,当用户成功输入昵称、密码、端口、IP等信息(考虑到用户权限问题,本程序在后台默认有固定IP、端口,)用户只需输入昵称、密码(密码用于后期连接数据库时用来匹配数据库存储的用户信息)。当用户成功输入用户名。昵称、密码等信息客户端登录成功跳转至用户进行端对端的聊天界面。聊天界面大致分为聊天记录展示界面,在线好友信息界面以及用户发送信息处。用户在发送消息处输入想要发送的文本消息,选择在线好友中的好友昵称点击选择好友即可选中您要发给的好友昵称,然后点击发送按钮,即可将消息发送给所选择的好友,同时将信息展示在自己的聊天界面中的聊天记录处 2.2. 功能要求 §2.2.1服务端功能要求: 当管理员输入服务器IP、以及端口等信息之后点击启动按钮之后,服务端正常启动之后,需要保持一直开机状态满足所有用户不论在何时登录之后都能进行与好友之间的聊天交流等,同时服务端还要满足监控用户登录信息,不同用户登录客户端之后,服务器后台能够看到某某客户上线了等提示信息。用于服务端查看好友在线状态同时作为服务器,还要能够监控用户的聊天记录,用于监控用户不能发送一些不利言论,从而将其用户及时作封号处理。阻止其传播一些不健康的言论。 §2.2.2客户端要求: 用户在登录界面输入昵称、密码等信息之后成功登录之后,进行窗口之间的跳转,由登录窗口跳转至进行用户之间的聊天窗口,之前的登录窗口也要随之消失。在聊天窗口之中用户需要根据好友在线信息情况选择自己想要与其进行聊天的对象。用户点击在线好友的昵称点击选择好友即可向该好友发送信息,发送成功之后同时要将其发送的信息以及时间信息展示在自己的窗口之中,同时也要在指定好友的窗口之中有所显示以及时间信息

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值