官术网_书友最值得收藏!

2.6 做留言板,使用數據庫

游戲服務端的另一項重要功能是保存玩家數據,Skynet提供了操作MySQL數據庫、MongoDB數據庫的模塊。

2.6.1 功能需求

如圖2-18所示,客戶端發送“set XXX”命令時,程序會把留言“XXX”存入數據庫,發送“get”命令時,程序會把整個留言板返回給客戶端。

圖2-18 留言板示意圖

2.6.2 學習數據庫模塊

skynet.db.mysql模塊提供操作MySQL數據庫的方法,如表2-7所示。

表2-7 連接MySQL數據庫的API

2.6.3 準備數據庫

服務端與MySQL通過TCP相連,獲取數據時,服務端會以特定形式發送形如“查詢id為101的玩家數據”的消息,MySQL收到消息后,回應查到的數據。啟動留言板程序前,需要先開啟MySQL數據庫,預先創建數據表。

知識拓展:完整地安裝和啟動MySQL數據庫包括如下步驟:

(1)安裝MySQL數據庫

在CentOS下執行如下三條指令,下載MySQL5.7并安裝它。如果提示系統找不到wget或rpm,請先用yum install XXX安裝它們。


wget 'https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm'
rpm -Uvh mysql57-community-release-el7-11.noarch.rpm
yum install mysql-community-server

(2)啟動MySQL數據庫

執行如下指令啟動MySQL數據庫。


service mysqld start

(3)查看默認數據庫密碼

新版MySQL(5.7之后)出于安全考慮,要求用戶重設密碼,之后才能正常操作。要重設密碼,就要先登錄數據庫,再執行修改密碼的指令。要登錄數據庫,就得用默認的密碼。那么,默認的密碼是什么?執行如下指令打開MySQL的日志文件。


vim/var/log/mysqld.log

會看到其中有一句


A temporary password is generated for root@localhost: qeWupq-Bp4K5

其中的“qeWupq-Bp4K5”就是首次登錄時要輸入的密碼,這是個隨機數,先記下它。

(4)修改密碼

輸入如下指令登錄數據庫,其中-u后面的root代表用戶名,-p后面的字符代表初始密碼。


mysql -h127.0.0.1 -uroot -pqeWupq-Bp4K5

在MySQL的命令行中輸入如下指令,其中的12345678aB-代表新密碼。密碼必須是8位以上,且含有數字、字母和特殊字符。


mysql> alter user 'root'@'localhost' identified by "12345678aB-";

(5)開放權限

出于安全考慮,默認情況下,新版MySQL只開放本地root權限,即只能在本機登錄。由于我們只是做實驗,不需要考慮安全性問題,因此可以輸入如下語句,讓其他電腦連接(安全的做法是新建一些受限賬號,對這些賬號僅開放所需的權限)。


mysql> use mysql;
mysql> update user set host='%' where user='root';   
mysql> flush privileges;

(6)測試

重新連接數據庫,輸入如下SQL語句顯示MySQL數據庫中的庫。如能成功,說明一切就緒。


mysql> show databases;

圖2-19展示了MySQL數據庫的結構。一個MySQL包含多個庫,庫中包含多個表,每個表包含多個欄位。操作數據庫時,需選定某個庫(如表2-5中mysql.connect的database項),再增刪改表中的數據。

圖2-19 MySQL數據庫的結構

知識拓展:有多種手動操作MySQL數據庫的方法。

(1)用命令行操作

使用“mysql-h127.0.0.1-uroot-pXXX”登錄數據庫,再輸入SQL語句即可實現操作,只是不太直觀。

(2)用工具操作

可在Windows上安裝“Navicat for MySQL”來操作MySQL數據庫,它是個可視化的MySQL客戶端軟件。本節會演示“Navicat for MySQL”的操作方法。

先創建名為message_board的庫。如圖2-20所示,打開Navicat,填入MySQL數據庫的IP、端口、用戶名和密碼,登錄數據庫(如果連接失敗,除了檢查用戶名、密碼外,還需設置云服務器的安全策略,開放3306端口)。

圖2-20 用Navicat連接數據庫

右鍵單擊連接名,選擇“新建數據庫”,命名為“message_board”。選擇新創建的數據庫,創建名為“msgs”的表,表結構如圖2-21所示。msgs表包含id和text兩個欄位。id欄位為int類型,將其設置為主鍵,不允許空值,并勾選自動遞增;text欄位設為text類型。

