Как я могу использовать socket.select?
Мне нужна помощь с использованием функции "выбор" сокета.
Мой код сервера выглядит так:
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
Но теперь я хочу использовать функцию выбора вместо создания такого цикла.
Читать это: http://w3.impa.br/~diego/software/luasocket/socket.html
Я знаю, что могу использовать что-то похожее на:
socket.select(servers, nil, 5)
Но я не знаю, как я могу использовать это в коде выше. Может кто-нибудь мне помочь?
Мне придется использовать это в то время как истинное утверждение?
Операция чтения (первый параметр) означает, что я могу только принять / получить]? А параметр секунд означает, что я могу только отправить?
2 ответа
Из документации для select
: "вызов select с серверным сокетом в параметре receive до вызова accept не гарантирует немедленного возврата accept. Используйте метод settimeout, иначе accept может заблокироваться навсегда". Это означает, что вам нужно использовать settimeout
до вашего accept
звоните, но при условии, что у вас есть список открытых соединений, с которыми вы можете работать в servers
стол, вы можете использовать select
следующим образом:
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
будет блокироваться на срок до 1 секунды, но вернется раньше, если в предоставленном вами списке есть сокет, из которого можно прочитать данные. Вы можете заблокировать на неопределенный срок, если вы используете socket.select(servers, nil, 0)
; блокировка на некоторое короткое время полезна, если вам нужно выполнить какую-то другую работу в ожидании ввода.
Обновлено для использования ipairs
вместо pairs
так как таблица возвращений имеет ключи как для чисел, так и для самих сокетов, поэтому, если из одного сокета можно прочитать, возвращаемый массив выглядит следующим образом {[1] = sock, [sock] = 1}
,
Согласно документации, select получает один или два массива сокетов и возвращает массив сокетов, из которых можно безопасно читать без блокировки, и массив сокетов, в которые можно безопасно записать без блокировки, и массив сокетов, которые можно безопасно записывать без блокировки. Важным моментом является то, что первый массив предназначен как для серверных сокетов, для которых вы хотите, чтобы вы вызывали accept, так и для клиентских сокетов, для которых вы хотите позвонить, для получения.
Параметр секунд это просто тайм-аут для выбора. Это не связано с тем, сколько операций вы можете сделать.
Основная вещь, которую вы должны будете изменить в своем коде, состоит в том, что, когда вызов приема завершается неудачно с таймаутом, вместо этого или с ошибкой вы должны добавить этот сокет в массив сокетов, которые вы передаете для выбора. Таким образом, вы можете указать select, когда этот сокет снова станет активным.
Одна демонстрация
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