Edited after comment on proper use of SO_REUSEADDR
I want to use same port for both inbound and outbound connections in java
The purpose is to make a node in distributed environment. But in Tcp I need to use two different ports for accepting and initiating connections.
// accept incoming connection on one port
ServerSocket.accept()
// connect to remote, the port used will be different from the one used for accepting
Socket.connect()
Now the problem is:
A starts listening on port a. B on b and C on c.
when A connects B (Using Socket.connect()), A & B will keep the socket open for future message passing.
B still doesn't know the port A is listening on because the the port from which b received the connection is different from a.
when C connects B, B gives the socket address of A to C, But that port is a bound by a Socket() instance which doesn't have a accept() method
Of course, A can inform B about the port it is listening, but isn't there a direct way?
How can I make this test to pass?
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DualSocketTest {
ExecutorService service= Executors.newFixedThreadPool(10);
int echoServerport=8080;
int localServerport=8090;
#Test
public void testConnectivity() throws IOException {
// create a echo server on port 8080
startEcho();
// create a local Server instance
ServerSocket localServer=new ServerSocket();
// set the reuseAddress to true
localServer.setReuseAddress(true);
// bind the serverSocket
localServer.bind(new InetSocketAddress(localServerport));
// create a socket to connect the echo server using the same port used by localServer
Socket socket = new Socket();
socket.setReuseAddress(true);
// but this will throw SocketBindException
socket.bind(new InetSocketAddress(localServerport));
socket.connect(new InetSocketAddress(echoServerport));
// write hello
socket.getOutputStream().write("Hello !".getBytes());
byte[] result=new byte[100];
// receive hello
String ans=new String(result,0,socket.getInputStream().read(result));
System.out.println("Server replied with : "+ans);
// what was written and what was received must be same.
assert(ans.equals("Hello !"));
}
// start a echo server listening on the specified port
private void startEcho() throws IOException {
ServerSocket echoServer=new ServerSocket(echoServerport);
service.submit(()->{
try {
while(!echoServer.isClosed()) {
Socket socket = echoServer.accept();
System.out.println("connected with :" + socket.getInetAddress().toString() + ":" + socket.getPort());
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
service.submit(() -> {
while (socket.isConnected()) {
try {
outputStream.write(inputStream.read());
} catch (IOException e) {
break;
}
}
System.out.println("The Client has closed connection.");
});
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread.yield();
}
// Write something to the socket.
}
There is no such problem in when I previously used udp. The same socket supports receive() and send() method. For udp, sharing address is easy.
when A connects B, B would save the socketAddress of A,
When C connects B, B would send the address of A to C and C would connect to A
Edit: WON'T WORK IN JAVA
SO_REUSEADDR option shall be set on a socket before binding. I initially did my tests in Python (no access to a Java environment) and following script worked without errors on a Windows 10 system:
import socket
serv = socket.socket() # set a listening socket
serv.bind(('0.0.0.0',8080))
serv.listen(5)
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0',8080))
s.connect(('127.0.0.1', 8090))
with another process listening on port 8090
Unfortunately, in Java setReuseAddr javadoc says explicitely (emphasize mine):
Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even though a previous connection is in a timeout state.
For reasons I cannot guess, Java is more restrictive here. What looks even more weird, is that according to this other question it used to be allowed on older JRE versions (up to JRE 7U5)
Original (and wrong) post follows:
The trick is to set the SO_REUSEADDR option before binding. That means that you will need to use a parameterless constructor for both ServerSocket et Socket. More or less:
ServerSocket localServer = new ServerSocket();
localServer.setReuseAddress(true);
localServer.bind(InetSocketAddress(localServerport));
... // Ok listening...
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.bind(InetSocketAddress(localServerport));
socket.connect(...);
That way you can connect from your local listening port so that the peer will know how to reconnect after the connection will be closed.
Beware: untested...
I've fixed your test - hope that it's the way you wanted it to be. Take a look at the code here:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class DualSocketTest {
ExecutorService service = Executors.newFixedThreadPool(10);
int echoServerport = 8080;
int localServerport = 8080;
#Test
public void testConnectivity() throws IOException {
// create a echo server on port 8080
startEcho();
// create a socket to connect the echo server using the same port used by localServer
Socket socket = new Socket();
// but this will throw SocketBindException
socket.connect(new InetSocketAddress(echoServerport));
// write hello
socket.getOutputStream().write("Hello !".getBytes());
socket.getOutputStream().flush();
byte[] result = new byte[100];
// receive hello
String ans = new String(result, 0, socket.getInputStream().read(result));
System.out.println("Server replied with : " + ans);
// what was written and what was received must be same.
assert (ans.equals("Hello !"));
}
// start a echo server listening on the specified port
private void startEcho() throws IOException {
ServerSocket echoServer = new ServerSocket(echoServerport);
service.submit(() -> {
try {
while (!echoServer.isClosed()) {
Socket socket = echoServer.accept();
System.out.println("connected with :" + socket.getInetAddress().toString() + ":" + socket.getPort());
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
service.submit(() -> {
while (socket.isConnected()) {
try {
byte[] buffer = new byte[1024];
int read = -1;
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
} catch (IOException e) {
break;
}
}
System.out.println("The Client has closed connection.");
});
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread.yield();
}
// Write something to the socket.
}
Related
I came across a relatively simple java code while trying to design a Tcp PortScanner. The following code checks for the listening ports available on the local machine.
I wonder what kind of scan it uses to check its status, i mean is it using Tcp Syn scan , or Tcp connect scan or anything other than this. I'm grateful for your response.
import java.net.*;
import java.net.InetAddress;
import java.net.Socket;
class PortScanner {
public static void main(String []args) {
for (int port = 1; port <= 65535; port++) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("localhost", port), 1000);
socket.close();
System.out.println("Port " + port + " is open");
} catch (Exception ex) {
}
}
}
}
First off, networking is not my strongest subject. So sorry if this question is ridiculous, or if I'm missing some major information. I'd be happy to provide any needed.
I am trying spoof a server program. The program I am trying to pretend to be basically creates a local server, then allows client versions of the same program to connect (provided they are on the same computer).
Using netstat -a -b -n I was able to figure out that the server was binding itself to 0.0.0.0:53640. The other information given was:
Proto: UDP
Local Address: 0.0.0.0:56426
Foreign Address: * : * (Without spaces, stackoverflow doesn't seem to like this when it doesn't have them)
State: (Was blank)
The closest I was able to come was
Proto: TCP
Local Address: 0.0.0.0:56426
Foreign Address: 0.0.0.0:0
State: LISTENING
The code that I am using is:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Main2
{
public static void main(String args[])
{
String ip = "0.0.0.0";
int port = 53640;
try
{
InetAddress address = InetAddress.getByName(ip);
ServerSocket server = new ServerSocket(port, 5, address);
System.out.println("Waiting for connection...");
Socket socket = server.accept();
System.out.println("Got connection!");
doSocket(socket);
server.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void doSocket(Socket socket)
{
try
{
System.out.println("Connection from: " + socket.getInetAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream());
int b;
char c;
while ((b = in.read()) != -1)
{
c = (char) b;
System.out.print(c);
}
in.close();
out.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
ServerSocket.accept seems to never stop yielding, as "Got connection!" is never printed to the output.
All help is very welcome. Thanks in advance! And sorry if I've done something horribly wrong with this post, its my first one.
UDP is connection-less, and 'ServerSocket' is connection-oriented and TCP-only. Have a look at the Oracle docs on datagrams (UDP).
UDP ports and TCP ports are in different namespaces; you can't get mixups from one to the other.
Well, here's my code:
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TcpServerEcho {
public static void main(String argv[]) {
int port = Integer.parseInt(argv[0]);
ServerSocket server_socket = null;
try {
InetAddress thisIp = InetAddress.getByName("kiravaio.homepc.it");
System.out.println(thisIp.getHostAddress());
//or
//server_socket = new ServerSocket(port, 10, InetAddress.getByName("79.47.49.68"));
server_socket = new ServerSocket(port, 10, thisIp);
}
catch (Exception e) {
System.err.println("Impossible to create socket server!");
System.out.flush();
System.exit(1);
}
System.out.printf("Server active on port: %d and on address %s\n", port, server_socket.getInetAddress());
Socket client_socket = null;
boolean exec = true;
while(exec) {
try {
client_socket = server_socket.accept();
InputStream is = client_socket.getInputStream();
OutputStream os = client_socket.getOutputStream();
boolean stop = false;
System.out.println("Received: ");
while(!stop) {
int b = is.read();
System.out.print((char)b);
if(b == -1) {stop = true;}
else {os.write( (byte)b );}
}
}
catch (IOException ioe) {
System.err.println("Error I/O!");
} finally {
try {
client_socket.close();
}
catch (IOException ioe) {}
}
System.out.println("");
}
try {
/* Never executed */
server_socket.close();
} catch (IOException ioe) {}
}
}
There's no way for me to create a socket on my public ip.
I have a domain
kiravaio.homepc.it
always updated everytime my ip public changes.
So as first, I get my ip address with
InetAddress thisIp = InetAddress.getByName("kiravaio.homepc.it");
then I create the socket:
server_socket = new ServerSocket(port, 10, thisIp);
But it always fails and I don't know why,
Only creating a socket on 127.0.0.1 works!
:(
Looking up homepc.it reveals this is a dyndns service domain name. That domain name is resolving to the IP of your router not your PC.
Your PC will have a private network IP address (e.g. 192.168.1.x) assigned to it by your router (that IP is being used by your PC to talk to your router which is performing NAT (Network Address Translation)) .
You have to bind to that address (or simply use the constructor for ServerSocket that only takes a port; this will bind to 0.0.0.0 (INADDR_ANY) and listen on all interfaces), and configure your router to forward the port you have chosen to that IP address.
(If you don't know how to do that, you should consult your router's manual or perhaps post a question to https://superuser.com/)
I strongly believe that for ServerSocket, you don't need to specify which ip address is going to be used, just do new ServerSocket(port) and the client should be able to connect via your dynamic domain.
A server software my client communicates with regularly sends transaction messages on port 4000. I need to print those messages to the console line by line. (Eventually I will have to write those values to a table, but I’m saving that for later.)
I tried this code but it doesn’t output anything:
package merchanttransaction;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ClassNotFoundException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class MerchantTransaction {
public static void main(String[] args) {
try {
InetAddress host = InetAddress.getLocalHost();
Socket socket = new Socket("192.168.1.104", 4000);
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
String message = (String) ois.readObject();
System.out.println("Message: " + message);
ois.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
By the way, I need to be able to monitor that port until the program terminates. I’m not sure if the code above will be able to do that because I don’t see any iteration to the code.
I’m using Java version 1.6.0_24, SE Runtime Environment (build 1.6.0_24-b07) running on Ubuntu.
You need to use a ServerSocket. You can find an explanation here.
What do you actually want to achieve? What your code does is it tries to connect to a server located at 192.168.1.104:4000. Is this the address of a server that sends the messages (because this looks like a client-side code)? If I run fake server locally:
$ nc -l 4000
...and change socket address to localhost:4000, it will work and try to read something from nc-created server.
What you probably want is to create a ServerSocket and listen on it:
ServerSocket serverSocket = new ServerSocket(4000);
Socket socket = serverSocket.accept();
The second line will block until some other piece of software connects to your machine on port 4000. Then you can read from the returned socket. Look at this tutorial, this is actually a very broad topic (threading, protocols...)
Try this piece of code, rather than ObjectInputStream.
BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream ()));
while (true)
{
String cominginText = "";
try
{
cominginText = in.readLine ();
System.out.println (cominginText);
}
catch (IOException e)
{
//error ("System: " + "Connection to server lost!");
System.exit (1);
break;
}
}
Do I have to close all the sockets after using it? Where should I put them in this code? My program just works normally when I run it. However, when I re-run it, it said "Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind". Therefore, I think I did not close all the socket after using it.
import java.io.*;
import java.net.*;
import java.util.*;
public class Server2 {
public static void main(String args[]) throws Exception {
int PORT = 5555; // Open port 5555
//open socket to listen
ServerSocket server = new ServerSocket(PORT);
Socket client = null;
while (true) {
System.out.println("Waiting for client...");
// open client socket to accept connection
client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
}
}
}
Call server.close() in a finally block.
ServerSocket server = new ServerSocket(PORT);
try {
while (true) {
System.out.println("Waiting for client...");
// open client socket to accept connection
Socket client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
}
} finally {
server.close();
}
Address already in use: JVM_Bind - means, that you operation system is not closed socket after previous use. It closes on timeout about 30-180 seconds.
I don't realy know how to do this in java, but in C code it may be done like this, before bind system function call:
int yes = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
That mean: set the flag (option) SO_REUSEADDR to sockfd socket.
In java must exists appropriate mechanism for do the same.
You are running an infinite while loop , have a boolean variable to say when to stop , i think you are not exiting gracefully, that is why port is not closed.
May be you can try like this
import java.io.*;
import java.net.*;
import java.util.*;
public class Server2 {
static int NUM_CONN_TO_WAIT_FOR=15;
boolean exitServer =false;
public static void main(String args[]) throws Exception {
int PORT = 5555; // Open port 5555
//open socket to listen
ServerSocket server = new ServerSocket(PORT);
Socket client = null;
static int connections =0;
try
{
while (!exitServer ) {
System.out.println("Waiting for client...");
// open client socket to accept connection
if ( connections < NUM_CONN_TO_WAIT_FOR )
{
client = server.accept();
System.out.println(client.getInetAddress()+" contacted ");
System.out.println("Creating thread to serve request");
ServerStudentThread student = new ServerStudentThread(client);
student.start();
} else
{
exitServer =true;
}
connections++;
}
} catch (Exception e)
{
System.out.println(e.printStackTrace());
}
finally
{
if ( client != null)
client.close();
if ( server!= null)
server.close();
}
}
}