Sending object and commands to a server - java

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.

Related

Java Telnet Apache Commons: How to send functions keys?

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.

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.

Recommended way to call client's methods using TCP Socket

I'm writing a "Instant-Messaging software" using TCP server / client model using Java's socket API and I'm wondering what's the recommended way to call methods/functions of my clients from my server.
Currently I'm looking at sending a string over to my clients with a 3 characters in front of the string to allow my clients to determine what type of message it is.
For example:
Server sends a string, "MSGhelloworld" to its clients
Client splits the string into "MSG" and "helloworld"
Client executes the 3 character command, "MSG" using a switch statement
Then Client executes the corresponding method/function with "MSG" determining what method to execute and "helloworld" being the parameter for the method
I'm opened for any other recommended solutions and any UDP solutions as well, thank you.

NoMethodError: undefined method `bytesize' Sinatra

I get the error NoMethodError: undefined method 'bytesize' when I try to connect to my ruby sinatra server through java.
This is my ruby code, I suspect I need some sort of method, which runs when a client connects but I am not sure:
require 'sinatra'
get '/hello' do
'this page displays hello'
end
get '/' do
'this page is the main page'
end
And here is the code for my java application:
private static Socket connect;
private static OutputStream output;
private static InputStream input;
public static void main(String[] args) throws IOException {
System.out.println("Connecting...");
connect = new Socket(InetAddress.getByName("localhost"), 4567);
System.out.println("Connected to: " + connect.getInetAddress().getHostName());
output = new ObjectOutputStream(connect.getOutputStream());
output.flush();
//input = new ObjectInputStream(connect.getInputStream());
System.out.println("Streams ready");
}
I would guess this is happening because of a theory error in Rack in the following code, paired with a theory error in your Java client invocation of the Ruby server:
# Return the bytesize of String; uses String#size under Ruby 1.8 and
# String#bytesize under 1.9.
if ''.respond_to?(:bytesize)
def bytesize(string)
string.bytesize
end
else
def bytesize(string)
string.size
end
end
module_function :bytesize
That is in the file <rack>lib/rack/utils.rb ... which Sinatra uses, here:
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
That is in the file <sinatra>lib/sinatra/base.rb in the #finish method, in inside a check which tests calculate_content_length?
...anyway, there is no test for if string is Nil, in the #bytesize method... it's just doing a test to see whether the Ruby engine itself supports #bytesize.
In other words, I would guess your body is Nil, or an incompatible kind of Object, which does not have the #bytesize method, since Rack does not test, it just assumes the data coming into that method is good, and passes the method call onto that object, based purely on the underlying engine... not based on the user_agent. That's Rack's theory error.
Troubleshooting further, I would guess that there is either something which is user_agent specific in your Java code, not your Ruby code. And not even truly user_agent, because you don't seem to instantiate a 'browser' but just open a socket connection. I'd guess that you need to actually invoke the server through HTTP commands in a formal request, RFC compliant protocol, etc... so you need to send a syntactically correct header and body.
I've seen this sort of thing happen with strange clients, such as obscure crawlers which do not send correct headers, or send no body and only headers. I'd further further further guess that opening a Socket connection is not enough. You need to send headers and a body to the server. I'd finally guess that you could likely use a Java library which is like a curl or a wget and not just manipulating a raw socket. That would do the proper protocol chatter for you, and just give you back what you're looking for from your Ruby/Sinatra endpoints. Looking around on here a bit, I found:
cURL equivalent in JAVA

I am losing periods in an email sent using Java Mail

I am sending newsletters from a Java server and one of the hyperlinks is arriving missing a period, rendering it useless:
Please print your <a href=3D"http://xxxxxxx.xxx.xx.edu=
au//newsletter2/3/InnovExpoInviteVIP.pdf"> VIP invitation</a> for future re=
ference and check the Innovation Expo website <a href=3D"http://xxxxxxx.xx=
xx.xx.edu.au/2008/"> xxxxxxx.xxxx.xx.edu.au</a> for updates.
In the example above the period was lost between edu and au on the first hyperlink.
We have determined that the mail body is being line wrapped and the wrapping splits the line at the period, and that it is illegal to start a line with a period in an SMTP email:
https://www.rfc-editor.org/rfc/rfc2821#section-4.5.2
My question is this - what settings should I be using to ensure that the wrapping is period friendly and/or not performed in the first place?
UPDATE: After a lot of testing and debugging it turned out that our code was fine - the client's Linux server had shipped with a very old Java version and the old Mail classes were still in one of the lib folders and getting picked up in preference to ours.
JDK prior to 1.2 have this bug.
From an SMTP perspective, you can start a line with a period but you have to send two periods instead. If the SMTP client you're using doesn't do this, you may encounter the problem you describe.
It might be worth trying an IP sniffer to see where the problem really is. There are likely at least two separate SMTP transactions involved in sending that email.
I had a similar problem in HTML emails: mysterious missing periods, and in one case a strangely truncated message. JavaMail sends HTML email using the quoted-printable encoding which wraps lines at any point (i.e. not only on whitespace) so that no line exceeds 76 characters. (It uses an '=' at the end of the line as a soft carriage return, so the receiver can reassemble the lines.) This can easily result in a line beginning with a period, which should be doubled. (This is called 'dot-stuffing') If not, the period will be eaten by the receiving SMTP server or worse, if the period is the only character on a line, it will be interpreted by the SMTP server as the end of the message.
I tracked it down to the GNU JavaMail 1.1.2 implementation (aka classpathx javamail). There is no newer version of this implementation and it hasn't been updated for 4 or 5 years. Looking at the source, it partially implements dot-stuffing -- it tries to handle the period on a line by itself case, but there's a bug that prevents even that case from working.
Unfortunately, this was the default implementation on our platform (Centos 5), so I imagine it is also the default on RedHat.
The fix on Centos is to install Sun's (or should I now say Oracle's?) JavaMail implementation (I used 1.4.4), and use the Centos alternatives command to install it in place of the default implementation. (Using alternatives ensures that installing Centos patches won't cause a reversion to the GNU implmentation.)
Make sure all your content is RFC2045 friendly by virtue of quoted-printable.
Use the MimeUtility class in a method like this.
private String mimeEncode (String input)
{
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
OutputStream out;
try
{
out = MimeUtility.encode( bOut, "quoted-printable" );
out.write( input.getBytes( ) );
out.flush( );
out.close( );
bOut.close( );
} catch (MessagingException e)
{
log.error( "Encoding error occured:",e );
return input;
} catch (IOException e)
{
log.error( "Encoding error occured:",e );
return input;
}
return bOut.toString( );
}
I am having a similar problem, but using ASP.NET 2.0. Per application logs, the link in the email is correct 'http://www.3rdmilclassrooms.com/' however then the email is received by the client the link is missing a period 'http://www3rdmilclassrooms.com'
I have done all I can to prove that the email is being sent with the correct link. My suspicion is that it is the email client or spam filter software that is modifying the hyperlink. Is it possible that an email spam filtering software would do that?
Are you setting the Mime type to "text/html"? You should have something like this:
BodyPart bp = new MimeBodyPart();
bp.setContent(message,"text/html");
I am not sure, but it looks a bit as if your email is getting encoded. 0x3D is the hexadecimal character 61, which is the equals character ('=').
What classes/libary are you using to send the emails? Check the settings regarding encoding.
I had a similar problem sending email programmatically over to a yahoo account. They would get one very long line of text and add their own linebreaks in the HTML email, thinking that that wouldnt cause a problem, but of course it would.
the trick was not to try to send such a long line. Because HTML emails don't care about linebreaks, you should add your own every few blocks, or just before the offending line, to ensure that your URL doesn't get split at a period like that.
I had to change my ASP VB from
var html;
html = "Blah Blah Blah Blah ";
html = html & " More Text Here....";
to
var html;
html = "Blah Blah Blah Blah " & VbCrLf;
html = html & " More Text Here....";
And that's all it took to clean up the output as was being processed on their end.
As Greg pointed out, the problem is with your SMTP client, which does not do dot-stuffing (doubling the leading dot).
It appears that the e-mail is being encoded in quoted-printable. Switching to base64 (I assume you can do it with the current java mime implementation) will fix the problem.

Categories

Resources