- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
include std/socket.e as s
include std/error.e as err
constant PORT = 5050
constant BACKLOG = 5
procedure die(object result, sequence action)
printf(2, "Error %d in %s", {result, action})
err:crash(action)
end procedure
procedure ensure_zero(integer result, sequence action)
if result != 0 then
die(result, action)
end if
end procedure
function ensure_seq(object result, sequence action)
if atom(result) then
die(result, action)
end if
return result
end function
enum SOCKET, READ, WRITE, ERROR
constant PHRASE = "Hello from Euphoria\n"
procedure client_proc(sequence socket)
while 1 do
for i = 1 to length(PHRASE) do
sequence result = s:select({}, socket, {}, 0, 100)
sequence result_s = result[1]
if result_s[WRITE] = 1 then
s:send(socket, {PHRASE[i]}, 0)
end if
task_yield()
end for
end while
end procedure
constant client_proc_id = routine_id("client_proc")
sequence server = ensure_seq(s:create(s:AF_INET, s:SOCK_STREAM, 0), "create")
ensure_zero(s:bind(server, "127.0.0.1", PORT), "bind")
ensure_zero(s:listen(server, BACKLOG), "listen")
while 1 do
sequence listen_result = s:select(server, {}, {}, 0, 100)
if listen_result[1][READ] = 1 then
sequence client = ensure_seq(s:accept(server), "accept")
printf(1, "Here comes %s\n", {client[2]})
atom task = task_create(client_proc_id, {client[1]})
task_schedule(task, {0.5, 0.5})
end if
task_yield()
end while
К сожалению, неблокирующие сокеты не работают кросс-платформенно, но работает select.
Осталось добавить кольцевой буфер, и можно сделать чат.
С помощью утилиты euc можно получить статически слинкованный бинарник
Меня теперь еще три дня не отпустит
пиздец конечно тормозит оно, лол
Ну правильно, если по 100 попугаев в каждом селекте спать... Больше тасок - больше лагов.
Какое масштабирование )))
на самом деле он спит в тасках только если некуда писать, но клиентов он ждет по 1/10 секунды, да
Эм, а там никаких ивентов нету что ли?
узнать о наличии данных можно только селектом.
Будет не оч красивый код кмк
сам селект ничего не будит: он блокируюется на 100 попугаев (или сколько напишешь) и возврашает сокеты, ну как селект и делает
а будить нужно самому
>нет такого
кажется, что нет
https://openeuphoria.org/docs/std_socket.html
сокет про таски нич не знает, а таски не знают про сокет
З.Ы. Ещё task_suspend какой-то есть.
>task_suspend
он стопает таску до момента, когда ты явно снова ее запустить черещ schedule
шедудер выбирает все незасуспенженные таски, и в соответствии с их приоритетом их дергает, если пришло время
можно задать или приоритет или время
А должен select/poll, как все нормальные юзермодные шедулеры. И резюмить таски, которые "заблокировались" на чтении или записи. Но, видимо, автор не осилил это в своём курсаче.
но помни: это писалось под атари ст и портировалось под дос потом
When the scheduler must delay, it calls sleep(), unless the required delay is very short. sleep() lets the operating system run other programs.
Такова жизнь... Виндовые шедулеры ещё и про оконные сообщения знают. Как иначе на одном треде сделать быструю реакцию без 100% загрузки проца?
А окна мы как-то обсуждали: они знают, какое окно сейчас активно. А прыщешедулер не знает. Потому винда более отзывчива
ConnectAsync
https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.connectasync?view=netcore-3.1
Можешь тогда себе сам слепить кошерный шедулер.
Сделай лоу-приорити таску которая тупо спит в select'е и пробуждает таски для которых есть готовые сокеты. И обёртки для read, write и accept которые добавляют пару (сокет, self) в массив для селекта и суспендятся.
Поскольку таска лоу приорити, она будет вызываться только когда все "события" обработаны. Ну если я правильно понимаю что такое приоритет.
Написать свой шедулер, который знает про сокеты )
Приоритет влияет на то, какую следующую таску запустит эйфориный шедулер.
Когда ты говоришь task_yield() ты передаешь управление шедулеру.
У него есть список тасок. Он выбирает нужную, и запускает ее.
Кстати, воткнуться можно и на чтении из сокета и на письме в него: Они всё таки блокирующие. Сделать неблокирующим можно только на линукс (под винду API в эфцории нет).
Так что нужно или дергать нативные API винды напрямую (там довольно неплохо сделан интероп) или смириться с тем, что пока ты пишешь гигабайт в сокет клиенту -- остальные таски сосут лапу.
там кстати говорили что есть такая хуйня, что на самом деле даже неблокирующие сокеты блокирующие, если буфер заполнен - в этом случае сисколл просто стоит и ждет, пока сможет запихнуть данные
какая производительность )))
Классический юникс вей это нафоркать детишек по одному на десяток клиентов, и селектом/полом их обслуживать.
Если воткнет, так пострадает группа товарищей, но не все кмк
Есть пруфы?
Обе хуйни вроде одно и тоже, но одна пришла из бзды, а вторая из SysV
Люди не решают сами когда им рождаться
кто же это?|
В воцапе дико бесит недоразвитость. Особенно на десктопе. Терплю это недоразумение ради < 5 контактов
неравноценная какая-то сделка короч
да, я из спб
какой эксперт ))
https://it.wikireading.ru/13685
Кстати, XENIX завозили и на 286 вроде: там уже был защищенный режим (хотя и без страничек).
Как жаль, что MS запилили свой NT на основе VMS, а не Unix. Насколько мир был бы лучше, ах
tl;tr
In fact, you can read sections of VAX/VMS Internals and Data Structures (Digital Press) as an accurate description of NT internals simply by translating VMS terms to NT terms.
Ты просто откртываешь какой-то объект: \Foo\Bar\Bus, и шлешь ему ioctl. А ядро перенаправляет их драйверу, создавшему этот объект (на самом деле там фильтры есть, еще хуйня какая-то, Борманд знает вроде), но в целом именно так.
Все эти ваши C:\ это вообще симлинки
Юзермод: C:\foo\bar
Ядро: \\.\Volume5\foo\bar
Драйвер файлухи для \\.\Volume5: \foo\bar
Но на x86 не встанет