Заглавието на вашия въпрос, както и фразата предполагат, че се опитвате да използвате UDP сокети като TCP.
TCP и UDP са различни протоколи
TCP е протокол, ориентиран към свързване. Клиентите се свързват със сървъри и даден сървър ще има един сокет за всяка връзка плюс един за слушане. Мрежовият стек на операционната система насочва входящите пакети към слушащия сокет или правилно свързания сокет.
UDP е без връзка. Вашата програма ще има само един UDP сокет. Той ще получи всички UDP пакети към дадения порт. Не можете да създадете процес и да го накарате да слуша на същия порт. Така че не можете да имате повече udp слушатели на същия порт, както сте написали в заглавието.
Като се има предвид изпълнението на Erlang
Общият модел на проектиране за TCP е да има един процес, който обработва слушащия сокет, създавайки нови работни процеси за всеки свързан сокет.
Тъй като се опитвате да приложите нещо подобно с UDP, трябва да извършите това, което мрежовият стек прави за вас с TCP. Можете да имате един процес, който да получава пакети и да ги препраща към правилния работен процес, създавайки, ако е необходимо, въз основа на порта на източника и IP адреса. Този процес трябва да поддържа таблица на всички активни връзки, т.е. всички живи потоци от пакети.
Моля, имайте предвид също, че няма механизъм за затваряне с UDP, така че трябва да разчитате на изчакване и може би допълнителен механизъм във вашия протокол.
Филтрирането на единичен сокет за всеки процес, както предлагате в коментарите, не е възможно, защото Erlang сокет в активен режим изпраща пакети към един процес (контролиращия процес). Можете да си представите някаква архитектура, при която пакетите се излъчват към всички процеси, като всеки извършва филтриране, за да избере интересни пакети.
Ще видите обаче, че това няма смисъл във вашия конкретен сценарий, защото вие също се нуждаете от механизъм, за да разберете дали работният процес трябва да бъде създаден, и този механизъм в крайна сметка ще ви каже кой процес трябва обработва входящия пакет. Може да има смисъл, ако няколко работници обработват едно и също съобщение.
Нека да видим това конкретно с някакъв код:
server_loop(Workers) ->
receive
{udp, Sock, Ip, Port, Msg} = UDPPacket ->
% find out if we need to spawn a new worker.
% typically, Workers is a gb_trees:tree().
NewWorkers = case gb_trees:lookup({Ip, Port}, Workers) of
none ->
NewWorkerPid = spawn_link(fun() -> worker_loop(Ip, Port) end),
gb_trees:insert(NewWorkerPid, Workers);
{value, _WorkerPid} -> Workers %% <- look, we have the worker!
end,
% broadcast to all workers.
lists:foreach(fun({_, Worker} ->
Worker ! UDPPacket
end, gb_trees:to_list(NewWorkers)),
server_loop(NewWorkers);
% ... timeout callbacks from workers would go here
end.
Това е просто прекалено сложна версия на това, което е намекнато по-горе, където пакетът се изпраща до правилния работник всеки път.
server_loop(Workers) ->
receive
{udp, Sock, Ip, Port, Msg} = UDPPacket ->
% find out if we need to spawn a new worker.
% typically, Workers is a gb_trees:tree().
{NewWorkers, Worker} = case gb_trees:lookup({Ip, Port}, Workers) of
none ->
NewWorkerPid = spawn_link(fun() -> worker_loop(Ip, Port) end),
{gb_trees:insert(NewWorkerPid, Workers), NewWorkerPid}
{value, WorkerPid} -> {Workers, WorkerPid}
end,
% send to worker.
Worker ! UDPPacket,
server_loop(NewWorkers);
% ... timeout callbacks from workers would go here
end.
person
Paul Guyot
schedule
19.05.2014