0. Introducción
Para establecer comunicación mediante java sockets, se requiere un servidor que esté a la escucha y un cliente que lo llame.
El servidor puede responder y se puede establecer un diálogo entre cliente y servidor.
Hay que definir un número de puerto de conexión
Se puede implementar cliente y servidor en la misma máquina o en máquinas distintas.
Lo importante a remarcar és como se ejecuta un proceso en modo ASÍNCRONO y como se utilizan "Piped Streams", para recoger la información generada por el proceso a medida que se ejecuta.
1. pom.xml
Veamos el fichero
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ximodante</groupId> <artifactId>SocketServer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SocketServer</name> <description>SocketServer</description> <properties> <maven.compiler.source>15</maven.compiler.source> <!-- 13,12 --> <maven.compiler.target>15</maven.compiler.target> <!-- 13, 12 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <lombok.version>1.18.18</lombok.version> <commons-io.version>2.8.0</commons-io.version><!-- abans 2.6 --> <commons-exec.version>1.3</commons-exec.version> <lang3.version>3.11</lang3.version> <!-- OK Antes 3.10, 3.9 --> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons-io.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${lang3.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-exec</artifactId> <version>${commons-exec.version}</version> </dependency> </dependencies> <!-- COMPILER PLUGIN --> <!-- This is OK http://crunchify.com/how-to-create-build-java-project-including-all-dependencies-using-maven-maven-resources-maven-dependency-maven-jar-plugin-tutorial/ --> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <!-- <release>13</release> --> <!-- compilerArgs>..enable-preview</compilerArgs --> <!-- CAMBIAR . POR - --> <showWarnings>true</showWarnings> <showDeprecation>true</showDeprecation> </configuration> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <id>copy-resources</id> <phase>validate</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${basedir}/target/MiCarpeta</outputDirectory> <resources> <resource> <directory>resources</directory> <filtering>true</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.1.2</version> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/MiCarpeta/lib</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>u.requests.sockets.SimpleSocketServer</mainClass> </manifest> <manifestEntries> <Class-Path>.</Class-Path> </manifestEntries> </archive> <finalName>MiCarpeta/socketserver</finalName> </configuration> </plugin> </plugins> </build> </project>
Solamente remarcar:
- versión de java
- librerias
- compilación a jar
2. El cliente (SimpleSocketClienteExample.java)
1. Saber la IP del servidor y el puerto
2. Tener un canal de entrada (o recepción) de los mensajes del servidor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | package u.requests.sockets; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import lombok.NoArgsConstructor; /** * A client caller to server * @author eduard * */ @NoArgsConstructor public class SimpleSocketClientExample { private Socket clientSocket; private PrintWriter out; private BufferedReader in; public SimpleSocketClientExample(String ip, int port) { } /** * starts a connection to the server to a port * @param ip * @param port * @throws UnknownHostException * @throws IOException */ public void startConnection(String ip, int port) throws UnknownHostException, IOException { clientSocket = new Socket(ip, port); out = new PrintWriter(clientSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); } public String sendMessage(String msg) throws IOException { System.out.println("Sending to server:"+ msg); out.println(msg); //out.println("repeat "+msg); String resp=""; String line = in.readLine(); if (line!=null) resp=resp + "\n" + line; while (line != null && line.length() > 0 ) { resp=resp + "\n" + line; System.out.println("linea client:"+line); line = in.readLine(); } //out.println(""); // Para terminar rl dendfmessage return resp; } public void stopConnection() throws IOException { in.close(); out.close(); clientSocket.close(); } public static void main (String[] args) throws IOException { SimpleSocketClientExample client = new SimpleSocketClientExample(); String ip="192.168.10.5"; int port=6666; //client.startConnection("127.0.0.1", 6666); if (args!=null && args.length==2) { ip=args[0]; port=Integer.parseInt(args[1]); } client.startConnection(ip, port); String response =""; for (int i=0;i<3;i++) { response = client.sendMessage("hello serverKK-->"+i); //assertEquals("hello client", response); //System.out.println("hello server ->" + response); //response = client.sendMessage(""); //System.out.println("hello server ->" + response); } response = client.sendMessage(""); //System.out.println("hello server ->" + response); client.stopConnection(); } } |
3. El servidor
3.1. SimpleSocketServer.java
package u.requests.sockets; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; import utils.PropertiesUtils; /** * Only open port for serving messages The important part is the access to * ServerRequestHandler03 that manages all the logic * * @author ximo * */ public class SimpleSocketServer extends Thread { private boolean isExecutedFromJar = false; // ????? Cambiar al compilar private ServerSocket serverSocket; private int port; private boolean running = false; // private String propsFileName="properties"+File.separator+"app.properties"; private Properties props = null; public SimpleSocketServer() { port = 6666; } public void getMyPort() { try { props = PropertiesUtils.getProperties(isExecutedFromJar, "app"); port = Integer.parseInt(props.getProperty("socket.port", "" + port)); } catch (Exception e) { e.printStackTrace(); } } public void startServer() { try { serverSocket = new ServerSocket(port); this.start(); } catch (IOException e) { e.printStackTrace(); } } public void stopServer() { running = false; this.interrupt(); } @Override public void run() { running = true; // This is for accepting multiple connections while (running) { try { System.out.println("System.out.println-->Listening for a connection"); // Call accept() to receive the next connection Socket socket = serverSocket.accept(); // socket.getPort(); // Pass the socket to the RequestHandler thread for processing ServerRequestHandler requestHandler = new ServerRequestHandler(socket, props); requestHandler.start(); } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { SimpleSocketServer server = null; try { server = new SimpleSocketServer(); if (args != null) { if (args.length > 0) { if (args[0].trim().length() > 0) server.isExecutedFromJar = true; } } server.getMyPort(); System.out.println("SimpleSocketServer03.Start server on port: " + server.port); server.startServer(); /* * // Automatically shutdown in 1 minute try { Thread.sleep( 60000 ); } catch( * Exception e ) { e.printStackTrace(); } */ } catch (Exception e) { if (server != null) { server.stopServer(); System.out.println("server stopped"); e.printStackTrace(); } } } }
3.2. ServerRequestHandler.java
package u.requests.sockets; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintWriter; import java.net.Socket; import java.util.Properties; import utils.CmdUtils; class ServerRequestHandler extends Thread { private Socket socket; private String command = ""; // private String myPath=""; private String shellsFolder = ""; private String jarsFolder = ""; private String javaPath = ""; private Properties props = null; private Boolean isError = false; private BufferedReader inSocket = null; private PrintWriter outSocket = null; private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); public ServerRequestHandler(Socket socket, Properties props) { this.socket = socket; this.props = props; } @Override public void run() { PipedOutputStream out = new PipedOutputStream(); PipedInputStream in = new PipedInputStream(); try { System.out.println("RH-->Received a connection"); // Get input and output streams inSocket = new BufferedReader(new InputStreamReader(socket.getInputStream())); outSocket = new PrintWriter(socket.getOutputStream(), true); command = inSocket.readLine(); outSocket.println("4.1 Des del server: Obtenint comandament a executar...(" + command + ")"); if (command.trim().length() < 2) showError("ERROR: Comandament curt:(" + command + ")"); else { try { shellsFolder = props.getProperty("shells.folder").trim(); jarsFolder = props.getProperty("jars.folder").trim(); javaPath = props.getProperty("java.path").trim(); // command=myPath.trim() + File.separator+ command; command = command.replace("JAVA_PATH", javaPath).replace("SHELLS_FOLDER", shellsFolder) .replace("JARS_FOLDER", jarsFolder); System.out.println("COMMAND=" + command); } catch (Exception e) { showError("ERROR : Obrint paràmetres del fitxer de propietats... app.properties" + e.getMessage()); } } if (!isError) { outSocket.println("4.2 Des del server: Executant...(" + command + ")"); try { out.connect(in); // Execute and wait for end of execution // if(CmdUtils.execProgram(command, null, null, false, outputStream) !=0) // showError("ERROR 4: Executant " + command + "... "); // Asynchronous if (CmdUtils.execProgram(command, null, null, true, out) != 0) showError("ERROR 4: Executant " + command + "... "); } catch (Exception e) { showError("ERROR 4.2: Executant " + command + "... " + e.getMessage()); } } if (!isError) { outSocket.println("4.3 Des del server: Informant ..."); try { byte[] bt = in.readNBytes(1); int i = 0; String line = ""; while (bt.length > 0) { line = line + (char) bt[0]; if (line.contains("\n")) { String lineUP = line.toUpperCase(); if (lineUP.contains("SHOWMESS") || lineUP.contains("ERROR")) { outSocket.println("4.3." + ++i + "-->" + line); System.out.println("4.3." + i + "-->" + line); } line = ""; } // else System.out.println("KKKKKKK="+line); bt = in.readNBytes(1); } } catch (Exception e) { showError("ERROR 4.3: Executant " + command + "... " + e.getMessage()); } } if (!isError) outSocket.println("FIN:"); // END OF PROCESS SIGNAL!! // Close our connection inSocket.close(); outSocket.close(); socket.close(); System.out.println("Rh:->Connection closed"); } catch (Exception e) { e.printStackTrace(); } } private void showError(String message) { isError = true; outSocket.println(message); } }
3.3. CmdUtils.java
package utils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandler; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.exec.PumpStreamHandler; /** * Utility class for executing programs locally and remotely * * @author eduard * */ public class CmdUtils { /** * * @param commandLine Line to execute * @param optSuccessValue (Optional) If the success return is not equal * to "0". For instance Acrobat returns 1 * @param optMaxDurationMiliSecs (Optional) Maximum wait until kill the program * if blocked, * @param isAsync True if we want to execute the command * asynchronously * @param outputStream OutputStream to collect the output * messages of the program * * @return * @throws ExecuteException * @throws IOException */ public static int execProgram(String commandLine, Integer optSuccessValue, Long optMaxDurationMiliSecs, Boolean isAsync, OutputStream outputStream) throws ExecuteException, IOException { int exitValue = 0; ExecuteWatchdog watchdog = null; CommandLine cmdLine = CommandLine.parse(commandLine); DefaultExecutor executor = new DefaultExecutor(); if (outputStream != null) { PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream); executor.setStreamHandler(streamHandler); } if (optSuccessValue != null) executor.setExitValue(optSuccessValue); if (optMaxDurationMiliSecs != null) { watchdog = new ExecuteWatchdog(optMaxDurationMiliSecs); executor.setWatchdog(watchdog); } if (isAsync != null && isAsync) executor.execute(cmdLine, new DefaultExecuteResultHandler()); else exitValue = executor.execute(cmdLine); return exitValue; } public static void main(String[] args) { String[] commandLines = { "/usr/bin/java -version", "java -version", "ls /home/eduard/", "/usr/bin/AutoFirma sign -i /home/ximo/kk/xmlprueba.xml -o /home/ximo/kk/xml_firma103.xsig -format xades -store mozilla -alias EPN1" }; int i = 0; try { for (String s : commandLines) { System.out.println(i++ + "-->" + s); execProgram(s, null, null, null, outputStream); int j = 0; for (String line : outputStream.toString().split("\\n")) System.out.println("Action:" + i + "." + ++j + "-->" + line); } catch (Exception e) { e.printStackTrace(); } } }