Java Telnet Apache Commons: How to send functions keys? - java

I am programming a Java connection to a server using the Apache commons telnet library. I have modified the example code at
http://www.java2s.com/Code/Java/Network-Protocol/ExampleofuseofTelnetClient.htm
to connect to our server and preform tests. Everything seems to work fine but I cannot figure out how to send function key presses over telnet.
After using a sniffer with our IBM 3151 emulator for the function key 'F9' I got the value: '/033i/r', but simply just typing this in does not work. I figure it is just sending those text characters when I simply type them.
I'd imagine that I just missing something simple but I cannot seem to find any information after searching for a few hours.

After searching for a bit longer I found that I had to send the ASCII hex characters in a byte array to the outputStream of the telnet session that corresponded to the terminal type I was using.
Thus to send '/033i/r' which is the code for the function key: 'F9', I created the following byte array:
byte[] toSend = new byte[] { (byte)0x1b, (byte)0x69, (byte)0x0d } ;
So you need to know which terminal emulation you are using for your telnet connection, and what the function keys map too.

Related

Send message through Socket Outputstream from Swift Client to Java Server

As the title says, I'm having some problems connecting my Swift Client to a Java Server by using only native libraries.
Right now I have a Java(client) to Java(server) connection, which works flawlessly, and a Swift(client) to Java(server) connection. My Swift client does connect to the Java server (it shows on the console), but the readFully of my server hangs - the only thing I see is the enormous message length on the console and that's pretty much it.
Swift Code (send):
func send(message: String) {
let data = "msg:\(message)".data(using: .utf8)!
data.withUnsafeBytes {
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
print("Error joining chat")
return
}
out!.write(pointer, maxLength: data.count)
}
}
Java Server (read):
int lenght = in.readInt();
System.out.println("Message: " + lenght);
if(length>0){
byte[] message = new byte[length];
in.readFully(message), 0, message.length); //This is where the problem is
}
So, basically the Java server hangs on the readFully method. Any ideas why that is? Whether I send a simple String or a Byte array, it always hangs, and for some reason the length is extremely big. Can someone help me understand what I'm doing wrong because I've around this for days and still didn't understand it (still pretty new to Swift).
Thank you very much!
In your Java code, you expect the first 4 bytes to be the length of the message, but in the Swift code, you didn't send the length of the message first. You sent the message itself directly. So now the Java code is left confused as to why the message is shorter than it expected, and waiting for more data to read.
You can try sending the number of bytes in data first:
let byteCountAsByteArray = withUnsafeBytes(of: Int32(data.count).bigEndian, Array.init)
out!.write(byteCountAsByteArray, maxLength: 4)
out!.write(pointer, maxLength: data.count)
I suspect that you are using a DataInputStream in your Java code, hence .bigEndian. But if you are reading this in a little endian way, use .littleEndian instead.

Data read through socket on a remote server is empty

We have a client-server software made in java.
Client part sends a string:
dataOutputStream.writeUTF("User");
Server reads this string:
String login = dataInputStream.readUTF();
System.out.println("User accepted: " + login);
The server part is launched on amazon ec2.
We have 2 offices and from 1 office everything works fine:
server accepts the socket and read the data correctly,
but from another office the server accepts the socket, however reads empty strings.
All the ports are opened for our IPs in the EC2 control panel.
I have installed WireShark and checked if correct data goes to the server and yes, it is correct.
Both offices are running the same client part.
The only difference i know is that office 1 have Win 7 and 8 (works on both, tried different machines) and office 2 have Win 10 (doesn't work, tried different machines)
What could be the reason of such behavior? What we could check / try to resolve it?
DataInputStream.readUTF() cannot possibly return an empty String, by which I assume you mean a String object whose length() is zero, unless an empty string was presented to writeUTF() at the other end. It can however throw an EOFException if the data has somehow been truncated in flight.
You'll have to post some code to elucidate this further.

Socket communication between Java and C# application

I have 02 applications, one is written in java and the another one is written in C#. I need to exchange data (Strings) between them thus I use a socket connection.
Currently the C# application acts as server and java application acts as client. The C# application will continuously listen on port "7777" and the Java application will make a socket to "localhost:7777" as start up and use that socket to send data to C# server. I don't close the connection between them since I need to exchange data frequently.
Everything is great until my C# server application sometimes needs to send some Strings to the Java client application. I think about using another port to make my java application becomes a server and the C# application will also become a client. Yet I don't feel that it is a good solution.
P/S: Yes, socket is Bi-direction, in my current application I can send string data from my C# application back to Java application, but only when the Java application first sent a string to the C# application and now it is waiting for the respond data from the C# application.
Thus I want to ask if there is another better solution ? Is it possible if we only use 1 port in total ? Thank you very much.
Your socket works both ways (bi-directional), so you won't need to create another. You can just get the output stream and input stream of the socket, on both sides of the connection, and use those for sending/receiving.
To send a string, the easiest way would probably be to use a DataOutputStream as you can write UTF-8 strings with a simple function.
Java side:
String blah = "hey";
DataOutputStream dataOs = new DataOutputStream(socket.getOutputStream());
dataOs.writeUTF(blah);
The C# side is slightly trickier as you need to account for the fact that the first two bytes sent from the java function writeUTF() will actually be the length (in bytes) of the string that follows. You can grab those 2 bytes first and then throw them into an int, shifting the bits as you go along. Then you can use that int as the size of the buffer when you request the string from the socket. Should look something like this.
C# side:
int length = 0;
byte[] sizeBuffer = new byte[2];
socket.Receive(sizeBuffer);
for (int i = 0; i < sizeBuffer.Length; i += 1)
{
length = length << 8;
length += sizeBuffer[i];
}
byte[] stringBuffer = new byte[length];
socket.Receive(stringBuffer);
string myString = Encoding.UTF8.GetString(stringBuffer, 0, stringBuffer.Length);

How to read ganglia information from other application?

I have managed to install and configure Ganglia on my cluster. I do not want to just see all performance data on ganglia web interface but instead I want to read cluster information from other application (application may be Java or Python based). I am not able to find if it is possible or not.
Is there any API to read Ganglia data?
To test Ganglia I used telnet master 8649 and Ganglia showed me nice XML text on my console. But how do I do the same thing using Java or Python? I can definitely connect to 8649 using sockets but after that do I need to send something to Ganglia daemons?
I can help you to get an insight on this. But before that I must tell you, I am not a Java programmer, rather I am a C/C++ programmer. So, it means I can let you know, how things work in ganglia and you can find equivalent methods in Java/ Python to rewrite the codes you want.
Please be informed that there is no API in ganglia to achieve what you want to.
First consider below set up of ganglia to understand properly:
GS1 and GS2 are collecting system metrics and pushing them to GM.
So, according to your question, if you want to collect all such metrics by your own Java/ Python based application, then you may have to install the application on the Master server (i.e Replace GS with your own application).
GS1 and GS2 sends all collected metrics either by UDP unicast channel or UDP multicast channel. It is recommended that UDP unicast should be enabled in every gmond.conf for easier scalability.
I wouldn't discuss much on GS1 and GS2 as your question is more about replacing GM with your own tool.
GM uses two important libraries heavily to establish a UDP connection and translate data into its own readable format. They are APR (Apache Portable Runtime) to establish UDP connection and perform related activities and XDR (External Data Representation) to send data across networks and perform RPC.
You need to find APR and XDR equivalent libraries in Java and Python first. XDR is already available in Java and APR could be replaced by your own basic implementation to perform inter-network operations (i.e., create UDP socket, etc).
Open gmond.c source file of ganglia and go to line 1436. You will find a C function:
static void process_udp_recv_channel(const apr_pollfd_t *desc, apr_time_t now).
This function basically performs "UDP connection establishment" and "data translation into readable format" activities.
The call flow of the above function is shown below:
Now, let's expand the function at line 1436 to understand more.
The first argument in this function carries network parameters such as IP, Port, etc. The structure is expanded below. You can find similar object in Java also.
struct apr_pollfd_t {
apr_pool_t *p; /**< associated pool */
apr_datatype_e desc_type; /**< descriptor type */
apr_int16_t reqevents; /**< requested events */
apr_int16_t rtnevents; /**< returned events */
apr_descriptor desc; /**< #see apr_descriptor */
void *client_data; /**< allows app to associate context */
};
The second parameter has nothing to do, if SFLOW is disabled.
So, Start with creating a APR pool, UDP connection, etc.
socket = desc->desc.s;
channel = desc->client_data;
apr_pool_create(&p, global_context);
status = apr_socket_addr_get(&remotesa, APR_LOCAL, socket);
status = apr_sockaddr_info_get(&remotesa, NULL, remotesa->family, remotesa->port, 0, p);
/* Grab the data */
status = apr_socket_recvfrom(remotesa, socket, 0, buf, &len);
if(status != APR_SUCCESS)
{
apr_pool_destroy(p);
return;
}
apr_sockaddr_ip_buffer_get(remoteip, 256, remotesa);
/* Check the ACL */
if(Ganglia_acl_action( channel->acl, remotesa) != GANGLIA_ACCESS_ALLOW)
{
apr_pool_destroy(p);
return;
}
All declarations of variable can be found in the beginning of the function expanded (line 1439 to 1456).
Then, create XDR stream:
xdrmem_create(&x, buf, max_udp_message_len, XDR_DECODE);
Flush the data of the struct which saves metadata and metrics value:
memset( &fmsg, 0, sizeof(Ganglia_metadata_msg));
memset( &vmsg, 0, sizeof(Ganglia_value_msg));
fmsg (Ganglia_metadata_msg) and vmsg (Ganglia_value_msg) struct definitions can be found in gm_protocol.h header file. Re-write them in Java.
Then, figure out if the message received is "metadata" or "metrics values".
xdr_Ganglia_msg_formats(&x, &id); // this function is located in the source file gm_protocol_xdr.c and this file is generated by rpcgen.
Note: rpcgen is a rpc compiler and its explanation can be found in this question.
Note: Here is the link for gm_protocol_xdr.c.
Here, id is an enum and its declaration is shown below:
enum Ganglia_msg_formats {
gmetadata_full = 128,
gmetric_ushort = 128 + 1,
gmetric_short = 128 + 2,
gmetric_int = 128 + 3,
gmetric_uint = 128 + 4,
gmetric_string = 128 + 5,
gmetric_float = 128 + 6,
gmetric_double = 128 + 7,
gmetadata_request = 128 + 8,
};
typedef enum Ganglia_msg_formats Ganglia_msg_formats;
Based on the value of id, you can determine what kind of value the packets have.
For this purpose, this function calls an another function (which is in fact generated by rpcgen) to determine the kind of value the packet has and if found, it translates it to human readable format too.
The function is:
xdr_Ganglia_value_msg(&x, &vmsg);
You can find the full expansion of this function in gm_protocol_xdr.c from line 275.
After that you can do whatever you would like with these packets.
In the end, you must free all XDR variables and APR pools allocated.
I hope this gives you a fair idea to start with your own application.

Sending object and commands to a server

I'm new to Java socket programming, looking for a good approach to send either commands or objects to a server via Java sockets. The objects shall be stored on the server, the commands shall request data from the server.
At first the server doesn't know what he receives in the input stream, so he has to examine it, but I'm not sure how to do that. I would take the input stream, convert it to a String and then check the first chars to decide if they form a command or not. The problem I have is that InputStream.toString() returns something like
java.net.SocketInputStream#437d51a6
Thanks for your opinions and ideas.
Here is my first bad approach:
String input = inputStream.toString(); // this doesn't work
String startString =
input.toString().substring(0, Math.min( input.toString().length(),3));
if(startString.equals(COMMAND)){
// process command, e.g. to request data from the server
}
else {
// extract object to send data to the server
}
There is nothing wrong with "simple" text commands. Have a look at SMTP or HTTP, it's just plain text.
And there is a good reason for that: You can just telnet into your server, and type in the commands. This is a great help, because you can query your server without a special client.
Example for telnet into a local web server (I just typed in "GET /")
$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
GET /
<html>
<body>
<h1>Welcome on xxx</h1>
</body>
</html>
Connection closed by foreign host.
Further your service is not tied to a special language or a special binary format respectively.
I have found out how this works. The trick is to wrap the inputStream into a Scanner object like this:
Scanner s = new Scanner(inputStream);
String str = s.nextLine();
One approach may be creating classes for data types as well as for commands.
You can then use writeObject method of ObjectOutputStream ( http://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html ) to send command/data to server using default Java serialization (that's assuming that needed classes are also present in the server classpath).
Server can then get them from ObjectInputStream and easily act accordingly to their type. You will have to cast them from Object type, but you can check their real type using .getClass() or instanceof if you need to.

Categories

Resources