python的tkinter、socket库开发tcp的客户端和服务端

news2024/9/22 19:40:11
一、tcp通讯流程和开发步骤
1、tcp客户端和服务端通讯流程图

套接字是通讯的利器连接时要经过三次握手建立连接,断开连接要经过四次挥手断开连接。

2、客户端开发流程

1)创建客户端套接字

2)和服务端器端套接字建立连接

3)发送数据

4)接收数据

5)关闭客户端套接字

3、服务端开发流程

1)创建服务端套接字

2)绑定ip和端口号

3)设置监听

4)等待客户端连接

5)接收数据

6)发送数据

7)关闭套接字

二、客户端的实现

使用python的tkinter库实现图形化界面,使用类来实现tcp的客户端和服务端

1、构造方法__init__初始化图形界面

设置了三个按钮

1)连接服务器的按钮: 用来发送请求连接服务端。

2)断开连接按钮:用来关闭连接。

3)发送消息按钮:来向服务端发送消息。

2、连接服务器的函数

1) tk.messagebox.showinfo: 弹窗,用来提示用户。

2socket.socket(socket.AF_INET, socket.SOCK_STREAM):  创建套接字。

参数1:ipv4协议,参数2:表示tcp协议

3)tcp_client_socket.connect(): 连接服务端,参数必须是一个元组。

3、发送消息函数

1)send_entry.get(): 获取输入框的内容。

2)encode():编码。

3)tcp_client_socket.send(): 发送数据。

4)Thread(): 创建线程,防止阻塞。

参数1:target=要执行的函数,参数2:守护主线程。

5) .start(): 开启线程。

4、接收消息函数

recv_data = tcp_client_socket.recv(1024).decode('utf-8'): 接收消息并解码。

5、断开连接函数

 tcp_client_socket.close(): 关闭客户端套接字。

三、服务端的实现
1、构造方法__init__初始化图形界面

设置了四个按钮:

1)启动服务端按钮:用来初始化服务端。

2)接收连接按钮:接收客户端请求的连接。

3)接收消息按钮:接收客户端发来的消息,需要手动接收。

4)发送消息按钮:向客户端发送消息。

2、启动服务端函数

1)tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM):创建服务器端套接字对象。

2)tcp_server_socket.bind(("", 8888)): 绑定IP地址与端口号,端口可以自行设置,但客户端必须和服务端保持一致。

3)tcp_server_socket.listen(5):监听连接,5表示最大连接数。

3、接收连接函数

 conn_socket, ip_port = tcp_server_socket.accept():等待接收客户端连接请求。

4、发送消息函数

 conn_socket.send(): 发送数据

5、接收消息函数

conn_socket.recv(1024).decode():接收数据并解码

conn_socket.close(): 关闭连接

tcp_server_socket.close():关闭套接字

四、效果图

使用说明:

1、先启动服务端,在启动客户端,再服务端点击接收连接按钮接收客户端发来的连接请求

2、客户端输入消息,点击发送消息

3、服务端点击接收消息,就会在下发文本框显示消息

4、服务端回消息,客户端会自动接收消息并显示在下方的文本框

五、代码
1、客户端
import socket
import tkinter as tk
import tkinter.messagebox
from threading import Thread


# 创建tcp客户端
class TcpClientSocket:
    def __init__(self):
        self.tcp_client_socket = None
        self.root = tk.Tk()
        self.root.title('tcp客户端')
        self.root.geometry('500x350')

        # 连接
        self.con_btn = tk.Button(self.root, text="连接服务端", width=10, command=self.connect)
        self.con_btn.place(x=100, y=20)

        # 断开连接
        self.discon_btn = tk.Button(self.root, text="断开连接", width=10, command=self.disconnect)
        self.discon_btn.place(x=300, y=20)

        # 文本输入框
        self.send_entry = tk.Entry(self.root, width=50)
        self.send_entry.place(x=50, y=80)
        # 发送消息按钮
        self.send_btn = tk.Button(self.root, text="发送消息", command=self.send)
        self.send_btn.place(x=420, y=75)

        # 消息框
        self.msg_test = tk.Text(self.root, width=70, height=16)
        self.msg_test.place(x=2, y=125)

        self.root.mainloop()

    # 连接服务端
    def connect(self):
        try:
            if self.tcp_client_socket:
                tk.messagebox.showinfo('提示', '已是连接状态')
            # 每次连接服务端就将上一次的记录清除
            self.msg_test.delete(1.0, tk.END)
            self.send_entry.delete(0, tk.END)
            # 创建客户端socket
            self.tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # 连接,端口可以改变
            self.tcp_client_socket.connect(('127.0.0.1', 8888))
            self.msg_test.insert(tk.END, "连接到服务端, 请输入信息...\n")
        except Exception as e:
            self.msg_test.insert(tk.END, f"连接失败的原因是: {e}")

    # 发送消息
    def send(self):
        # 从输入框获取数据
        input_data = self.send_entry.get()
        self.tcp_client_socket.send(input_data.encode(encoding='utf-8'))
        self.msg_test.insert(tk.END, f"客户端:{str(input_data)}\n")
        # 使用线程,防止未响应
        receive_thread = Thread(target=self.receive, daemon=True)
        receive_thread.start()

    def receive(self):
        if self.tcp_client_socket:
            rec_msg = self.tcp_client_socket.recv(1024).decode(encoding='utf-8')
            self.msg_test.insert(tk.END, f"服务端:{str(rec_msg)}\n")

    # 断开连接
    def disconnect(self):
        if self.tcp_client_socket:
            self.send_entry.delete(0, tk.END)
            self.msg_test.insert(tk.END, "断开连接")
            self.tcp_client_socket.send('#'.encode(encoding='utf-8'))  # 发送’#‘断开连接
            self.tcp_client_socket.close()  # 关闭客户端
        else:
            tk.messagebox.showinfo('提示', '未连接到服务端')


