Advertisement

How to unblock a server wait (in code) without stopping the server run

Started by April 09, 2017 03:52 AM
15 comments, last by hplus0603 7 years, 7 months ago

I'm not familiar with Android development, but typically processes on the same machine can talk to one another on the loopback address.

If I were you, I'd think about just writing some non-Android based networking applications to experiment and get familiar with the topic, adding Android and Emulators into the mix is only going to make things a little harder. Writing small console applications is a great way to learn, trying to do your learning by building your desired functionality in an already complex application is a recipe for lots of unrelated issues to slow you down.


Why is it that despite the practical advantage of NIO api for tcp, their examples are not so common on the internet? In fact every time I every time I've searched I've ended up with the simplistic and impractical type of examples that I ended up following

Well blocking I/O still has a place for simple use cases. For example, if you want to make a quick web request as part of a larger program, then a non-blocking solution would actually be quite complicated - particularly if you want to use the result immediately. Just throwing a quick timeout on a blocking request can be acceptable.

The audience of examples on the Internet is people new to the subject of networking. Better to start with the basics, sockets, ports, hostnames, etc in the simpler environment of blocking I/O. Examples typically try to get to the core of what is being taught, and actually try to avoid being too large as it can distract from the subject at hand. One suspects that sometimes the people who write these examples are often just graduated from being beginners themselves.

I'm not familiar with Android development, but typically processes on the same machine can talk to one another on the loopback address.

If I were you, I'd think about just writing some non-Android based networking applications to experiment and get familiar with the topic, adding Android and Emulators into the mix is only going to make things a little harder. Writing small console applications is a great way to learn, trying to do your learning by building your desired functionality in an already complex application is a recipe for lots of unrelated issues to slow you down.

Hmm... I see your point.

Yeah, I think that should be a better way to go

Well blocking I/O still has a place for simple use cases. For example, if you want to make a quick web request as part of a larger program, then a non-blocking solution would actually be quite complicated - particularly if you want to use the result immediately. Just throwing a quick timeout on a blocking request can be acceptable. The audience of examples on the Internet is people new to the subject of networking. Better to start with the basics, sockets, ports, hostnames, etc in the simpler environment of blocking I/O. Examples typically try to get to the core of what is being taught, and actually try to avoid being too large as it can distract from the subject at hand. One suspects that sometimes the people who write these examples are often just graduated from being beginners themselves.

Ah... get it

thanks

can't help being grumpy...

Just need to let some steam out, so my head doesn't explode...

Advertisement

But since I've been told I've got to use NIO classes (which is even harder than what i've done already and worse still, to me- it's like starting all over again)


If your code is clean, this is not such a big change. After all, your file loading and saving should be completely separate.

However, it's standard to use regular blocking I/O for Android networking since you're usually only making one call at a time, in a background thread. Not so much so for servers, perhaps. But nobody claimed this was introductory-level material.

For learning purposes I need to test some stuff exclusively on Android devices.


No, really you want to test everything on a desktop PC where you have full control of the environment.

1. Is it possible to use IP 127.0.0.1 to run a client->server loopback on the same android device (not on emulator)?


Android devices are not designed to act as servers.

