【目標】使用socket套接字寫個簡易的聊天工具团搞,實現(xiàn)全雙工收發(fā)數(shù)據(jù)
語言:python
包:socket threading time
代碼注釋寫的比較詳細严望,這里為了方便所有人都能看懂,大佬可忽略
搭建服務端
本文用到的socket逻恐、threading等都是python內(nèi)置庫像吻,直接import即可;
socket用于構(gòu)建鏈接服務梢莽;
threading用于實現(xiàn)收發(fā)消息的并發(fā)運行萧豆;
話不多說,直接上代碼:
import socket as sk
import threading
import time
def get_host_info(): # 獲取本機IP的函數(shù)
HOSTNAME = sk.gethostname() # gethostname()方法昏名,獲取主機信息
HOST = sk.gethostbyname(HOSTNAME) # gethostbyname()方法涮雷,解析主機信息獲得IP
print(HOST)
return HOST
def recv_message(conn, size):
while True:
recv_msg = conn.recv(size).decode('utf-8') # 接收消息并解碼
print(f'客戶端:{recv_msg}') # 接收消息有內(nèi)容就打印出來
time.sleep(0.1)
def send_message(conn):
while True:
send_msg = input('') # 阻塞等待用戶輸入
if send_msg != '': # 輸入內(nèi)容不為空字符串時,執(zhí)行發(fā)送轻局,否則繼續(xù)循環(huán)
conn.send(send_msg.encode('utf-8')) # UTF-8編碼消息并傳輸
time.sleep(0.1)
else:
pass
HOST = get_host_info() # 獲取本機IP
POST = 8997 # 定義一個端口號
ADDR = (HOST, POST)
SIZE = 1024 # 定義最大傳輸數(shù)據(jù)(bytes)
sever = sk.socket(family=sk.AF_INET, type=sk.SOCK_STREAM) # 創(chuàng)建套接字對象(AF_INET——IPV4洪鸭,SOCK_STREAM——TCP連接)
sever.bind(ADDR) # 套接字對象綁定IP和端口號
sever.listen(10) # 開始監(jiān)聽客戶端的連接請求
conn, addr = sever.accept() # 阻塞并等待連接,解析客戶端主機信息仑扑,連接成功
# conn是新的套接字對象览爵,用來發(fā)送和接收數(shù)據(jù);addr是客戶端的主機地址
print('客戶端已連接镇饮。')
t1 = threading.Thread(target=recv_message, args=(conn, SIZE)) # 構(gòu)造雙線程讓t1和t2并行蜓竹,從而實現(xiàn)全雙工
t2 = threading.Thread(target=send_message, args=(conn,))
if __name__ == '__main__':
t1.start()
t2.start()
搭建客戶端
和服務端的邏輯一樣,把收發(fā)功能和線程再寫一遍
import socket as sk
import threading
import time
def recv_message(client, size):
while True:
recv_msg = client.recv(size).decode('utf-8')
print(f'服務端:{recv_msg}')
time.sleep(0.1)
def send_message(client):
while True:
send_msg = input('')
if send_msg != '':
client.send(send_msg.encode('utf-8')) # 發(fā)信函數(shù)會在此阻塞储藐,等待信息輸入后再循環(huán)
time.sleep(0.1)
else:
pass
client = sk.socket(family=sk.AF_INET, type=sk.SOCK_STREAM)
HOST = '' # 將服務端的HOST寫進來
POST = 8997
ADDR = (HOST, POST)
SIZE = 1024
client.connect(ADDR)
print('服務端已連接俱济。')
t1 = threading.Thread(target=recv_message, args=(client,SIZE))
t2 = threading.Thread(target=send_message, args=(client,))
t1.start()
t2.start()
注意事項
1、服務端和客戶端都啟動的情況下钙勃,才能實現(xiàn)聊天蛛碌。
2、由于沒寫退出功能辖源,任何一方關(guān)閉程序都自動斷開連接蔚携。
3、如果正在輸入時來消息克饶,會打斷輸入過程酝蜒。這是由于未搭建前端文本框?qū)е碌?strong>輸入和輸出信息重疊。一個比較簡單的解決方案是tkinter搭建一個前端交互界面矾湃,將聊天框和輸入框分離亡脑,以解決打斷輸入的問題。后面我也會再寫一篇,記錄tkinter的學習心得远豺。
4、由于服務端程序沒有固定的IP地址坞嘀,目前工具僅能實現(xiàn)同一路由器下的局域網(wǎng)聊天躯护。想實現(xiàn)跨網(wǎng)絡還是要在專屬服務器上搭建。