if __name__ == '__main__':
    TcpClientSocket()
2、服务端
import socket

import tkinter as tk
from threading import Thread
import tkinter.messagebox


class TcpServerSocket:
    def __init__(self):
        self.conn_socket = None
        self.tcp_server_socket = None
        self.root = tk.Tk()
        self.root.title('tcp服务端')
        self.root.geometry('500x350')

        # 连接
        self.con_btn = tk.Button(self.root, text="启动服务端", width=10, command=self.start_server)
        self.con_btn.place(x=100, y=20)

        # 接收消息
        self.status_btn = tk.Button(self.root, text="接收连接", width=10, command=self.status)
        self.status_btn.place(x=200, y=20)
        # 接收消息
        self.rev_btn = tk.Button(self.root, text="接收消息", command=self.receive)
        self.rev_btn.place(x=300, y=20)
        # 文本输入框
        self.send_entry = tk.Entry(self.root, width=50)
        self.send_entry.place(x=50, y=80)
        # 发送消息按钮
        self.send_btn = tk.Button(self.root, text="发送消息", command=self.send)
        self.send_btn.place(x=420, y=75)
        # 消息框
        self.msg_test = tk.Text(self.root, width=70, height=16)
        self.msg_test.place(x=2, y=125)
        self.root.mainloop()

    # 启动tcp服务端
    def start_server(self):
        try:
            # 每次连接服务端就将上一次的记录清除
            self.send_entry.delete(0, tk.END)
            self.msg_test.delete(1.0, tk.END)

            # 创建服务端socket
            self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server_socket.bind(('', 8888))  # 绑定
            self.tcp_server_socket.listen(5)  # 监听的最大连接数
            self.msg_test.insert(tk.END, f"服务端启动成功!\n")
        except Exception as e:
            self.msg_test.insert(tk.END, f"启动失败的原因是: {e}")

    def status(self):
        if self.conn_socket is None:
            self.conn_socket, ip_port = self.tcp_server_socket.accept()
        elif self.conn_socket:
            self.msg_test.insert(tk.END, "客户端已连接\n")
        else:
            tk.messagebox.showinfo('提示', "客户端未连接")

    def send(self):
        try:
            input_data = self.send_entry.get()
            self.conn_socket.send(input_data.encode(encoding='utf-8'))
            self.msg_test.insert(tk.END, f"服务端:{str(input_data)}\n")
        except Exception as e:
            self.msg_test.insert(tk.END, f"发送失败的原因: {e}")

    def receive(self):
        rec_msg = self.conn_socket.recv(1024).decode(encoding='utf-8')
        print(rec_msg)
        # 获取到#断开连接
        if rec_msg == '#':
            self.conn_socket.close()
            self.tcp_server_socket.close()
            self.msg_test.insert(tk.END, f"客户端断开连接\n")
            return
        self.msg_test.insert(tk.END, f"客户端:{str(rec_msg)}\n")


if __name__ == '__main__':
    TcpServerSocket()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1939855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

钡铼分布式I/O系统边缘计算Modbus,MQTT,OPC UA耦合器BL206

BL206系列耦合器是一个数据采集和控制系统,基于强大的32 位微处理器设计,采用Linux操作系统,支持Modbus,MQTT,OPC UA协议,可以快速接入现场PLC、DCS、PAS、MES、Ignition和SCADA以及ERP系统,同时…

习题2.21

(defn rever [a](defn item[l r](if ( nil (first l)) r(item (rest l) (cons (first l) r))))(item a nil)) 这段代码非常有助于理解什么是深度优先,什么是广度优先。 很久没有写习题的代码了,倒不是懒得做习题了,是私事多,状态…

【局域网服务器连接】如何远程连入实验室linux系统服务器?| 局域网 | 内网穿透

文章目录 前言服务器基本配置安装 ssh 服务防火墙放行 局域网内网穿透获取SN码添加映射 总结 前言 简单记录连接实验室服务器步骤。如服务器直接有公网 ip 地址,ssh 直接连入即可,无需参考本文。 与服务器连同一 wifi, 参考 局域网 方式连接…

Android:requestLayout、invalidate 和 postInvalidate 的区别

