How do i use socket.select?

安稳与你 提交于 2019-12-08 01:54:24

问题


I need some help using socket "select" function.

My server code is like this:

while true do
    for _,server in pairs(servers) do
        local client = server:accept()

        client:settimeout(5)

        local line, err = client:receive()
        if not err then
            client:send(line .. "_SERVER_SIDE\n")
        else
            client:Send("___ERRORPC"..err)
        end

        client:close()
    end
end

But now i want to use the select function instead of make a forever loop like this.

Reading this: http://w3.impa.br/~diego/software/luasocket/socket.html

I know that i can use something simmilar than:

socket.select(servers, nil, 5)

But i don´t know how i can use this on the code above. Can anyone help me?

I will have to use this inside a while true statement?

The reading operation (first parameter) means that i can only make an accept/receive]? And the seconds parameter means that i can only make a send?


回答1:


From the documentation for select: "calling select with a server socket in the receive parameter before a call to accept does not guarantee accept will return immediately. Use the settimeout method or accept might block forever." This means that you'd need to use settimeout before your accept call, but assuming you have a list of opened connections you can work with in servers table, you can use select in the following way:

local canread = socket.select(servers, nil, 1)
for _,client in ipairs(canread) do
  local line, err = client:receive()
  if not err then
      client:send(line .. "_SERVER_SIDE\n")
  else
      client:send("___ERRORPC"..err)
  end
end

socket.select will block for up to 1 second, but will return sooner if there is a socket from the list you provided that can be read from. You can block indefinitely if you use socket.select(servers, nil, 0); blocking for some short time is useful if you need to do some other work while waiting for the input.

Updated to use ipairs instead of pairs as the returns table is keyed both on numbers as well as on sockets themselves, so if one socket can be read from, the returned array looks like {[1] = sock, [sock] = 1}.




回答2:


As per the documentation, select receives one or two arrays of sockets and returns an array of sockets that can safely be read from without blocking and an array of sockets that can be safely written to without blocking and an array of sockets that can safely be written without blocking. An important point is that the first array is for both server sockets that want you want to call accept on and for client sockets that you want to call receive on.

The seconds parameter is just a timeout for the select. It doesn't have to do with how many operations you can make.

The basic thing you are going to have to change in your code is that when a receive call fails with a timeout, instead or giving an error you should add that socket to the array of sockets that you pass to select. This way you can have select tell you when that socket becomes active again.




回答3:


single demo

local server = socket.bind("*",7777)
local client_tab = {}

while true do
    -- socket.select first param is a table of connected socket,
    -- you want a connected socket,you need to call accept()
    -- if you do not want to block,you should call settimeout(seconds)
    local recvt = socket.select(client_tab, nil, 1)
    server:settimeout(1)
    local client = server:accept()
    if client then
        client_tab[#client_tab+1] = client 
    end
    if #recvt > 0 then
        -- read clients in recvt
    end
end


来源:https://stackoverflow.com/questions/16004612/how-do-i-use-socket-select

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!