这个项目的由来是来自计算机网络课程学习的大作业,基于socket套接字写一个超小型的QQ,晚上8点到12点的奋战,编码工作大致做完了,GUI框架也有了,特此分享出来。
功能介绍
已完成
支持单人聊天、支持群聊(所有的人都在一个群)
支持单人收发文件、群收发文件
多线程实现并发
人性化的UI界面
To do list
给每个ip维护一个昵称,方便聊天
支持单人收发文件、群收发文件
select实现并发
操作说明
如图所示:
左边是用户框架,右边是消息框架
选择已登录用户
,消息/文件是群发的
选择树分支下的某个ip,消息/文件是私发给这个ip的
消息``文件
二选一即可发送,优先发送消息
主要技术点
socket编程,实现点对点通信
消息格式统一采用json格式,统一打包和解析
wxPython打造GUI界面
多线程编程、函数式编程
主要代码
采用python环境编写,pycharm+python3.5.1环境;
下面仅给出主要代码
服务端server.py
def socketHander(connectionSocket):
global connectionSocketList
connectionSocketList.append(connectionSocket)
connectionSocket.settimeout(2)
for socket in connectionSocketList:
socket.send(json.dumps(updateConnectionList()).encode("utf-8"))
while True:
try:
# 接收消息
receivedMessage = connectionSocket.recv(1024)
if not receivedMessage:
time.sleep(1)
continue
receivedMessage = receivedMessage.decode("utf-8")
receivedMessage = json.loads(receivedMessage)
print(receivedMessage)
type = receivedMessage.get("type")
if __name__ == "__main__":
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.bind((serverIp,serverPort))
serverSocket.listen(100)
while True:
connectionSocket,addr = serverSocket.accept()
print(connectionSocket.getpeername()) #('127.0.0.1', 1958)
Thread(target=socketHander,args=(connectionSocket,)).start()
客户端client.py
def socketHander(self):
self.clientSocket = socket(AF_INET, SOCK_STREAM)
self.clientSocket.connect((serverIp, serverPort))
self.clientSocket.settimeout(2)
self.ip,self.port = self.clientSocket.getsockname()
print("self ip",self.ip)
while True:
#发送消息
if len(self.sendMessage) == 0:
pass
else:
if self.isChoosedFile == True:
self.clientSocket.send(json.dumps(self.sendMessage).encode("utf-8"))
self.messageList.AppendText("文件[" + self.fileName + "]发送成功\r\n")
self.fileName = None
self.dataOfChoosedFile = None
self.isChoosedFile = False
self.sendMessage = ""
else:
self.clientSocket.send(json.dumps(self.sendMessage).encode("utf-8"))
self.messageList.AppendText("消息["+self.sendMessage.get("content")+"]发送成功\r\n")
self.input.SetLabelText("")
self.sendMessage = ""
try:
# 接收消息
receivedMessage = self.clientSocket.recv(1024)
receivedMessage = receivedMessage.decode("utf-8")
receivedMessage = json.loads(receivedMessage)
print(receivedMessage)
type = receivedMessage.get("type")
# 客户端接收服务端发来的转发消息
if type == "1":
print("客户端收到消息")
sourceIp = receivedMessage.get("sourceIP")
content = receivedMessage.get("content")
if sourceIp == self.ip:
pass
else:
self.messageList.AppendText("来自:["+sourceIp+"]的消息:["+content+"]\r\n")
elif type == "2":
# 客户端接收服务端发来的刷新列表请求
self.userList = receivedMessage.get("content")
self.setUserList()
elif type == "3":
filename = receivedMessage.get("filename")
print("rrrr",filename)
with open(filename,"w") as f:
f.write(receivedMessage.get("content"))
except:
print("等待数据...")
pass
pass
def setUserList(self):
self.userListTree.DeleteChildren(self.rootID)
for user in self.userList:
# if user == self.ip:
# continue
self.userListTree.AppendItem(self.rootID,user)
pass
函数说明
函数名称 | 函数功能 |
---|---|
socket(param1,param2) | 创建一个套接字,param1指明网络层协议,常用AF_INET(ip协议);param2指明传输层协议,常用SOCK_STREAM(TCP)、SOCK_DGRAM(UDP) |
bind((param1,param2)) | 绑定socket到指定的ip(param1)和端口(param2),注意param1,param2必须组成一个元组 |
listen(param) | 指明服务端最大的客户端连接数 |
connect((param1,param2)) | 客户端连接到指定的服务端,参数同bind() |
accept() | 无参数,服务端接收来自客户端的连接请求 |
关于配置两台PC的连接过程,我已经将过程纪录于此:局域网下两台PC机互联填坑之路
下一篇,我们将考虑将服务端部署到阿里云服务器,突破局域网的限制,随时随地聊天。