提醒:下面源码来自SDK里Android-34版本 一、requestLayout 点击查看requestLayout官网文档 1.1 requestLayout方法源码 /*** Call this when something has changed which has invalidated the* layout of this view. This will schedule a layout pass of the v…

【C++航海王:追寻罗杰的编程之路】关于空间配置器你知道多少?

目录 1 -> 什么是空间配置器 2 -> 为什么需要空间配置器 3 -> SGI-STL空间配置器的实现原理 3.1 -> 一级空间配置器 3.2 -> 二级空间配置器 3.2.1 -> 内存池 3.2.2 -> SGI-STL中二级空间配置器设计 3.2.3 -> SGI-STL二级空间配置器之空间申请 …

Spring Boot 3.3 【三】Spring Boot RESTful API 增删改查详细教程

Spring Boot RESTful API 增删改查详细教程 一、RESTful 架构风格简介 1. 简介 RESTful API 是一种基于HTTP协议的网络应用接口设计风格,它遵循REST(Representational State Transfer,表述性状态转移)原则。RESTful架构风格的出…

花几千上万学习Java,真没必要!(二十)

ArrayList 是一种可以动态增长和缩减的数组,与普通的数组相比,它提供了更加灵活的操作方式。ArrayList 内部使用数组来存储元素,但是它会根据需要自动调整数组的大小,以便能够存储更多的元素。 ArrayList 的主要特点包括&#xf…

如何成为学习高手

文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 所有的学习方式,核心都是动脑加动手。 区别在于如何让…

吴恩达大模型LLM系列课程学习(更新42门课程)

目录 GPT-4o详细中文注释的Colab中英文字幕观看视频1 浏览器下载插件2 打开官方视频 课程1:Prompt Compression and Query Optimization课程2:Carbon Aware Computing for GenAI developers课程3:Function-calling and data extraction with …

Java语言程序设计——篇六(1)

字符串 概述创建String类对象     字符串基本操作实战演练 字符串查找字符串转换为数组字符串比较实战演练 字符串的拆分与组合 概述 字符串 用一对双引号“”括起来的字符序列。Java语言中,字符串常量或变量均用类实现。 字符串有两大类: 1&…

2024年【起重机司机(限桥式起重机)】考试题及起重机司机(限桥式起重机)新版试题

题库来源:安全生产模拟考试一点通公众号小程序 起重机司机(限桥式起重机)考试题参考答案及起重机司机(限桥式起重机)考试试题解析是安全生产模拟考试一点通题库老师及起重机司机(限桥式起重机)操作证已考过的学员汇总,相对有效帮助起重机司机(限桥式起重…

JS 原型与原型链图解:彻底搞懂的终极指南

前言 📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步! 🍅 个人主页:南木元元 在JavaScript中,原型和原型链是非常重要的知识点,只有理解了…

Express+mysql单表分页条件查询

声明(自己还没测试过,只提供大概逻辑,什么多表连接查询可以在原基础上添加) class /*** param connection Express的mysql数据库链接对象* current 当前页* pageSize 一页显示行数* where [{key:id,operator:,value15}], key查询…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 卢小姐的生日礼物(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

pg_restore导入错误的解决思路

背景 开发使用postgresql 数据库,当需要部署时,通过pg_dump导出,通过pg_restore导入,发现导入遇到错误,很多表没有导入。部分报错截图如下: 排查问题 开发中用到了postgresql插件postgis里的地理类型&am…

ORBSLAM3 ORB_SLAM3 Ubuntu20.04 ROS Noetic 虚拟机镜像 下载

下图是build.sh 和 build_ros.sh编译结果截图: slam数据集测试视频: orbslam3 ubuntu20.04 test 下载地址: 链接:https://pan.baidu.com/s/1nre0Y9vig5QXIGU52qCLbQ?pwd9rbi 提取码:9rbi

什么是裸机管理程序?

在这个旨在使最终用户体验尽可能无缝的快节奏环境中,企业不断扩展其网络以处理增加的负载,为了应对可扩展性问题并增强其设备的最佳性能,网络管理员开始使用虚拟化技术。 通过使用管理程序虚拟化网络,网络管理员可以实现灵活、可…

C++基础(3.内和对象)

目录 赋值运算符重载: const限制权限: 隐式类型转换: 再探构造函数: static成员: 有元: 内部类: 赋值运算符重载: 赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值.要注…

【STM32 HAL库】全双工I2S+双缓冲DMA的使用

1、配置I2S 我们的有效数据是32位的,使用飞利浦格式。 2、配置DMA **这里需要注意:**i2s的DR寄存器是16位的,如果需要发送32位的数据,是需要写两次DR寄存器的,所以DMA的外设数据宽度设置16位,而不是32位。…

pgsql的update语句在set里进行字段的运算 SET sort = sort +1

一、场景 需求:version 版本字段是记录数据更新的次数,新增时自动填充 version1 ,每更新一次数据 version就自增1。项目里单表插入和更新要手写update语句进行插入和更新。 –表中int4类型的字段 version 是1时,由1变成2 – version 是null…