Tuesday, April 28, 2009

Opening a PHP to Java socket

In a project I've been working on recently we needed to integrate a functionality we have in a few Java classes we developed in to a PHP script. If those specific classes could be wrapped in a simple command-line app, it would not have been a problem, as you can execute command-line apps from PHP easily. But! These specific Java classes took very long time to load (around two seconds!) before they could be used. So command-line app was out of question, because two seconds delays for every command-line execution are unacceptable when dealing with thousands of calls a day, so the solution was to load the app once and to use the already running application when needed.

How do you use a running Java application from PHP code? A quick (and dirty?) solution is sockets. In this case the Java app is the server and PHP is the client. Ok, lets take a look at some code (Links to the sources are at the bottom of the page).

The Java server class looks like this:



public class MyJavaServer {
public static void main(String[] args) {
int port = 20222;
ServerSocket listenSock
= null; //the listening server socket
Socket sock = null; //the socket that will actually be used for communication

try {

listenSock
= new ServerSocket(port);

while (true) { //we want the server to run till the end of times

sock
= listenSock.accept(); //will block until connection recieved

BufferedReader br
= new BufferedReader(new InputStreamReader(sock.getInputStream()));
BufferedWriter bw
= new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
String line
= "";
while ((line = br.readLine()) != null) {
bw.write(
"PHP said: " + line + "\n");
bw.flush();
}

//Closing streams and the current socket (not the listening socket!)
bw.close();
br.close();
sock.close();
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}


What it does:
Opens a listening (server) socket which waits for incoming connections on port 20222 in an endless loop. As soon as a connection is received the socket's input and output streams are "turned" in to buffered reader and writer (so they can be manipulated in an easier and more effective way).
Afterward we read line by line the incoming message, add a "PHP said: " prefix to each line we received and then send it back to the client. After the incoming message is over we close the buffered reader, writer and the socket, and wait for another incoming connection.

Note: It's important that you add a end-of-line char ("\n") to the end of the reply when you are writing to the socket, as the PHP client finishes reading when it encounters the end-of-line char.

The PHP client looks like this:



$PORT = 20222; //the port on which we are connecting to the "remote" machine
$HOST = "localhost"; //the ip of the remote machine (in this case it's the same machine)

$sock = socket_create(AF_INET, SOCK_STREAM, 0) //Creating a TCP socket
or die("error: could not create socket\n");

$succ = socket_connect($sock, $HOST, $PORT) //Connecting to to server using that socket
or die("error: could not connect to host\n");

$text = "Hello, Java!"; //the text we want to send to the server

socket_write(
$sock, $text . "\n", strlen($text) + 1) //Writing the text to the socket
or die("error: failed to write to socket\n");

$reply = socket_read($sock, 10000, PHP_NORMAL_READ) //Reading the reply from socket
or die("error: failed to read from socket\n");

echo $reply;


What it does:
We define a port (20222 - the port that MyJavaServer listens on) and a host we want to connect to (localhost is our own machine, change to a specific IP to connect remote machines). Create a socket descriptor ($sock), and connect the socket to the "remote" host (the $succ variable is used to check if the connection was successful). Afterward we write the contents $text to the socket, and then read the server's reply. The PHP_NORMAL_READ flag tells the socket_read() function to read until the first end-of-line char.

Notes:
* Make sure you add an end-of-line ("\n") to the string you send to the server, as the server reads until it encounters the end-of-line char.
* Don't forget to add 1 to the length of the string you are sending so that the added end of line will actually be sent.

Conclusion:
There's nothing new in this code neither for "Javers" nor PHPers. The novelty here (for me anywayz) is the interaction between the codes, which on the other makes perfect sense because of the fact that sockets on both utilize the same protocol - in this case TCP/IP.

If you still have questions please ask! If you have comments, well, comment :D

Sources: php_java_sock.zip

19 comments:

  1. Excellent, just what i was working on, great help!

    ReplyDelete
  2. this is the best and most simple explanation I discovered. PHP and Java linkage via sockets is very exciting. For my case, I don't want to risk having my server IP running in my client Java application, so I am using another medium server running php scripts to establish socket connection to the Java server.

    ReplyDelete
  3. Thanks :)
    Good to hear you guys found it helpful. Hope I'll have the time to reformat the code colors soon so it's more readable

    ReplyDelete
  4. Thanks a lot! You explain better than the professors at UPR.

    ReplyDelete
  5. Simple and concise ...

    ReplyDelete
  6. Thanks for this article, I was wondering if this communication is doable and you showed me the way!

    ReplyDelete
  7. @Anonymous you're very welcome :)
    For general knowledge, this type of communication is possible between any two languages supporting the TCP protocol.

    ReplyDelete
  8. Thanks a lot man. You are a life saver :)

    ReplyDelete
  9. exactly what i am looking for. Thanks a bunch!

    ReplyDelete
  10. Thank y so much, i have success connecting but miss /n end message.

    ReplyDelete
    Replies
    1. Very welcome :)
      It should be "\n" though, and not "/n"

      Delete
    2. I know that, my keyboard miss this character *,*

      Delete
    3. Are you on windows or linux?

      Delete
  11. I like the way you explain this topic
    thank you

    ReplyDelete
  12. I like the way you explain this topic
    thank you

    ReplyDelete
  13. great code, and perfect explanation. nothing simpler than this.

    ReplyDelete
  14. Hii! Great code, can you help me with one thing.
    I send multiples sockets write from php to java, and no problem, but I can't manage to send one data to php.

    JAVA // I get Every message
    while ((line = reader.readLine()) != null){
    System.out.println("MSG: "+line);
    }
    writer.write("Thank you"+"\n"); //Can't send this message
    writer.flush();

    PHP
    foreach ($_POST as $key => $val){
    $send = $key . ':' . $val;
    socket_write($sock, $send."\n", strlen($send) + 1) or die("error: failed to write to socket\n");
    //Every message is send
    }

    $reply = socket_read($sock, 10000, PHP_NORMAL_READ) or die("error: failed to read from socket\n"); //I have one reply because I only want to recieve one message.


    When I send an echo from the java server it works, I mean 3 MSG PHP -> Java and Java sends me all messages back to php but I want to send 3 MSG form PHP to Java and Recieve 1 MSG form JAVA to PHP.

    Please help me.

    ReplyDelete