圖2-21 msgs表結構

在msgs表里添加幾條數據(用于測試),如圖2-22所示。

圖2-22 在msgs表里添加測試數據

2.6.4 代碼實現

這里先不直接做留言板,而是寫個小程序嘗試測試數據庫讀寫功能,以便融會貫通。編寫代碼2-8所示的主服務,功能如下:

·調用mysql.connect連接MySQL,并選用message_board庫。

·使用db:query("insert ...")向數據庫插入一條數據,在text欄位插入字符串“hehe”。

·使用db:query("select ...")查詢數據庫,將結果保存到res中,遍歷它并打印出來。

代碼2-8 examples/Pmain.lua

(資源:Chapter2/5_mysql.lua)


local skynet = require "skynet"
local mysql = require "skynet.db.mysql"

skynet.start(function()
    --連接
    local db=mysql.connect({
        host="39.100.116.101",
        port=3306,
        database="message_board",
        user="root",
        password="7a77-788b889aB",
        max_packet_size = 1024 * 1024,
        on_connect = nil
    })
    --插入
    local res = db:query("insert into msgs (text) values (\'hehe\')")
    --查詢
    res = db:query("select * from msgs")
    --打印
    for i,v in pairs(res) do
        print ( i," ",v.id, " ",v.text)
    end
end)

運行服務端,能看到如圖2-23所示的輸出,其中“hello”和“good”是手動添加的數據,“hehe”是主服務添加的數據。

圖2-23 程序運行結果

現在將網絡編程和數據庫操作結合起來,完成本節的需求。在代碼2-9中,新增變量db用于保存數據庫對象;服務啟動后,開啟網絡監聽,并發起數據庫連接。

代碼2-9 examples/Pmain.lua中的部分內容

(資源:Chapter2/5_messageboard.lua)


local skynet = require "skynet"
local socket = require "skynet.socket"
local mysql = require "skynet.db.mysql"

local db = nil

skynet.start(function()
    --網絡監聽
    local listenfd = socket.listen("0.0.0.0", 8888)
    socket.start(listenfd ,connect)
    --連接數據庫
    db=mysql.connect({
            host="127.0.0.1",
            port=3306,
            database="message_board",
            user="root",
            password="12345678aB+",
            max_packet_size = 1024 * 1024,
            on_connect = nil
        })
end)

新連接的回調方法connect如代碼2-10所示,它分成兩個部分:

·如果客戶端發送的數據是“get\r\n”,則查詢數據庫,然后將結果一條條地發回。

·如果客戶端發送的是“set XXX”(為了簡潔,假設用戶會輸入正確的數據),則用正則表達式將字符串XXX提取出來(變量data),然后插入數據庫中。

代碼2-10 examples/Pmain.lua中connect方法的部分代碼


function connect(fd, addr)
    ……
    --正常接收
    if readdata ~= nil then
        --返回留言板內容
        if readdata == "get\r\n" then
            local res = db:query("select * from msgs")
            for i,v in pairs(res) do
                socket.write (fd, v.id.." "..v.text.."\r\n")
            end
        --留言
        else
            local data = string.match( readdata, "set (.-)\r\n")
            db:query("insert into msgs (text) values (\'"..data.."\')")
        end
   ……
end

說明:“\r\n”即換行符,在telnet中輸入字符串,它會把換行符也發給服務端。

2.6.5 運行結果

開啟服務端,再用telnet連接。客戶端的運行結果如圖2-24所示:輸入get命令,能看到所有留言;輸入set lpy表示插入留言;再輸入get可獲取相應信息。

圖2-24 留言板客戶端的運行結果

主站蜘蛛池模板: 台北市| 万宁市| 电白县| 孝感市| 阿图什市| 夹江县| 铁岭市| 株洲市| 内江市| 清远市| 新平| 乌拉特前旗| 舟曲县| 同心县| 凤冈县| 中方县| 汝州市| 光泽县| 宿松县| 航空| 星座| 盈江县| 普宁市| 江山市| 木兰县| 沈丘县| 铁岭县| 汝阳县| 通山县| 滕州市| 白银市| 内黄县| 亚东县| 连云港市| 时尚| 郓城县| 青铜峡市| 莱西市| 开阳县| 北宁市| 融水|