微信公衆號:inspurer
關注可瞭解更多的教程及排版技巧。問題或建議,請公衆號留言;
[若是你以爲對你有幫助,歡迎讚揚]php
這個項目的由來是來自計算機網絡課程學習的大做業,基於socket套接字寫一個超小型的QQ,晚上8點到12點的奮戰,編碼工做大體作完了,GUI框架也有了,特此分享出來。python
功能介紹
已完成
支持單人聊天、支持羣聊(全部的人都在一個羣)編程
支持單人收發文件、羣收發文件json
多線程實現併發服務器
人性化的UI界面微信
To do list
給每一個ip維護一個暱稱,方便聊天網絡
支持單人收發文件、羣收發文件多線程
select實現併發併發
操做說明
如圖所示:
app
![在這裏插入圖片描述](http://static.javashuo.com/static/loading.gif)
左邊是用戶框架,右邊是消息框架
選擇`已登陸用戶`,消息/文件是羣發的
選擇樹分支下的某個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機互聯填坑之路
下一篇,咱們將考慮將服務端部署到阿里雲服務器,突破局域網的限制,隨時隨地聊天。
本文分享自微信公衆號 - 月小水長(inspurer)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。