3

Please consider the following example (using 2 R sessions):

1st R session - R Server

library(svSocket)
startSocketServer()

2nd R session - R Client

library(svSocket)
con <- socketConnection(host = "localhost", port = 8888, blocking = FALSE)

value<-"setosa"
evalServer(con, tmp, value) # first call to the server
evalServer(con, head(iris[iris$Species==tmp,])) # second call to the server
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

To send the above query I need a 2-step process where I first save my parameter in the server and then I use them to query the table.

Problem

Do the same in one step only. For example, building the query using paste and send it to the server like I would in PHP + MySQL. Basically, I need to avoid that a different user overwrites tmp between the first and the second call to the server. The above commands will be running behind web apps with 30 to 50 users simultaneously connected, so I reckon that this inconvenience might happen.

Michele
  • 8,563
  • 6
  • 45
  • 72
  • Take look at [Rserve](http://www.rforge.net/Rserve/). There's also a [php library](https://github.com/cturbelin/rserve-php) for it. I think it will (heh) serve you better than the `svSocket' approach as it was really intended as a GUI back-end connection. Also, since you're familiar with R, why not just use Shiny? – hrbrmstr Mar 30 '14 at 12:11
  • 1
    @hrbrmstr I already have a rApache implementation. I have simply no time to switch to a different technology. I chose this because it makes R behave like PHP and others, which means people can start to see R as a general purpose language... something I'd really love to happen! – Michele Mar 30 '14 at 12:31

1 Answers1

2

One possible answer

$ query <- paste0('evalServer(con,"head(iris[iris$Species==\'', value,'\',])")')
$ eval(parse(text=query))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

This does the job but it's kind of a dial... The code is very messy and difficult to read.

Final solution:

I ended up modifying/simplifying evalServer. This version accept only a character string with the expression to evaluate in the server

evalServer2 <- function (con, expr) 
{
  if(!is.character(expr)) stop("expr must be a character string containing the expression to evaluate in the server.")
  cat("..Last.value <- try(eval(parse(text = \"", expr, "\"))); .f <- file(); dump(\"..Last.value\", file = .f); flush(.f); seek(.f, 0); cat(\"\\n<<<startflag>>>\", gsub(\"<pointer: [0-9a-fx]+>\", \"NULL\", readLines(.f)), \"<<<endflag>>>\\n\", sep = \"\\n\"); close(.f); rm(.f, ..Last.value); flush.console()\n", 
      file = con, sep = "")
  objdump <- ""
  endloc <- NULL
  while (!length(endloc)) {
    obj <- readLines(con, n = 1000, warn = FALSE)
    if (!length(obj)) {
      Sys.sleep(0.01)
      next
    }
    endloc <- grep("<<<endflag>>>", obj)
    if (length(endloc)) 
      obj <- obj[0:(endloc[length(endloc)] - 1)]
    objdump <- c(objdump, obj)
  }
  startloc <- grep("<<<startflag>>>", objdump)
  if (!length(startloc)) 
    stop("Unable to find <<<startflag>>>")
  objdump <- objdump[-(1:startloc[length(startloc)])]
  nospace <- grep("[^ ]$", objdump)
  nospace <- nospace[nospace < length(objdump)]
  for (i in rev(nospace)) {
    objdump[i] <- paste(objdump[i], objdump[i + 1], sep = "")
    objdump[i + 1] <- ""
  }
  objcon <- textConnection(objdump)
  on.exit(close(objcon))
  source(objcon, local = TRUE, echo = FALSE, verbose = FALSE)
  return(..Last.value)
}

which allows:

> x <- "5 + 4"
> evalServer2(con, x)
[1] 9

Instead, evalServer would retrieve a variable called x stored in the R server

> evalServer(con, x, 23)
[1] TRUE
> evalServer(con, x)
[1] 23
> evalServer2(con, "x")
[1] 23
Michele
  • 8,563
  • 6
  • 45
  • 72