Advertisement

How is a real-time server port "find" known to client code

Started by March 02, 2017 11:39 AM
51 comments, last by hplus0603 7 years, 8 months ago

The reason you pass both an address and a port number to bind(), is because a computer may have multiple network cards, and each network card has a separate IP address, and perhaps you only want to accept incoming connections on some particular network card. (Note that the "loopback" interface, used for "localhost" local connections, also counts as a "network card" or interface.)

If you just want to listen for connections on a particular port, on all available interfaces, you should set the address part to INADDR_ANY (which ends up resolving to 0.0.0.0)

If you're using Java, it may use slightly different names for functions and constants than the canonical sockets API. For example, if there's a constructor for a socket that takes only a port number, then perhaps that constructor already binds to that port. (This socket would then have to have an accept() method that actually returns new sockets for remote connections, if you're using TCP.)

If you're using C, you also have to use htons() when filling out the sockaddr_in struct. Java will likely do that for you.

Finally, it's important to know the difference between your network-local address (of the PC/workstation/server,) and the IP-public internet address (the address of your router or DNAT box.) In most situations these days, they are different, and the public interface (router) needs to be set up to "port forward" or "DMZ" incoming connections to the appropriate internal address of the server.

enum Bool { True, False, FileNotFound };

Many thanks, @[member='hplus0603'],

If you just want to listen for connections on a particular port, on all available interfaces,

i actually want the server to connect with client

Would appreciate if you could help spot why the code is not connecting. I am guessing it Shouldn't be complicated to look at for anyone who already experienced with this.

... ... with Android could even run a mini test

Many Thnx

can't help being grumpy...

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

Advertisement

i actually want the server to connect with client

No, you don't.

In general, that doesn't work, unless you treat your server as another client and use a second server for NAT introduction, which would be way more complexity than you need.

Even so, the client needs to be actively soliciting for connections to come in, for the NAT introducer to be able to introduce it. (See the STUN and TURN protocols for more information.)

And, because the client is already active, it might as well just talk directly to the server.

enum Bool { True, False, FileNotFound };

i actually want the server to connect with client

No, you don't.

In general, that doesn't work, unless you treat your server as another client and use a second server for NAT introduction, which would be way more complexity than you need.

Even so, the client needs to be actively soliciting for connections to come in, for the NAT introducer to be able to introduce it. (See the STUN and TURN protocols for more information.)

And, because the client is already active, it might as well just talk directly to the server.

That was an inadvertent error on my side, I meant it the other way round (client to server). Such glaring typos confirms I'm tired

I have had multiple replies to this post but none actually looks at the code

The problem, I reckon, is something in the code so subtle that I'm not seeing ... just need that to be pointed out (and will learn from it)

can't help being grumpy...

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

That was an inadvertent error on my side, I meant it the other way round (client to server). Such glaring typos confirms I'm tired
I have had multiple replies to this post but none actually looks at the code
The problem, I reckon, is something in the code so subtle that I'm not seeing ... just need that to be pointed out (and will learn from it)

Normally a server creates a socket you can think of as a listening socket, assuming we're talking TCP they then can connect to the socket. Connecting sets them in a sort of "waiting" state until you accept the connection through the listening socket. When you accept it, it gives you a socket that is connected to the client, you can then send and receive through that socket.

Setting up the listening socket usually means creating the socket(some basic information about the protocol it uses) then binding it (setting it to work on a certain port) and then setting it to listen(setting it to wait for connections and hold them.) Not sure how Java abstracts that away but that's how the socket libraries work at the bottom level.

The reason is likely that you have a bunch of Java UI Android code.

The advice people gave you is to write a small program, 20 lines or less each, that you believe should

a) Open a socket listening on a known port on the server

b) Connect to the server's IP and port from the client

Once you have those small programs, you should be able to start the server, then start the client, and see what's going on.

If that still doesn't help, then posting those two small programs here might give you a better chance of getting an answer.

That being said: The client has two variables named "sock," one of which is uninitialized and the other of which is created with an IP address, and a port value of 0. That should be the exact port value that you use when creating the server.

Your ServerSocket should not bind to port 0, because that means it will get a random port, and the client won't know which port to connect to.

enum Bool { True, False, FileNotFound };
Advertisement
The problem is you need to pick a port number for the server.

An analogy is the telephone system in a company, with extension numbers for each department. Imagine the server computer is "Servcom, Inc". The IP address is like the phone number, e.g. 555 - 123 4556. While in real life if you rang that number you'd get through to some general inquiries system. There is no equivalent system here, so imagine you need to know which department in advance. The extension numbers are going to be like ports.

Perhaps it has a "website" department. Most companies do, it is usually on extension 80. The maintenance department might be on extension 22. Servcom already has a "Gleeful Games" department, they happen to be on extension 5879.

