(已完善)基于Python的TCP 协议实现人机聊天(程序具有服务端和客户端)

服务端

实现目标

  • GUI显示人机互动聊天内容,当客户端输入不完整内容,如’how old’,服务器能回复年龄等。
  • GUI当客户端输入“send a file”,服务器端回复“please input the file name:”(在客户端显示)。
  • (本文代码已实现)当客户端输入文件名后,服务器端如果有该文件,则发送该文件,否则回复客户端“This file does not exist”(此处博主建议采用异常处理)。客户端打印接收到的文件内容。
  • 服务端发送程序参考如下:
if data == 'send a file':
        data = conn.recv(1024).decode()
        filename = data
        file_size = os.path.getsize(filename)
        fhead = struct.pack('l', file_size)
        s.sendall(fhead)
        fp = open(filename, 'rb')
        while True:
            data = fp.read(1024)
            if not data:
                break
            s.sendall(data)
        fp.close()
        print("send over")

  • 实现服务器与多客服通信功能。(线程实现
  • 多客服端参考代码如下:
import socket
from threading import Thread
from os.path import commonprefix

BUFSIZE=1024

def reply(conn):
    # 开始聊天
    while True:
        data = conn.recv(1024).decode()
        if not data:
            break
        print('Received message:', data)
  
        m = 0
        key = ''
        for k in words.keys():
            data = ' '.join(data.split())
            if len(commonprefix([k, data])) > len(k)*0.7:
                key = k
                break
            length = len(set(data.split())&set(k.split()))
            if length > m:
                m = length
                key = k
        # 选择合适的信息进行回复
        conn.sendall(words.get(key, 'Sorry.').encode())
    conn.close()
    
words = {'how are you?':'Fine,thank you.',
         'how old are you?':'38',
         'what is your name?':'Dong FuGuo',
         "what's your name?":'Dong FuGuo',
         'where do you work?':'University',
         'bye':'Bye',
         'send a file':'please input the file name:'}

HOST = '192.168.1.103'
PORT = 5007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定socket
s.bind((HOST, PORT))
# 开始监听一个客户端连接
s.listen(50)
print('Listening on port:',PORT)
while True:
    conn, addr = s.accept()
    print('Connected by', addr)
    Thread(target=reply, args=(conn,)).start()
    s.close()

  • 博主邮箱3303295829@qq.com

聊天功能智能实现原理

commonprefix()函数

  • os.path.commonprefix()是Python中的方法用于获取路径列表中最长的公共路径前缀。博主采用此函数来猜测对方要表达的真正意思。

实现代码

# -*- coding: utf-8 -*-
"""
Created on 2021-12-21 下午 07:47

@author: 浅笑醉红楼.(3303295829@qq.com)

@Software: PyCharm

(1) create by 浅笑醉红楼. 2021-12-21 下午 07:47
"""
import socket
from os.path import commonprefix

words={'how are you?':'Fine,thank you.',
		'how old are you?':'38',
		'what is your name?':'DongFuGuo',
        "what's your name?":'DongFuGuo',
        'where do you work?':'SDIBT',
        'bye':'Bye',
        'send a file':'please input the file name:'}
HOST='' #IP地址
PORT=5007
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定scoket
s.bind((HOST,PORT))
# 开始监听
s.listen(1)
print('Listening at port:',PORT)
conn,addr=s.accept()    
print('Connected by',addr)
while True:
    data = conn.recv(1024).decode()
    if not data:
        break
    print('Received message:', data)
    m = 0
    key = ''
    for k in words.keys():
        data = ' '.join(data.split())
        if len(commonprefix([k, data])) > len(k)*0.7:
            key = k
            break
        length = len(set(data.split())&set(k.split()))
        if length > m:
            m = length
            key = k
    conn.sendall(words.get(key, 'Sorry.').encode())
    try:
	    if data == 'send a file':
	        data = conn.recv(1024).decode()
	        filename = data
	        file_size = os.path.getsize(filename)
	        fhead = struct.pack('l', file_size)
	        s.sendall(fhead)
	        fp = open(filename, 'rb')
	        while True:
	            data = fp.read(1024)
	            if not data:
	                break
	            s.sendall(data)
	        fp.close()
	        print("send over")
	except Exception as e:
    	conn.sendall(words.get(data, 'This file does not exist').encode())
    	print("传输异常:", e)
conn.close()
s.close()

客服端

# -*- coding: utf-8 -*-
"""
Created on 2021-12-22 上午 10:54

@author: 浅笑醉红楼.(3303295829@qq.com)

@Software: PyCharm

(1) create by 浅笑醉红楼. 2021-12-22 上午 10:54
"""
import wx
import socket
import sys
import struct

class ChatWND(wx.Frame):
    def __init__(self, superior):
        wx.Frame.__init__(self, parent=superior,title=u'Chat Window', size=(800, 600))
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.panel.SetBackgroundColour("Green")
        self.label1 = wx.StaticText(self.panel, -1, 'IP:', style=wx.ALIGN_LEFT)
        self.label2 = wx.StaticText(self.panel, -1, 'PORT:', style=wx.ALIGN_RIGHT)
        self.label3 = wx.StaticText(self.panel, -1, 'MSG:', style=wx.ALIGN_LEFT, size=(50, 50))
        self.label4 = wx.StaticText(self.panel, -1, 'Send:', style=wx.ALIGN_LEFT, size=(50, 50))
        self.textIP = wx.TextCtrl(self.panel, -1)
        self.textPORT = wx.TextCtrl(self.panel, -1)
        self.textRecord = wx.TextCtrl(self.panel, -1, style=wx.TE_MULTILINE, size=(520, 200))
        self.textSend = wx.TextCtrl(self.panel, -1, style=wx.TE_MULTILINE, size=(520, 30))
        self.buttonConnectSvr = wx.Button(self.panel, -1, 'Connect')
        self.buttonSendMsg = wx.Button(self.panel, -1, 'Send')
        self.buttonGetFiles = wx.Button(self.panel, -1, 'File')
        sizer1 = wx.FlexGridSizer(2, 2, 20, 15)
        sizer1.AddMany(
            [
                (self.label3, 0, wx.ALIGN_LEFT),
                (self.textRecord, 0, wx.ALIGN_RIGHT),
                (self.label4, 0, wx.ALIGN_LEFT),
                (self.textSend, 0, wx.ALIGN_RIGHT),
            ])
        sizer2 = wx.FlexGridSizer(1, 7, 5, 5)
        sizer2.AddMany(
            [(self.label1, 0, wx.ALIGN_LEFT),
             (self.textIP, 0, wx.EXPAND),
             (self.label2, 0, wx.ALIGN_LEFT),
             (self.textPORT, 0, wx.ALIGN_RIGHT),
             (self.buttonConnectSvr, 0, wx.EXPAND),
             (self.buttonSendMsg, 0, wx.EXPAND),
             (self.buttonGetFiles, 0, wx.ALIGN_RIGHT)
             ])
        self.border = wx.BoxSizer(wx.VERTICAL)
        self.border.Add(sizer1, 0, wx.ALL, 15)
        self.border.Add(sizer2, 0, wx.ALL, 15)
        self.panel.SetSizerAndFit(self.border)
        self.Fit()  
        self.Bind(wx.EVT_BUTTON, self.OnButtonConnectSvr,self.buttonConnectSvr)
        self.Bind(wx.EVT_BUTTON, self.OnButtonSendMsg,self.buttonSendMsg)
        self.Bind(wx.EVT_BUTTON, self.OnButtonGetFiles,self.buttonGetFiles)

    def ConnectSvr(self, HOST, PORT):
    # HOST->服务端主机IP地址
    # PORT->服务端主机端口号
        self.ClientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        try:
            self.ClientSocket.connect((HOST, int(PORT)))  # 连接服务器
            print('连接至服务器')
        except socket.error:
            print('Server not found or not open')
            sys.exit()

    def OnButtonConnectSvr(self, event):
        HOST = self.textIP.GetValue()
        PORT = self.textPORT.GetValue()
        self.ConnectSvr(HOST, PORT)

    def Chat(self):
        strMsg = self.strSend
        self.ClientSocket.sendall(strMsg.encode())  # 发送数据
        data = self.ClientSocket.recv(1024)
        data = data.decode()
        record = self.textRecord.GetValue() + 'Sever:' + data + '\n'
        self.textRecord.SetValue(record)
        if (strMsg.lower() == 'bye'):
            self.ClientSocket.sendall(strMsg.encode())
            data = self.ClientSocket.recv(1024)
            record = self.textRecord.GetValue() + 'Sever:' + data + '\n'
            self.textRecord.SetValue(record)
            self.ClientSocket.close()  # 关闭连接

    def OnButtonSendMsg(self, event):
        self.strSend = self.textSend.GetValue()
        record = self.textRecord.GetValue() + 'Me:' + self.strSend + '\n'
        self.textRecord.SetValue(record)
        self.textSend.SetValue('')
        self.Chat()

    def GetFiles(self):
        filename = self.strSend
        self.ClientSocket.sendall(filename.encode())
        data = self.ClientSocket.recv(1024)
        if (data.decode() == 'This file does not exist'):
            record = self.textRecord.GetValue() + 'Sever:' + data.decode() + '\n'
            self.textRecord.SetValue(record)
        else:
            data = self.ClientSocket.recv(1024)
            f_info = struct.unpack('l', data)
            file_size = f_info[0]
            recv_size = 0
            with open(filename[:filename.rfind('.')] + '_new' +
                        filename[filename.rfind('.'):], 'wb') as fp:
                while not recv_size == file_size:
                    if file_size - recv_size > 1024:
                        data = self.ClientSocket.recv(1024)
                        recv_size += len(data)
                    else:
                        data = self.ClientSocket.recv(file_size - recv_size)
                        recv_size = file_size
                    fp.write(data)
            record = self.textRecord.GetValue() + 'Received a file' + '\n'
            self.textRecord.SetValue(record)

    def OnButtonGetFiles(self, event):
        self.strSend = self.textSend.GetValue()
        record = self.textRecord.GetValue() + 'Me:' + self.strSend + '\n'
        self.textRecord.SetValue(record)
        self.textSend.SetValue('')
        self.GetFiles()


if __name__ == '__main__':
    app=wx.App()
    frame = ChatWND(None)
    frame.Show()
    app.MainLoop()

在这里插入图片描述

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

✎浅笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值