2. Could both Client and Server run in the same application on same device? ( asking because most devices at the moment can run only one app at time. And since client and server can't run as separate app but have to run in the same application)


Yes, but that's an order of magnitude more complex than doing what you've been trying so far.

3. Could port numbers be used with mobile devices


The whole internet works with port numbers. TCP/IP doesn't care whether a device fits in your pocket or not.

If your code is clean, this is not such a big change. After all, your file loading and saving should be completely separate.

A big relieve to read this, ... means I don't have to discard what i coded already to accommodate NIO api. So lately I started doing some digging on NIO, nothing solid yet...

You create an InputStreamReader around the InputStream, and then a BufferedReader around that, but then you go back to reading from the InputStream directly later. I'm pretty sure you were warned not to do this in a previous thread, because some of your data can get 'lost' inside the BufferedReader.

I was trying to restructure my code as you advised, but I see that i need BufferedReader instance to read a line of string-text. Because Client sends a string-text data first before sending the file (image or text). i.e


          BufferedReader br = new BufferedReader(isr);
          String number = br.readLine();

I would have used InputStream only but on right-clicking on it and checking the doc I see no methods for reading a line of string/text. I know the string is still bytes but since it shouldn't mix with the file bytes I'm thinking String number = br.readLine(); reads the string-text separately while InputStream is; is.read(...); Is then dedicated to reading the file bytes.

In essence it means not using BufferReaderObject.readLine() means I can't separately read the string text

I'm writing my understanding of this but like to be corrected so i can do it right.

can't help being grumpy...

Just need to let some steam out, so my head doesn't explode...

I see that i need BufferedReader instance to read a line of string-text


Here's the problem: The other end may be sending "This is line 1\nThis is line 2\n" as two lines of text.
The underlying network may split that into the packets: "This ", "is line 1\nT", "his", " is line 2" and "\n"
(or any other way)
So, when you receive the first packet, you may or may not have a full string yet.
When you use a BufferedReader, and synchronous I/O, your program will wait for the full line to arrive in the thread that runs the BufferedReader code.
This is why a lot of Java code uses one thread per socket/client, and it performs poorly, AND it requires threading which causes bugs in programs that aren't 100% thread-safe.

What high-performance programs do is take over serialization themselves. They keep their own input buffer. Each time they get some data and extend the buffer, they check the buffer for whether it contains one (or more) full frames of data, and then extracts and processes those frames. (And then remove the parsed data from the head of the buffer -- a ring buffer is often useful.)
What enterprise applications that don't care about performance do, is use Java built-in serialization. However, that way lies network packets that are multiple kilobytes just to send the data "hello, world!" AND it's usually a big security hole, so I would strongly recommend against trying that route.
enum Bool { True, False, FileNotFound };
What high-performance programs do is take over serialization themselves. They keep their own input buffer. Each time they get some data and extend the buffer, they check the buffer for whether it contains one (or more) full frames of data, and then extracts and processes those frames. (And then remove the parsed data from the head of the buffer -- a ring buffer is often useful.) What enterprise applications that don't care about performance do, is use Java built-in serialization. However, that way lies network packets that are multiple kilobytes just to send the data "hello, world!" AND it's usually a big security hole, so I would strongly recommend against trying that route.

I would like to follow your advice except that the second half of your post is a little bit too high level for me to translate back to "how to fix it", or better said I don't know how to construct the the fix.

For instance as said in previous post, I'd like to use just InputStream as you and Kylotan advice, but how do I know how to read the first part of the received data separately form the second. (I'm avoiding the word "line", but still I need to separate the string data part from the file data stream part). Do I specify the exact number of bytes for the first dataset(string) and the second dataset (image file)? A little bit of pseudocode (2 ... 3 lines) will be highly appreciated.

As a complete starter (in this branch of computing) I've always thrived when I see a little bit of snippet/APIs ex, otherwise I have no clue.

Using only Inputstream instance, how do I avoid lumping the two data together? How do I see the end of the first part and the start of the second part?

Many thanks in advance

can't help being grumpy...

Just need to let some steam out, so my head doesn't explode...

Advertisement

how do I know how to read the first part of the received data separately form the second


When you call the native "receive()" function on the socket, it will return as much or little data as is available (but at least one byte.)
Thus, even if you ask for 1000 bytes, if there's only 3 bytes arrived, you will get 3 bytes.
The main problem with the original Java sockets is that you don't actually get access to that underlying native behavior, and thus old-school Java programs do terrible things like spawn a thread, which just asks for one byte at a time from a socket.
(As you can imagine, this generates garbage like crazy on the heap!)
Yes, it turns out, the creators of Java weren't super-humans who never made mistakes :-)

If you use java.net.Socket, and then call getInputStream(), then you may be able to check how much to ask for by calling available().
Thus, your "scan for input" would call available(), and then read that many bytes into your input buffer array.

However, it's better to use java.nio and tie a SocketChannel to the socket and set the SocketChannel in non-blocking mode.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement