2013-03-21 2 views
2

Я экспериментирую с удаленными актерами Akka, пытаясь установить простую игру с двумя игроками по сети. This answer к более раннему вопросу дал мне действительно хорошую отправную точку, но теперь мне трудно понять, как адаптировать его к моей ситуации. ISTM, что оригинал подключается дважды от одного и того же клиента (см. Следующий раздел). То, что я хочу сделать, это запустить его дважды от отдельных клиентов, но когда я это сделаю, я получаю BindException, адрес уже используется. Думаю, это потому, что каждый раз, когда я запускаю код, он пытается запустить сервер? Мне нужна ситуация, когда я могу начать и остановить главного актера независимо от подключения и отключения клиентов. (Минимальная) Акка конфигурация и исключение составляет после кода:Akka BindException при попытке подключения к удаленному игроку: Адрес уже используется

import akka.actor._ 
//example from answer to https://stackoverflow.com/questions/15527193/keeping-references-to-two-actors 
// by Patrick Nordwall 
case object JoinMsg 
case class Msg(s: String) 

class Server extends Actor { 

    def receive = { 
    case JoinMsg => 
     println("got player 1") 
     sender ! Msg("Waiting for player 2") 
     context.become(waitingForPlayer2(sender)) 
    } 

    def waitingForPlayer2(client1: ActorRef): Actor.Receive = { 
    case JoinMsg => 
     println("got player 2") 
     sender ! Msg("hi") 
     client1 ! Msg("hi") 
     context.become(ready(client1, sender)) 
    } 

    def ready(client1: ActorRef, client2: ActorRef): Actor.Receive = { 
    case m: Msg if sender == client1 => client2 ! m 
    case m: Msg if sender == client2 => client1 ! m 
    } 
} 

/* I want to run this once for each "player" */ 
object Demo extends App { 
    val system = ActorSystem("Game") 
    val server = system.actorOf(Props[Server], "server") 

    system.actorOf(Props(new Actor { 
    server ! JoinMsg 
    def receive = { 
     case Msg(s) => println(s) 
    } 
    })) 

    /* Rather than connecting twice from the same node, I want to run this 
    program twice from different nodes 
    system.actorOf(Props(new Actor { 
    server ! JoinMsg 
    def receive = { 
     case Msg(s) => println(s) 
    } 
    }))*/ 
} 

Config:

akka { 
    actor { 
    provider = "akka.remote.RemoteActorRefProvider" 
    } 
    remote { 
    transport = "akka.remote.netty.NettyRemoteTransport" 
    netty { 
     hostname = "localhost" 
     port = 9000 
    } 
} 
} 

Исключение:

Exception in thread "main" java.lang.ExceptionInInitializerError 
    at akkademo.main(akkademo.scala) 
Caused by: org.jboss.netty.channel.ChannelException: Failed to bind to: localhost/127.0.0.1:9000 
    at org.jboss.netty.bootstrap.ServerBootstrap.bind(ServerBootstrap.java:298) 
    at akka.remote.netty.NettyRemoteServer.start(Server.scala:54) 
    at akka.remote.netty.NettyRemoteTransport.start(NettyRemoteSupport.scala:90) 
    at akka.remote.RemoteActorRefProvider.init(RemoteActorRefProvider.scala:94) 
    at akka.actor.ActorSystemImpl._start(ActorSystem.scala:588) 
    at akka.actor.ActorSystemImpl.start(ActorSystem.scala:595) 
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:111) 
    at akka.actor.ActorSystem$.apply(ActorSystem.scala:93) 
    at akkademo$.<init>(akkademo.scala:4) 
    at akkademo$.<clinit>(akkademo.scala) 
    ... 1 more 
Caused by: java.net.BindException: Address already in use 

ТИА.

ответ

10

При запуске нескольких экземпляров на одном компьютере вам необходимо настроить для них разные порты. В этом примере только серверу нужен порт знаний (9000). Для клиентов вы можете использовать 0 для случайного порта.

Определите другой файл конфигурации для клиентов. client.conf:

akka { 
    actor { 
    provider = "akka.remote.RemoteActorRefProvider" 
    } 
    remote { 
    transport = "akka.remote.netty.NettyRemoteTransport" 
    netty { 
     hostname = "localhost" 
     port = 0 
    } 
} 
} 

Запустите ActorSystem на клиентах с этой конфигурацией:

import com.typesafe.config.ConfigFactory 
val system = ActorSystem("Game", ConfigFactory.load("client")) 

В клиентах вы будете искать сервер с:

val server = system.actorFor("akka://[email protected]:9000/user/server") 
+0

Спасибо, Патрик. Объявление 'system' дает мне ошибку: требуемый тип com.typesafe.config.Config. Я использую Akka 2.0.5 и scala 2.9. – jaybee

+0

Отлично, это работает для меня сейчас :-) Если кто-то пытается сделать то же самое, я скопировал с https://github.com/akka/akka/tree/v2.0.5/akka-samples/akka-sample -восстановитесь, чтобы сервер загрузился и работал. – jaybee

+1

кажется, что в настоящее время порт необходимо установить через 'akka.remote.netty.tcp.port', а не' akka.remote.netty.port'. – phdoerfler

3

вам необходимо либо указать порт для конфигурации клиента отдельно или изменить порт конфигурации на стороне сервера с 2552 на другое. 2552 - это порт по умолчанию для аккорных систем akka, когда вы создаете актерскую систему на стороне клиента для поиска (на том же компьютере), он также пытается привязать к порту 2552, если он явно не указан и, таким образом, вы получите эту ошибку.