Основная проблема заключается в том, что, когда ваш основной поток завершает работу, все остальные потоки уничтожаются автоматически.Вы должны заставить основной поток ждать receiveMessages thread
, иначе он, скорее всего, просто завершит работу, прежде чем будут получены какие-либо ответы.Один простой способ сделать это - использовать MVar
.
. MVar
- это синхронизированная ячейка, которая может быть пустой или содержать ровно одно значение.Текущий поток заблокируется, если он попытается извлечь из пустого MVar
или вставить в полный.В этом случае нам не важно само значение, поэтому мы просто сохраним ()
.
Начнем с пустого MVar
.Затем основной поток разветвляется из потока получателя, отправляет все пакеты и пытается получить значение из MVar
.
import Control.Concurrent.MVar
main = withSocketsDo $ do
-- prepare socket, same as before
done <- newEmptyMVar
-- we need to pass the MVar to the receiver thread so that
-- it can use it to signal us when it's done
forkIO $ receiveMessages sock done
-- send pings, same as before
takeMVar done -- blocks until receiver thread is done
В потоке получателя мы получим все сообщения, а затемвставьте ()
в MVar
, чтобы сигнализировать, что мы закончили получать.
receiveMessages socket done = do
-- receive messages, same as before
putMVar done () -- allows the main thread to be unblocked
Это решает основную проблему, и программа отлично работает на моем ноутбуке с Ubuntu, но есть еще паравещи, о которых вы хотите позаботиться.
sendTo
не гарантирует отправку всей строки.Вам нужно проверить возвращаемое значение, чтобы увидеть, сколько было отправлено, и повторить попытку, если не все было отправлено.Это может произойти даже для короткого сообщения, например "ping"
, если буфер отправки заполнен.
recv
требует подключенного сокета.Вместо этого вы захотите использовать recvFrom
.(Хотя он все еще работает на моем ПК по неизвестной причине).
Печать на стандартный вывод не синхронизирована, поэтому вы можете изменить это, чтобы использовать MVar
сообщить количество полученных пакетов вместо ()
.Таким образом, вы можете сделать весь вывод из основного потока.Также можно использовать другой MVar
в качестве мьютекса для управления доступом к стандартному выводу.
Наконец, я рекомендую прочитать документацию Network.Socket , Control.Concurrent и Control.Concurrent.MVar тщательно.Большая часть моего ответа собрана из информации, найденной там.