2016-09-06 1 views
0

Я пишу чат-приложение в Scala, проблема с клиентами, клиент читает из StdIn (который блокирует) перед отправкой данных на сервер эхо-сигналов, поэтому, если несколько клиентов подключены, то они не получают данные с сервера до тех пор, пока чтение из StdIn не завершится. Я имею в виду, что местный IO, то есть чтение из STDIN и чтения/записи в сокет должен быть в отдельных потоках, но я не могу придумать способ сделать это, ниже код клиента синглтон:Приложение Scala Chat, отдельные потоки для локального ввода-вывода и гнезда IO

import java.net._ 
import scala.io._ 
import java.io._ 
import java.security._ 

object Client { 

    var msgAcc = "" 

    def main(args: Array[String]): Unit = { 
    val conn = new ClientConnection(InetAddress.getByName(args(0)), args(1).toInt) 
    val server = conn.connect() 
    println("Enter a username") 
    val user = new User(StdIn.readLine()) 
    println("Welcome to the chat " + user.username) 
    sys.addShutdownHook(this.shutdown(conn, server)) 
    while (true) { 
    val txMsg = StdIn.readLine()//should be on a separate thread? 
    if (txMsg != null) { 
     conn.sendMsg(server, user, txMsg) 
     val rxMsg = conn.getMsg(server) 
     val parser = new JsonParser(rxMsg) 
     val formattedMsg = parser.formatMsg(parser.toJson()) 
     println(formattedMsg) 
     msgAcc = msgAcc + formattedMsg + "\n" 
     } 
    } 
    } 

    def shutdown(conn: ClientConnection, server: Socket): Unit = { 
    conn.close(server) 
    val fileWriter = new BufferedWriter(new FileWriter(new File("history.txt"), true)) 
    fileWriter.write(msgAcc) 
    fileWriter.close() 
    println("Leaving chat, thanks for using") 
    } 

} 

ниже класс ClientConnection используется совместно с Клиентом одноточечного:

import javax.net.ssl.SSLSocket 
import javax.net.ssl.SSLSocketFactory 
import javax.net.SocketFactory 
import java.net.Socket 
import java.net.InetAddress 
import java.net.InetSocketAddress 
import java.security._ 
import java.io._ 
import scala.io._ 
import java.util.GregorianCalendar 
import java.util.Calendar 
import java.util.Date 
import com.sun.net.ssl.internal.ssl.Provider 
import scala.util.parsing.json._ 

class ClientConnection(host: InetAddress, port: Int) { 

    def connect(): Socket = { 
    Security.addProvider(new Provider()) 
    val sslFactory = SSLSocketFactory.getDefault() 
    val sslSocket = sslFactory.createSocket(host, port).asInstanceOf[SSLSocket] 
    sslSocket 
    } 

    def getMsg(server: Socket): String = new BufferedSource(server.getInputStream()).getLines().next() 

    def sendMsg(server: Socket, user: User, msg: String): Unit = { 
    val out = new PrintStream(server.getOutputStream()) 
    out.println(this.toMinifiedJson(user.username, msg)) 
    out.flush() 
    } 

    private def toMinifiedJson(user: String, msg: String): String = { 
    s"""{"time":"${this.getTime()}","username":"$user","msg":"$msg"}""" 
    } 

    private def getTime(): String = { 
    val cal = Calendar.getInstance() 
    cal.setTime(new Date()) 
    "(" + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE) + ":" + cal.get(Calendar.SECOND) + ")" 
    } 

    def close(server: Socket): Unit = server.close() 
} 

ответ

0

Вы можете добавить параллелизм с помощью Scala AKKA Актеры. На момент написания этой статьи текущая версия Scala - 2.11.8. См Actor документации здесь:

http://docs.scala-lang.org/overviews/core/actors.html

Этот пример чат старый, но демонстрирует технику для обработки в окрестностях миллиона одновременных клиентов с помощью Актеры:

http://doc.akka.io/docs/akka/1.3.1/scala/tutorial-chat-server.html

Наконец, вы можете также Google проект Twitter Finagle, который использует Scala и предоставляет серверы с параллелизмом. Много работы, чтобы узнать это, я думаю ...