Once you know the extension number, you can get through to the correct department. We're starting a new department, "Grumpy Games". This department needs an extension number - it doesn't matter what it is, it just needs to be unique for "Servcom, Inc.". We can use 22, that's taken by the maintenance department. But there are thousands of numbers that haven't been allocated yet!

In this analogy, when you look at netstat, one part of the output is all the extension numbers you can ring inside your current building. What you won't see is all the possible extension numbers that are available for new departments (there are too many to list).

So, pick a number. The server should listen on that port. The client should connect to that port on the server. Don't worry about the client's port. That is managed for you. In our utterly stretched analogy, perhaps the player is in building "Apartment 623, 7153 Plebian Way", or they could be across town in "1 Millionaire Row". Maybe there are many phones there, who knows. In " Servcom", it doesn't matter which building / extension is used to ring us, but once they do we'll see it in the caller ID and we can ring them back.

So choose a port. It is best to avoid common ports - If you choose port 80, then you cannot run a default web server at the same time, which might annoy some people who want to run your server. In your last post you mentioned 45210, so let's use that.

It would be easier to start a new project for the next part, a simple command line program for the server, and another for the client.

Make your server listen on that port (e.g. new ServerSocket(45210)). Remove the data transfer code until you definitely have these basics working. Test this by starting your server and using "telnet local host 45210" on the same machine. Your server should print that it got a connection!

Next, change your client to connect to port 45210 on the server (new Socket(serverIp, 45210)). Remove the file transfer - just connect and disconnect. Start your server and test that the client can connect successfully.

Next, change your server to print the number of bytes it received. Test again.

Change the client to send "Hello, World".getBytes(). Test again.

Keep testing and changing small bits, and gradually build up to the data transfer. This will help you focus on solving one issue at a time.

Once you have all this working as you expect, then start to change your android application to do the same.
Also, typically your server should be written to handle multiple clients at once, and can avoid freezing if one client is slow.

Your current server code processes a single request only. Might be OK if you have a strictly two player game, but ideally you want to be robust in the case some other software happens to connect to the server port.

In any case, it will be annoying for testing if you have to restart the server every time you want to change the client!

I must stress security oriented thinking. What if the client sends you a malformed image? Or what if the client has a bug, or has its connection dropped. Make any code on the server that loads robust in the face of failure!

What about if the client sends a malicious executable instead of an image? The server owner might accidentally run the executable when investigating why the "image" won't load.

Make sure the file system path you're saving to is expected. Right now it is hard-coded, which is fine. If you cahbge that, make sure that the remote client cannot pick the path. For example, if the clients eventually have usernames, it would be dangerous to use this username as the name of a directory or file. A malicious client could say their username is something like "../../../path/to/your/pictures/parents", and overwrite your "parents.jpg" file, and this is a fairly mild example.

You can never be too paranoid when you are doing network programming - you cannot know who is on the other end of that socket, sending those bytes!

Thanks @[member='rip-off'], et al.

@[member='hplus0603'], Yeah, I had changed from 0 to using an actual port number. It was trying to "diagnose" the blocking issue that made me experiment with that idea anyway.

Generally speaking i also took on the advice most people gave: that I should start with very small application sending only text rather than an image file and narrow down the area where the problem is. To be fair to myself what I posted is actually as small as it can get because the Android code included with the socket code was just enable me to select any image file from the phone's Gallery. But nonetheless I stripped all that away and changed the data to text. But the issue remained. In fact at this stage I was 100% sure the line responsible for the blocking is sock = new Socket(serverIP, port); (in the client code)

I then placed a try-catch around it and I got


java.net.ConnectException: failed to connect to /192.168.1.2 (port 52059): connect failed: ETIMEDOUT (Connection timed out) 

At this stage i thought once I keep googling connectException ETIMEDOUT its only a matter of time that i would find the solution to it. But I was wrong about that. Following suggestions, I turned off all firewalls, restarted IDE, rebooted machine... so far all to no use

Does anyone have experience or suggestions to solve this connection exception?

The security issue rip_off mentioned is extremely important, but I need to small -once this works at this level - i would build security up gradually

can't help being grumpy...

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

if you can't connect to port 52059 on host 192.168.1.2, then there is no process running on 192.168.1.2 listening on port 52059 running, or the address 192.168.1.2 is not routable from the client's network interface.

You should be able to verify whether a server is actually running and listening by using a telnet client. On Windows, download putty. Set it up to connect using telnet protocol, to host 192.168.1.2, to port 52059. If the server is correctly running and listening on that address, it should see a connection when you open that window. For Linux and MacOS, there are command-line Telnet clients, so "telnet 192.168.1.2 52059" in the Terminal should do it.

If your client is not on the same network as the server (i e, using mobile data, or is on a guest network,) then you cannot connect to the local address of the server; you have to set up port forwarding on your internet modem/router, and connect to the public address of the modem.

Finally, when debugging networking code, you'll want to use a good packet sniffer to see what's actually going on. I like Ethereal, which is available for most platforms. Linux also has tcpdump built in (a command-line option.)

enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement