【问题标题】:Scala Chat Application, separate threads for local IO and socket IOScala 聊天应用程序,本地 IO 和套接字 IO 的单独线程
【发布时间】:2017-01-14 01:43:20
【问题描述】:

我正在用 Scala 编写一个聊天应用程序,问题出在客户端上,客户端在将数据发送到回显服务器之前从 StdIn(阻塞)读取,所以如果连接了多个客户端,那么它们不会收到从服务器读取数据,直到从 StdIn 读取完成。我在想本地 IO,即从 StdIn 读取和读取/写入套接字应该在单独的线程上,但我想不出办法做到这一点,下面是客户端单例代码:

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")
  }

}

下面是与Client单例结合使用的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()
}

【问题讨论】:

    标签: multithreading scala sockets io client


    【解决方案1】:

    您可以使用 Scala Akka Actors 添加并发性。在撰写本文时,当前的 Scala 版本是 2.11.8。在此处查看 Actor 文档:

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

    这个聊天示例很老,但演示了一种使用 Actors 处理大约一百万个同时客户端的技术:

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

    最后,您还可以使用 Google 搜索 Twitter Finagle 项目,该项目使用 Scala 并为服务器提供并发性。我认为学习它需要做很多工作......

    【讨论】:

      猜你喜欢
      • 2020-01-18
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 2016-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多