邓亚君 杨刚 翁文斌 邱泸谊
摘要 本文使用的网络编程模型是客户端/服务端(C/S)结构,网络聊天功能通过socket模块实现,用户在客户端上登录到指定端口的服务端与其他用户进行网络聊天。服务器启动后,等待客户端的连接,转发客户端指定的聊天用户或所有的其他用户。客户端启动后在Python的GUI界面接收用户传递到服务器端的消息。某一用户可以与指定用户进行私聊,也可以向系统中其他已经登录的客户发送消息实现自由聊天,同时可以管理好友列表如添加或删除好友。
【关键词】网络通信socket多线程GUI界面
1 前言
在互联网相当流行的时代,人们对网络的依赖与日俱增,网络交流更是成为了人们生活的一部分。借助网络聊天工具,人们足不出户就可实现闲聊甚至工作交流,使人们的日常生活与工作需求更加便利。网络聊天室主要包括文字聊天室和视频聊天室这两种。本次设计的文字聊天室使用的是Python语言,它具有面向对象、与平台无关、安全、多线程等特点。
2 总体方案设计
2.1 设计原理
Socket对象在网络编程中承担着重要任务,能够用套接字技术编写一个网络聊天室,每个用户需要服务器启动一个线程进行相应工作。在该线程中借助套接字实现客户间信息交流,当服务器接收到客户端发送的聊天信息时,服务器可以在相应的线程的输入流中写入相关信息,然后特定的客户套接字的输入流便能读取到相关信息。
2.2 基本设计概念和处理流程
本系统运行用Python开发,采用C/S结构,系统分为客户端和服务端两大部分,使用socket库建立套接字实现客户端和服务端的通信。
服务器端先将Socket初始化,然后绑定指定端口,实现端口监听,调用accept方法实现TCP阻塞,等待客户端连接。如果这时有一个Socket对象被客户端初始化,并向服务器请求连接。如果连接成功,数据便可以在客户端与服务端之间进行传递。服务端接收客户端发送的数据请求并处理,之后将回应数据发送给指定客户端,该客户端读取相应数据,如果没有数据传递则关闭连接,交互完毕。如图1所示。
这个聊天室采用的是面向连接的传输控制协议,即TCP(Transmission Control Protocol)。TCP协议在传送数据前必须先建立连接,并在数据传送后要释放连接。TCP能够实现全双工通信提供可靠交互的服务,能按序到达目的端,且不会出现错误。
3 单元模块设计
3.1 客户端
客户端代码可以实现在登录窗口中通过套接字连接到本机IP地址127.0.0.1,端口号为9999的指定服务端。登录时通过触发登录按钮调用login_sever函数,退出登录时调用exit_system函数。使用Python的内置模块tkinter描绘界面,其模块中的Tk接口是Python的标准GUI工具包的接口,使用import tkinter的命令即可将该模块导入程序。编写程序时,将窗口的长宽设置为不可变的情况,这样可以保证内部控件位置的合理性。用exit_system函数实现客户端退出,login_sever函数实现登录。在登录函数中调用connect_sever函数,创建socket对象,连接对应的服务端,并为该客户端启动一个线程。客户端有显示对话的功能,并且通过敏感字向聊天室的所有人发送消息,实现群聊和私聊。get_info函数可以实现接受服务器发来的消息,并且能够将好友昵称插入好友列表中。通过好友列表中的Delete键将来将好友删除,以此来管理好友。在本程序中能够自动将已发送消息的好友昵称添加至好友列表。该功能的实现是调用tkinter模块中listbox的delete方法,实现指定好友从列表中删除。客户端能够实现将本用户的消息发给服务端,并且在自己的消息框中展示。通过insert_user()函数将选中的好友名放入发送好友框中,进行指定好友通信,实现私聊。客户端的群聊和私聊的消息展示可以在同一窗口展示。模拟客户端E与客户端Q私聊的消息可以在两方的消息框中展示,并且不会被其他用户看见他们之间私聊的消息。
3.2 服务端
在服务器程序中首先要绑定一个固定端口并监听来自其他客户端的连接。如果某个客户端已发送连接请求,服務器就与该客户端建立Socket连接。在大量的客户端连接中,服务器通过一个Socket连接的服务器地址与端口和客户端的地址与端口来确定是否为唯一的Socket。之所以服务器要对每个客户端的连接需要一个新的线程来处理,是因为服务器必须同时响应多个客户端的请求。首先初始化socket对象,同时使用thread模块实现多线程功能。然后调用Socket对象中的bind()函数来指定服务器的port端口和具体IP地址。最后调用socket对象的accept()方法,等待客户端的连接,并返回连接对象。
1. win = tkinter.Tk() # 创建主窗口
2. win.mainloop() # 相应窗口动态
用tkinter实现GUI界面绘制,entryIp和entryport定义了两个输入框,从键盘中获得服务器的地址和端口。在本程序运行中,采用本机地址127.0.0.1,选择数值较大且不易被计算机使用的端口号9999。对“启动”按键进行绑定函数startSever,用来为服务器运行开启一个线程。
1. def startSever():
2. s = threading.Thread(target=start)# 启 用一个线程开启服务器
3. s.start()# 开启线程
在为服务器启动的线程中,自动触发start函数,使服务器开始监听客户连接,并进行相应的要求应答。服务器每次收到一个客户端的连接请求就为它开启一个线程,同时触发run函数。在该函数中使用while True命令实现服务端不断接收客户端的信息的功能。在run函数里面,服务器使用ck.recv(1024)指令接收客户端发送的消息,并且在for循环中,判断客户发来的消息中是否含有“@全体成员”,对infolist客户列表进行遍历,将消息发送给所有客户端。
在客户登录后,通过广播欢迎消息,可以使客户尽快向聊天室的其他成员发送消息,这样就可以在房间内自由聊天。
4 总体系统
在进行测试系统时,先运行服务端程序,通过操作建立模拟服务器,等待客户端的连接。在本设计中,总共运行了三次客户端的程序,分别模拟用户Q、用户W和用户E。三个客户分别登录到模拟服务器,所以只需要向服务器发送消息,便可以向其他用户发送相应的消息。客户可以向全体成员发送消息,并且客户端之间互发消息不被别人知晓。
能够实现服务器与和客户端之间的通信依赖于socket库的网络编程的方法。s.bind()将套接字绑定到指定地址,s.listen(num)开始监听传入连接,其中num的含义是在拒绝连接之前,计算机可以挂起的最大连接数量,s.accept()接受连接并返回连接对象,可以用来接收和发送数据,accept()方法采用阻塞式策略等待接收TCP客户的连接。s.recv()用来接受套接字的数据。s.send()将接收到的数据发送到指定的套接字。以上几种命令便是在本设计的客户端和服务端程序中使用最多的方法,也是网络通信必不可少的环节。
5 结论
服务端能够显示已连接的用户,并且向指定用户甚至所有用户发送消息,存在特殊关键字的消息可以使人更加明确的知道是群聊消息,通过切换发送对象能够随时随心的私聊。客户端的聊天界面可以显示每条消息的发送时间,并且可以在好友列表中自动插入已给自己发送信息的用户名。客户可以通过删除键删除好友名称,也可以在发送框中选择未在列表里的在线用户进行交流。
参考文献
[1]杨心强,陈国有.数据通信与计算机网络[M].北京:电子工业出版社,2018(06).
[2]张蕾.网络控制中心的远程智能监控系统[J].科技资讯,2014.
[3]王丰锦,邵新宇,喻道远,李培根.基于SOCKET和多线程的应用程序间通信技术的研究[J].计算机应用,2000(06).
[4]杨国军.一种基于WinSocket的聊天程序设计方法[J].内江科技,2007(02).