TCP 的英文全拼(Transmission Control Protocol)簡稱傳輸控制協議,它是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。python
socket (簡稱 套接字) 是進程之間通訊一個工具,進程之間想要進行網絡通訊須要基於這個 socket。它負責進程之間的網絡數據傳輸,比如數據的搬運工。不誇張的說,只要跟網絡相關的應用程序或者軟件都使用到了 socket 。web
下面是一個開發TCP應用程序客戶端的通常流程,後面見具體代碼:json
建立客戶端套接字對象api
和服務端套接字創建鏈接瀏覽器
發送數據bash
接收數據服務器
關閉客戶端套接字網絡
from socket import *
class Cilent_Socket:
def __init__(self):
self.tcp_client_socket = socket(AF_INET, SOCK_STREAM) # AF_INET指ipv4地址,SOCK_STREAM指TCP協議
self.tcp_client_socket.connect(('192.168.137.1',8989)) #鏈接服務端,指定服務器ip和端口
def run(self):
while True:
# 用戶輸入數據
send_data = input("我:")
if len(send_data)==0:
print('已斷開鏈接!')
break
if send_data == "quit" or send_data == "exit" or send_data =='Bye'or send_data =='bye':
self.tcp_client_socket.send(send_data.encode("gbk"))
recv_data = self.tcp_client_socket.recv(4096).decode('gbk')
print('小美:', recv_data)
self.tcp_client_socket.close()
break
self.tcp_client_socket.send(send_data.encode("gbk")) # 接收對方發送過來的數據,最大接收4096個字節
recv_data = self.tcp_client_socket.recv(4096).decode('gbk')
print('小美:', recv_data)
# 關閉套接字
self.tcp_client_socket.close()
def main():
client = Cilent_Socket()
client.run()
if __name__ == '__main__':
main()複製代碼
上面代碼中的__init__
方法初始化了一個客戶端套接字,並與服務器創建一個長鏈接,run()
方法中用於和後臺機器人發送消息和接收機器人給你返回的消息。多線程
建立一個服務端程序的基本步驟是:app
建立服務端端套接字對象
綁定端口號
設置監聽
等待接受客戶端的鏈接請求
接收數據
發送數據
關閉套接字
要建立一個能自動回覆的機器人,只要循環接收用戶輸入的信息,將其輸入的關鍵詞進行判斷,能夠後臺預先給定它對應的關鍵詞對應給用戶回覆的信息便可,或者調用已知已經作好的API接口。下面兩種狀況會分別進行介紹。
1.自定義消息關鍵詞回覆
from socket import *
import time
import random
class Server_Socket:
def __init__(self):
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
tcp_server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, True) #設置端口複用
tcp_server_socket.bind(('', 8989)) # 綁定服務器端口
tcp_server_socket.listen(128)
self.tcp_server_socket = tcp_server_socket
self.chat_list = ['今每天氣真好,和朋友出去玩一下吧','今天你學習了嗎','又不知道吃什麼','藍瘦香菇','好嗨喲','去看電影吧','去吃好吃的'] # 定義初始化消息回覆列表
def start(self):
client_socket, client_addr = self.tcp_server_socket.accept()
while True:
# 接收對方發送過來的數據
recv_data = client_socket.recv(4096).decode('gbk') # 接收4096個字節
if len(recv_data) == 0:
print("程序結束")
break # 下面一串是對用戶的輸入邏輯進行判斷
elif recv_data =="quit" or recv_data =="exit" or recv_data =='Bye' or recv_data =='bye' or recv_data =='再見':
client_socket.send('再見'.encode('gbk'))
break
elif "你好" in recv_data or "hello" in recv_data:
client_socket.send("你好".encode('gbk'))
elif "sb" in recv_data or "SB" in recv_data or "傻" in recv_data or "二貨" in recv_data :
client_socket.send("你才傻,你全家都傻!!!".encode('gbk'))
elif "賤" in recv_data or "蠢" in recv_data :
client_socket.send("你個蠢貨!".encode('gbk'))
elif "吃" in recv_data or "hello" in recv_data:
client_socket.send("紅燒肉、東坡肘子...".encode('gbk'))
elif "玩" in recv_data or "hello" in recv_data:
client_socket.send("雲南麗江不錯!".encode('gbk'))
elif "名字" in recv_data or "name" in recv_data:
client_socket.send("我叫小美,編號9527,哈哈...".encode('gbk'))
elif "時間" in recv_data or "time" in recv_data:
client_socket.send(('如今時間是:'+time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))).encode('gbk')) # 返回當前時間
else:
self.chat_list.append(recv_data) # 收集用戶輸入信息,豐富詞彙
rand_idx = random.randint(0, len(self.chat_list) - 1) # 經過隨機下標獲取一條信息
send_data = self.chat_list[rand_idx] # 將信息發送給客戶端
client_socket.send(send_data.encode('gbk')) # 關閉爲這個客戶端服務的套接字,只要關閉了,就意味着爲不能再爲這個客戶端服務了,若是還須要服務,只能再次從新鏈接
client_socket.close()
def main():
server = Server_Socket()
server.start()
if __name__ == '__main__':
main()複製代碼
上面的代碼是聊天機器人服務端代碼,可和用戶進行通常的閒聊,返回當前時間等,代碼邏輯不復雜,優勢是能夠自行定製。
2.調用圖靈機器人API實現自動回覆
圖靈機器人的接口能夠實現的功能有:中文聊天,情感引擎等。要使用圖靈的API,首先要去它官網進行註冊,而後建立機器人,獲取一個APIkey,而後才能使用它的API接口。下面是網址入口:
下面對它的API文檔有用的一部分進行摘抄:
UTF-8(調用圖靈API的各個環節的編碼方式均爲UTF-8)
openapi.tuling123.com/openapi/api…
HTTP POST
請求參數格式爲 json 請求示例:
{ "reqType":0, "perception": { "inputText": { "text": "附近的酒店" }, "inputImage": { "url": "imageUrl" }, "selfInfo": { "location": { "city": "北京", "province": "北京", "street": "信息路" } } }, "userInfo": { "apiKey": "", "userId": "" }}複製代碼
參數說明
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
reqType | int | N | - | 輸入類型:0-文本(默認)、1-圖片、2-音頻 |
perception | - | Y | - | 輸入信息 |
userInfo | - | Y | - | 用戶參數 |
perception
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
inputText | - | N | - | 文本信息 |
inputImage | - | N | - | 圖片信息 |
inputMedia | - | N | - | 音頻信息 |
selfInfo | - | N | - | 客戶端屬性 |
注意:輸入參數必須包含inputText或inputImage或inputMedia!
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
text | String | Y | 1-128字符 | 直接輸入文本 |
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
url | String | Y | 圖片地址 |
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
url | String | Y | 音頻地址 |
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
location | - | N | - | 地理位置信息 |
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
city | String | Y | - | 所在城市 |
province | String | N | - | 省份 |
street | String | N | - | 街道 |
userInfo
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
apiKey | String | Y | 32位 | 機器人標識 |
userId | String | Y | 長度小於等於32位 | 用戶惟一標識 |
groupId | String | N | 長度小於等於64位 | 羣聊惟一標識 |
userIdName | String | N | 長度小於等於64位 | 羣內用戶暱稱 |
輸出示例:
{ "intent": { "code": 10005, "intentName": "", "actionName": "", "parameters": { "nearby_place": "酒店" } }, "results": [ { "groupType": 1, "resultType": "url", "values": { "url": "http://m.elong.com/hotel/0101/nlist/#indate=2016-12-10&outdate=2016-12-11&keywords=%E4%BF%A1%E6%81%AF%E8%B7%AF" } }, { "groupType": 1, "resultType": "text", "values": { "text": "親,已幫你找到相關酒店信息" } } ]}複製代碼
參數說明
參數 | 類型 | 是否必須 | 取值範圍 | 說明 |
---|---|---|---|---|
intent | - | Y | - | 請求意圖 |
results | - | N | - | 輸出結果集 |
intent
參數 | 類型 | 是否包含 | 取值範圍 | 說明 |
---|---|---|---|---|
code | int | Y | - | 輸出功能code |
intentName | String | N | - | 意圖名稱 |
actionName | String | N | - | 意圖動做名稱 |
parameters | Map | N | - | 功能相關參數 |
results
參數 | 類型 | 是否包含 | 取值範圍 | 說明 |
---|---|---|---|---|
resultType | String | Y | 文本(text);鏈接(url);音頻(voice);視頻(video);圖片(image);圖文(news) | 輸出類型 |
values | - | Y | - | 輸出值 |
groupType | int | Y | - | ‘組’編號:0爲獨立輸出,大於0時可能包含同組相關內容 (如:音頻與文本爲一組時說明內容一致) |
下面是針對文檔來封裝實現輸入關鍵詞來返回用戶輸入信息的函數代碼:
import requests
import json
def get_response(msg):
api = 'http://openapi.tuling123.com/openapi/api/v2' # 接口地址
data = { "perception": { "inputText": { "text": msg }, "inputImage": { "url": "imageUrl" }, "selfInfo": { "location": { "city": "成都", # 參數必須指定地點 "province": "四川", # 參數必須 "street": "蜀西路" } } }, "userInfo": { "apiKey": '', # 參數必須此處填入網站申請的key "userId": "" } }
data = json.dumps(data) # 將字典格式轉化爲json格式,另外loads函數是將json轉化爲python中的字典
print(data)
print('=================================================================================')
r = requests.post(api, data=data).json() # 將post請求的結果轉爲json
print(r)
return r['results'][0]['values']['text'] # 返回的數據
mes = get_response('天氣') # 輸入關鍵詞複製代碼
上面用到了python內置的request和json庫,調用了幾回發現有時返回的結果不太滿意,不知道是否是沒有買它套餐的緣由。上一個版本的機器人服務端只實現了單用戶,下面實現能夠多用戶聊天的版本:
import socket
import threading
import requests
import json
# 建立web服務器的類
class HttpWebServer:
"""初始化套接字對象"""
def __init__(self, port):
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
tcp_server_socket.bind(('', port))
tcp_server_socket.listen(128)
self.tcp_server_socket = tcp_server_socket
@staticmethod
def get_response(msg):
# 調用圖靈機器人API
api = 'http://openapi.tuling123.com/openapi/api/v2'
data = { "perception": { "inputText": { "text": msg }, "inputImage": { "url": "imageUrl" }, "selfInfo": { "location": { "city": "成都", "province": "四川", "street": "" } } }, "userInfo": { "apiKey": '',# 填入申請的key "userId": "" } }
data = json.dumps(data) # 將字典格式轉化爲json格式,另外loads函數是將json轉化爲python中的字典
print(data)
# print('=================================================================================')
r = requests.post(api, data=data).json() # 將post請求的結果轉爲json
print(r)
return r['results'][0]['values']['text'] # 返回的數據
@staticmethod
def client(new_socket):
"""新套接-請求-響應"""
# 接受客戶端消息
while True:
recv_data = (new_socket.recv(4096))
recv_decode = recv_data.decode('utf-8')
# 判斷請求內容長度,若爲0,則瀏覽器斷開鏈接
if len(recv_data) == 0:
print('offline')
new_socket.close()
return
print('帥哥:' + recv_decode)
response = HttpWebServer.get_response(recv_decode)
new_socket.send(response.encode('utf-8'))
def start(self):
"""開啓服務器的方法"""
while True:
# 循環接受請求,並建立相應的套接字
new_socket, ip_port = self.tcp_server_socket.accept()
# 運用多線程實現多個客戶端訪問,並設置主線程守護
sub_threading = threading.Thread(target=self.client, args=(new_socket,), daemon=True)
# 子線程開啓
sub_threading.start()
def main():
"""程序入口"""
web_server = HttpWebServer(8989)
web_server.start()
if __name__ == '__main__':
main()複製代碼
上面採用了threading實現了可多用戶聊天,並使用了守護主線程,防止了在主線程接受數據阻塞引發服務器崩潰的狀況。