Python進階開發之網絡編程,socket實現在線聊天機器人


系列文章

第一章 元類編程,已完成 ;

第二章 網絡編程,已完成 ;

本文目錄

什么是socket?創建socket客戶端創建socket服務端socket工作流程圖解socket公共函數匯總實戰:搭建在線聊天機器人

. 什么是socket?

說到網絡編程,難免要提到socket

那什么是socket呢,中文名叫"套接字",更難理解了吧。

通俗來講,socket表示一個網絡連接,通過這個連接,使得主機間或者一台計算機上的進程間可以通訊。

不管是不同主機,還是同一主機。既然是通信,必定有一個發送方,一個接收方。對應一個客戶端,和一個服務端。

. 創建socket客戶端

  • 創建socket,建立連接
1import socket
2
3# 指定IPv4協議(AF_INET),IPv6協議請使用AF_INET6
4# 指定使用TCP協議(SOCK_STREAM),UDP協議請使用SOCK_DGRAM
5sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
6
7# 參數是一個tuple,tuple里指定服務器地址(域名或ip)和端口號
8sock.connect(('www.sina.com.cn', 80))
  • 發送數據
1# 注意這里str格式要遵循HTTP協議標准。
2# 注意結尾一定要用 \r\n\r\n
3sock.send("GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\n\r\n".encode("utf-8"))
  • 接收數據
 1buffer = []
2while True:
3 # 每次最多接收1k字節
4 d = sock.recv(1024)
5 if d:
6 # Python3接收到為bytes類型,要轉為str
7 buffer.append(str(d))
8 else:
9 break
10data = ''.join(buffer)

. 創建socket服務端

  • 創建socket
1import socket
2
3sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  • 綁定ip和port
1# 注意以元組格式傳入,可以是某網卡的公網ip,或0.0.0.0,或127.0.0.1
2sock.bind(('127.0.0.1', 9999))
  • 監聽端口
1# 指定等待連接的最大數量
2sock.listen(5)
  • 接收數據
1while True:
2 # 接受一個新連接,阻塞的,只有接收到新連接才會往下走
3 sock, addr = s.accept()
4 # 每一次連接,都要創建新線程,否則一次只能處理一個連接
5 t = threading.Thread(target=tcplink, args=(sock, addr))
6 t.start()
  • 連接處理函數
1def tcplink(sock, addr):
2 while True:
3 data = sock.recv(1024)
4 if data == 'exit' or not data:
5 break
6 sock.send('Hello, %s!' % data)
7 sock.close()

. socket工作流程圖解

. socket公共函數匯總

  • 發送數據
1# 發送TCP數據,返回值:發送的字節當量
2sk.send("data string")
3
4# 完整發送TCP數據,頻繁調用send方法,確保數據發送完成
5sk.sendall("data string")
6
7# 發送UDP數據
8sk.sendto("data string",address)
  • 接收數據
1# 接收TCP數據,一次最大只接收1k數據
2sk.recv(1024)
3
4# 接收UDP數據,一次只接收1k數據,返回值:數據和發送方ip
5(data,address) = sk.recvfrom(1024)
  • 獲取socket信息
1# 獲取遠程socket的addr,port
2(addr, port) = sk.getpeername()
3
4# 獲取本地socket的addr,port
5(addr, port) = sk.getsockname()
  • 獲取其他信息
 1import socket
2
3# 獲取當前主機名
4HostName = socket.gethostname()
5
6# 獲取當前主機的ip
7HOST = socket.gethostbyname(HostName)
8
9# 獲取當前socket連接的文件描述符
10file_no = sk.fileno()
  • 設置socket
 1# 設置連接的超時時間
2sk.settimeout(timeout)
3sk.gettimeout()
4
5# 設置為非阻塞模式,默認是0(阻塞)
6# 非阻塞下,accept和recv時一旦無數據,則報錯:socket.Error
7sk.setblocking(1)
8
9# 設置socket內部參數,
10# 具體有哪些參數,可以查看socket類的python源碼
11sk.setsockopt(level,optname,value)
12sk.getsockopt(level,optname)

