百万在线:大型游戏服务端开发
上QQ阅读APP看书,第一时间看更新

2.4 写Echo,练习网络编程

游戏服务端要处理客户端请求,作为服务端引擎,网络编程也是Skynet的核心功能。

2.4.1 功能需求

图2-14是开启处理客户端消息的服务,它会把收到的内容原封不动地发回给客户端。

图2-14 Echo程序示意图

2.4.2 学习网络模块

skynet.socket模块提供了网络编程的API,Echo程序会用到它们,如表2-6所示。

表2-6 处理网络消息的API

更多API参见https://github.com/cloudwu/skynet/wiki/Socket,本节暂不列举太多,后面用到时再做介绍。socket.read中所谓的阻塞模式和skynet.call一样,都利用了Lua的协程机制。调用socket.read,服务有可能被挂起,直到接收到数据,才会往下执行。2.9节将对阻塞模式做进一步说明。

2.4.3 代码实现

本例只需开启一个服务。修改主服务Pmain,程序结构如代码2-5所示。先引入skynet和skynet.socket这两个模块,在服务启动后(使用skynet.start的回调方法),依次调用socket.listen和socket.start来监听8888端口。socket.start的回调方法connect见代码2-6。

代码2-5 examples/Pmain.lua

(资源:Chapter2/3_echo.lua)


local skynet = require "skynet"
local socket = require "skynet.socket"
    
skynet.start(function()
    local listenfd = socket.listen("0.0.0.0", 8888)
    socket.start(listenfd ,connect)
end)

新客户端发起连接时,connect方法将被调用。在while循环里,程序先用socket.read接收数据,如果收到数据(if readdata~=nil的真分支),则通过socket.write将数据发回客户端;如果客户端断开了连接(if readdata~=nil的假分支),则调用socket.close关闭连接。代码中的print方法用于打印调试信息,与skynet.error类似。

代码2-6 examples/Pmain.lua


function connect(fd, addr)
    --启用连接
    print(fd.." connected addr:"..addr)
    socket.start(fd)
    --消息处理
    while true do
        local readdata = socket.read(fd)
        --正常接收
        if readdata ~= nil then
            print(fd.." recv "..readdata)
            socket.write(fd, readdata)
        --断开连接
        else
            print(fd.." close ")
            socket.close(fd)
        end
    end
end

2.4.4 运行结果

执行./skynet examples/Pconfig运行服务端程序。

说明:如果开启服务端时提示“init service failed: ./lualib/skynet/socket.lua:360: Listen error”,意味着监听端口8888被占用,可能是多次运行服务端所致,可以(在测试环境下)执行“killall-9 skynet”关闭所有的Skynet进程。

再启动客户端程序(如telnet),连接服务端。

知识拓展:telnet是Linux下的一个程序,可用于调试TCP连接。如果尚未安装,可在CentOS下执行“yum install telnet”安装。输入“telnet [ip] [端口]”即可向指定服务器发起连接(图2-15所示为连接127.0.0.1:8888),还可以在telnet中输入内容,按回车键可将字符串发给服务端。

如果使用云服务器时能够在本机上调试,但无法跨机器连接,很可能是云服务器防火墙屏蔽了客户端连接,可以设置云服务器的“安全策略”以开放端口。

Echo程序的运行结果如图2-16所示,这里先后开启了两个客户端,分别输入“lpy”和“helloskynet”,服务端将会给出回应。图中客户端部分白色字体代表用户输入,灰色字体代表程序输出,灰色箭头代表消息的流向。

图2-15 向指定服务器发起连接

图2-16 Echo程序的运行结果