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
Related
I'm pretty puzzled with this issue. I have an Apache Thrift 0.9.0 client and server. The client code goes like this:
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(this.transport);
this.client = new ZKProtoService.Client(protocol);
This works fine. However, if I try to wrap the transport in a TFramedTransport
this.transport = new TSocket(this.server, this.port);
final TProtocol protocol = new TBinaryProtocol(new TFramedTransport(this.transport));
this.client = new ZKProtoService.Client(protocol);
I get the following obscure (no explanation message whatsoever) exception in the client side. Server side shows no error.
org.apache.thrift.transport.TTransportException
at org.apache.thrift.transport.TIOStreamTransport.read(TIOStreamTransport.java:132)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.transport.TFramedTransport.readFrame(TFramedTransport.java:129)
at org.apache.thrift.transport.TFramedTransport.read(TFramedTransport.java:101)
at org.apache.thrift.transport.TTransport.readAll(TTransport.java:84)
at org.apache.thrift.protocol.TBinaryProtocol.readAll(TBinaryProtocol.java:378)
at org.apache.thrift.protocol.TBinaryProtocol.readI32(TBinaryProtocol.java:297)
at org.apache.thrift.protocol.TBinaryProtocol.readMessageBegin(TBinaryProtocol.java:204)
at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:69)
at com.blablabla.android.core.device.proto.ProtoService$Client.recv_open(ProtoService.java:108)
at com.blablabla.android.core.device.proto.ProtoService$Client.open(ProtoService.java:95)
at com.blablabla.simpleprotoclient.proto.ProtoClient.initializeCommunication(ProtoClient.java:411)
at com.blablabla.simpleprotoclient.proto.ProtoClient.doWork(ProtoClient.java:269)
at com.blablabla.simpleprotoclient.proto.ProtoClient.run(ProtoClient.java:499)
at java.lang.Thread.run(Thread.java:724)
It also fails if I use TCompactProtocol instead of TBinaryProtocol.
In the server side I have extended TProcessor with my own class since I need to reuse existing service handler (the service server-side IFace implementation) for this client:
#Override
public boolean process(final TProtocol in, final TProtocol out)
throws TException {
final TTransport t = in.getTransport();
final TSocket socket = (TSocket) t;
socket.setTimeout(ProtoServer.SOCKET_TIMEOUT);
final String clientAddress = socket.getSocket().getInetAddress()
.getHostAddress();
final int clientPort = socket.getSocket().getPort();
final String clientRemote = clientAddress + ":" + clientPort;
ProtoService.Processor<ProtoServiceHandler> processor = PROCESSORS
.get(clientRemote);
if (processor == null) {
final ProtoServiceHandler handler = new ProtoServiceHandler(
clientRemote);
processor = new ProtoService.Processor<ProtoServiceHandler>(
handler);
PROCESSORS.put(clientRemote, processor);
HANDLERS.put(clientRemote, handler);
ProtoClientConnectionChecker.addNewConnection(clientRemote,
socket);
}
return processor.process(in, out);
}
And this is how I start the server side:
TServerTransport serverTransport = new TServerSocket(DEFAULT_CONTROL_PORT);
TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(
serverTransport).processor(new ControlProcessor()));
Thread thControlServer = new Thread(new StartServer("Control", server));
thControlServer.start();
I have some questions:
Is it correct to reuse service handler instances or I shouldn't be doing this?
Why does it fail when I use TFramedTransport or TCompactProtocol? How to fix this?
Any help on this issue is welcome. Thanks in advance!
I was having the same problem and finally found the answer. It is possible to set the transport type on the server, though this is not clear from most tutorials and examples I've found on the web. Have a look at all of the methods of the TServer.Args class (or the args classes for other servers, which extend TServer.Args). There are methods inputTransportFactory and outputTransportFactory. You can use new TFramedTransport.Factory() as inputs to each of these methods to declare which transport the server should use. In scala:
val handler = new ServiceStatusHandler
val processor = new ServiceStatus.Processor(handler)
val serverTransport = new TServerSocket(9090)
val args = new TServer.Args(serverTransport)
.processor(processor)
.inputTransportFactory(new TFramedTransport.Factory)
.outputTransportFactory(new TFramedTransport.Factory)
val server = new TSimpleServer(args)
println("Starting the simple server...")
server.serve()
Note that if you are using a TAsyncClient, you have no choice about the transport that you use. You must use TNonblockingTransport, which has only one standard implementation, TNonblockingSocket, which internally wraps whatever protocol you are using in a framed transport. It doesn't actually wrap your chosen protocol in a TFramedTransport, but it does prepend the length of the frame to the content that it writes, and expects the server to prepend the length of the response as well. This wasn't documented anywhere I found, but if you look at the source code and experiment with different combinations, you will find that with TSimpleServer you must use TFramedTransport to get it to work with an async client.
By the way, it's also worth noting that the docs say that a TNonblockingServer must use TFramedTransport in the outermost later of the transport. However, the examples don't show this being set in TNonblockingServer.Args, yet you still find that you must use TFramedTransport on the client side to successfully execute an rpc on the server. This is because TNonblockingServer.Args has its input and output protocols set to TFramedTransport by default (you can see this using reflection to inspect the fields of the superclass hierarchy or in the source code for the constructor of AbstractNonblockingServerArgs -- you can override the input and output transports, but the server will likely fail for the reasons discussed in the documentation).
When the issue happens with framed, but it works without framed, then you have an incompatible protocol stack on both ends. Choose one of the following:
either modify the server code to use framed as well
or do not use framed on the client
A good rule of thumb is, to always use the exact same protocol/transport stack on both ends. In the particular case it blows up, because framed adds a four-byte header holding the size of the message that follows. If the server does not use framed, these additional four bytes sent by the client will be interpreted (wrongly) as part of the message.
Altough the sample code in that answer
TNonblockingServer in thrift crashes when TFramedTransport opens is for C++, adding framed on the server should be very similar with Java.
PS: Yes, it is perfectly ok to re-use your handler. A typical handler is a stateless thing.
I have a Python server that listens for json requests. The "receiving" section of the code looks like this:
while True:
next_message = conn.recv(1024)
response = Foo.do_some_stuff(next_message)
conn.send(response)
I built a Sinatra application that uses the Python API.
client = TCPSocket.new("localhost", 5000)
client.puts("foobar")
response = client.gets
All of the above code functions perfectly. Now, I'm doing something similar with some Java code.
Socket client = new Socket("localhost", 5000);
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(new client.getOutputStream(), true);
out.println("foobar");
String response = in.readLine();
The problem is that this code works for the first request, but on subsequent requests the Python server hangs, still waiting for the message. My question is what is the Ruby implementation of output stream appending to the message to signal the message's end that the Java implementation isn't?
Relevant details:
I'm using the Google Gson package in the Java code to create Json objects that I send to the Python server.
I'm using auto-flush on the PrintWriter.
I read that perhaps subsequent requests alter the size of the data being sent to the Python server - because of the underlying TCP protocol, and that the Python socket will keep listening until the connection ends or it's read 1024 bytes. This would make sense, except that the Ruby implementation works perfectly.
I've been digging through Java, Python, and Ruby docs for the past two days trying to figure this out. Any help would be greatly appreciated.
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.
I want to build a client-server-application for some practice. I started off with a simple chat which was not so hard to do. I'm also able to identify different commands by just simply split a String, e.g. "command:msg". But I think that may be a little inconvenient. So I'm wondering if there are better ways to realize that. And I stumbled over that side:
http://www.javaworld.com/jw-01-1997/jw-01-chat.html?page=6
At the very end it says:
An alternative, however, and much more elegant solution, is to abstract the protocol behind a set of stream classes. The specifics of header construction and insertion can be handled automatically by the stream classes, and the client is then left with much the same interface as before: Clients write messages to a stream, but instead of flushing the stream, they call a method that attaches appropriate headers and sends the encapsulated message.
I don't really know what is meant by that. Could somebody explain it, or even better, give me a code example. Perhaps there may are other ways to do?
Let's say you want to send messages encapsulated as the link you sent:
| ID | len | message contents |.
What they mean with "to abstract the protocol behind a set of stream classes" is to create classes that extend stream classes which will put the correct ID and length on the encapsulated message for you.
For example, for an extended PrintWriter where you send two kinds of message:
ID 1 - normal message.
ID 2 - error message.
class MyProtocolPrintWriter extends PrintWriter {
public static final int NORMAL_MESSAGE = 1;
public static final int ERROR_MESSAGE = 2;
//put the constructor
public void writeMessage(String message) {
println(
String.format(
"%02x%02d%s", NORMAL_MESSAGE, message.length(), message));
}
public void writeErrorMessage(String message) {
println(
String.format(
"%02x%02d%s", ERROR_MESSAGE, message.length(), message));
}
}
Here's what one fairly successful chat network used for a protocol.
Internet Relay Chat
And here's a list of the commands that were implemented using the IRC protocol.
List of Internet Relay Chat commands
You would implement these commands as a set of stream classes. The user issues a command, and your stream class handles the specifics of the header construction and insertion into the stream.
I am going to read from a socket in java. Here is what I am going to do:
System.out.println("Start Reading");
/* bab is socket connector */
/* and readLine is the method below.
/* public String readLine()throws IOException
{
String a = inStream.readLine();
return a;
}
*/
for( int j=0;j<9;j++)
{
response = bab.readLine();
System.out.println(response);
}
I see a lot of delay (2-3 seconds) between printing "start Reading" and first line of the response. But when I requested it with Firefox, it responsed quickly (20 ms). What is the problem? And how can I solve this problem?
I suspect the reason is the server doesn't send the line-delimiter for some time, so the readLine() method waits. I bet if you just do readByte() it must be quick.
As Firefox or any other browser wouldn't read line by line, it dosn't affect them.
Firefox is probably caching the response and is therefore able to display it very quickly to you. I suggest you clear the cache on Firefox and time it again.
If you are using a domain name for the call then Firefox will also cache the DNS lookup which could save time in Firefox whereas making the call in Java could require a DNS lookup.
If you are using Windows then download Fiddler which will allow you to monitor the HTTP connection and give you a better idea of what is happening.