. 實戰:搭建在線聊天機器人

通過上面的學習,我們知道,同主機下或不同主機下的兩個進程要進行通信(TCP/UDP,不管是消息傳輸還是文件傳輸),必定要借助socket這個橋梁。

那接下來,我們就一起來完成這個實戰項目:在線聊天機器人

思路:首先,客戶端和服務端建立socket連接,然后客戶端向服務端發送消息,服務端接收消息,並調用 圖靈機器人API接口,獲取回復返回給客戶端。

在這里,我們需要先去圖靈機器人(http://www.tuling123.com)申請帳號,並創建機器人應用,獲取授權碼。

一切准備就緒,就可以寫我們的代碼了。

  • 客戶端
 1import socket
2import time
3
4class ChatClient:
5 def __init__(self, username, port):
6 self.username = username
7 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
8 self.socket.connect(("127.0.0.1", port))
9
10 def send_msg(self, msg):
11 self.socket.send("{username}::{msg}".format(username=self.username,msg=msg).encode("utf-8"))
12
13 def recv_msg(self):
14 data=self.socket.recv(1024)
15 if data:
16 print("\n【機器人小圖】"+" "+time.strftime('%Y-%m-%d:%H:%M:%S',time.localtime(time.time())))
17 print(data.decode("utf-8"))
18 return True
19 return False
20
21 def main(self):
22 data = self.socket.recv(1024)
23 print(data.decode("utf-8"))
24 msg = input("請輸入消息:")
25 self.send_msg(msg)
26 while True:
27 if self.recv_msg():
28 msg=input("\n我:")
29 self.send_msg(msg)
30 if msg == "exit":
31 print("聊天室已關閉")
32 break
33
34if __name__ == '__main__':
35 cc = ChatClient(username="小明", port=9999)
36 cc.main()
  • 服務端
 1import socket
2import time
3import threading
4import requests
5import json
6
7
8class ChatServer:
9 def __init__(self, port):
10 # 綁定服務器的ip和端口,注意以tuple的形式
11 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12 self.socket.bind(("0.0.0.0", port))
13 self.socket.listen(5)
14 # 圖靈機器人,授權碼
15 self.key = "your tuling robot key"
16 print("正在監聽 127.0.0.1 :{}...".format(port))
17
18 def tcplink(self, sock, addr):
19 # 每次連接,開始聊天前,先歡迎下。
20 sock.send("你好,歡迎來到機器人聊天器!".encode("utf-8"))
21 while True:
22 data = sock.recv(1024).decode("utf-8")
23 print(sock.getpeername())
24 print(sock.getsockname())
25 print(sock.fileno())
26 username = data.split("::")[0]
27 msg = data.split("::")[1]
28 if msg == "exit":
29 break
30 if msg:
31 print("【"+username+"】 "+time.strftime('%Y-%m-%d:%H:%M:%S',time.localtime(time.time())))
32 print(msg)
33 response = self.get_response(msg)
34 sock.send(response.encode("utf-8"))
35 sock.close()
36 print("與 {} 結束聊天!".format(username))
37
38 def get_response(self, info):
39 # 調用圖靈機器人API
40 url = 'http://www.tuling123.com/openapi/api?key=' + self.key + '&info=' + info
41 res = requests.get(url)
42 res.encoding = 'utf-8'
43 jd = json.loads(res.text)
44 return jd['text']
45
46 def main(self):
47 while True:
48 sock, addr = self.socket.accept()
49 t=threading.Thread(target=self.tcplink, args=(sock, addr))
50 t.start()
51
52if __name__ == '__main__':
53 cs = ChatServer(port=9999)
54 cs.main()

將服務端程序跑起來,然后運行客戶端,看下效果。

至此,我們看到我們機器人已經正常和我們調侃。


 

 


免責聲明!

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



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