python 實現實時聊天


Python3 socket編程,並與多線程實現最簡單的聊天工具之一

socket通訊必須有服務端和客戶端

 

創建服務端:

 

【第一步】:先創建一個socket類型的對象s:

s=socket.socket(familly,type)

family參數可以是AF_UNIX(Unix域,用於同一台機器上的進程間通訊),也可以是AF_INET(用於IPV4協議的TCP和 UDP)。

type參數一般為SOCK_STREAM(流套接字)或者 SOCK_DGRAM(數據報文套接字),很少用SOCK_RAW(raw套接字)。可以簡單的認為:

SOCK_STREAM :能確保數據達到,用於發送文件數據。

SOCK_DGRAM  :不能確保數據到達,用於局域網廣播消息。

SOCK_RAW        :需要自定義IP包,暫不解釋。

其實后面還有參數proto用來指明要接收的協議包?fileno參數大概是內存地址一類的東西?默認都不填。

【第二步】:調用socket對象里的bind方法綁定IP和端口:

s.bind((host,port))

bind只有一個tuple(元組)類型的參數,host為客戶端的ip,0.0.0.0表示任何ip,本地測試也可以用127.0.0.1,端口最好大於1024。

【第三步】:設置監聽數:

s.listen( )

參數填最大監聽的連接數。

【第四步】:accept方法接收客戶端的連接:

connect , address = s.accept( )

無參數,程序進入阻塞模式直到有客戶端連接,接收到連接后會返回一個元組形式的參數:connect為新產生的socket對象,address為客戶端的ip。

【第五步】:收發數據及關閉連接:

必須使accept返回的新socket對象connect來收發數據,connect里的send和recv方法

connect.send(" string ".encode('utf8'))

connect.recv(size).decode('utf8')

send方法在Python2里參數是字符串,在Python3里參數是二進制對象,所以必須先用encode('utf8')將字符串重新編碼

recv方法參數為讀取的緩沖區大小size,與send方法同理,接收到數據后必須用decode('utf8')將數據解碼成可讀的字符串

最后會話結束s.close()關閉連接

 

 

創建客戶端:

 

【第一步】:先創建一個socket類型的對象s:

s=socket.socket(familly,type)

與服務端同理

【第二步】:連接服務端:

s.connect((host,port))

host為服務端主機的ip,端口為服務端定義的端口。

【第三步】:收發數據及關閉連接:

與服務端同理的send和recv方法

s.send()、s.recv()、s.close()

 

具體代碼(必須在CMD里運行,每次服務端或客戶端僅能發送一條信息,if內代碼可精簡):

服務端:

 

  1.  
    import socket
  2.  
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3.  
    s.bind(( "127.0.0.1",1234))
  4.  
    s.listen( 2)
  5.  
    sock,addr=s.accept()
  6.  
    while True:
  7.  
    t=sock.recv( 1024).decode('utf8') #服務端先接收信息
  8.  
    if t == "exit":
  9.  
    break
  10.  
    print(t)
  11.  
    t=input()
  12.  
    if t == "exit":
  13.  
    break
  14.  
    sock.send(t.encode( 'utf8'))
  15.  
    s.close()

客戶端:

 

  1.  
    import socket
  2.  
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  3.  
    s.connect(( "127.0.0.1",1234))
  4.  
    while True:
  5.  
    t=input()
  6.  
    s.send(t.encode( 'utf8')) #客戶端先發送信息
  7.  
    if t == "exit":
  8.  
    break
  9.  
    t=s.recv( 1024).decode("utf8")
  10.  
    if t == "exit":
  11.  
    break
  12.  
    print(t)
  13.  
    s.close()


由於input函數的阻塞作用,以上的代碼發完一條信息,只能等待另一端的信息發過來才能繼續發送。

這時就要考慮將輸入與接收分開來,將接收的函數(或方法)從主線程里抓出來丟到另一個線程里單獨運行,為實現這一功能,必須引入多線程。

多線程的使用別人的教程寫得都太雜亂,什么select都來了……,其實很簡單,Python里兩句話搞定,需要import  threading

接收的方法為recv,就把s.recv()寫到其他函數里,然后主函數里讓它自己跑起來:

trd=threading.Thread(target=rec,args=(sock,))
trd.start()

target參數為需要跑起來的函數名,僅函數名,不需要括號,args為傳遞到target函數里的參數(元組類型),這里僅傳入收發數據用的socket對象即可

改良后的代碼(須在CMD里運行):

服務端:

 

  1.  
    import socket
  2.  
    import threading
  3.  
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  4.  
    s.bind(( "127.0.0.1",9999))
  5.  
    s.listen( 2)
  6.  
    sock,addr=s.accept()
  7.  
    true= True
  8.  
    def rec(sock):
  9.  
    global true
  10.  
    while true:
  11.  
    t=sock.recv( 1024).decode('utf8') #函數的核心語句就一條接收方法
  12.  
    if t == "exit":
  13.  
    true= False
  14.  
    print(t)
  15.  
    trd=threading.Thread(target=rec,args=(sock,))
  16.  
    trd.start()
  17.  
    while true:
  18.  
    t=input()
  19.  
    sock.send(t.encode( 'utf8'))
  20.  
    if t == "exit":
  21.  
    true= False
  22.  
    s.close()

客戶端:

 

  1.  
    import socket
  2.  
    import threading
  3.  
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  4.  
    s.connect(( "127.0.0.1",9999))
  5.  
    true= True
  6.  
    def rec(s):
  7.  
    global true
  8.  
    while true:
  9.  
    t=s.recv( 1024).decode("utf8") #客戶端也同理
  10.  
    if t == "exit":
  11.  
    true= False
  12.  
    print(t)
  13.  
    trd=threading.Thread(target=rec,args=(s,))
  14.  
    trd.start()
  15.  
    while true:
  16.  
    t=input()
  17.  
    s.send(t.encode( 'utf8'))
  18.  
    if t == "exit":
  19.  
    true= False
  20.  
    s.close()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM