Hot questions for Using Transmission Control Protocol in ip

Question:

I have a Linux program split into two parts.

One part does NAT traversal to obtain either a UDP socket (UDP hole punching) or a TCP socket (TCP hole punching). Part one is written in C to allow for native features which facilitate or enhance the NAT traversal process. Part two actually uses the connected socket obtained via the NAT traversal performed in part one.

Now here is the problem. I want the first part, the part that obtains the socket, to be independent of the second part, the part that uses the socket for an application specific purpose. For example, I want the first part to be reusable for a variety of different applications that all need UDP and TCP connections that were established between peers.

Right now, I would like the second part (the application part) to be written in Java rather than C or C++. I want the second part to use a socket connection that was obtained by the C code responsible for NAT traversal. Let's say the first part established a connection and then returns a struct:

// Represents a TCP or UDP connection that was obtained in part one.
struct ConnectionObtained {
    int socket_file_descriptor;
    int source_port;
    int destination_port;
    int source_address; // 4 byte ipv4 address
    int destination_address;
    int is_UDP; // 1 for UDP client socket, 0 for TCP client socket 
};

The C code in part one can provide this POD/struct to the Java code in part two either via JNI (Java Native Interface) or via inter-proceess communication.

I want the Java code to use that information to construct an object whose declared type is either java.net.DatagramSocket or java.net.Socket and then use that object wherever a DatagramSocket or Socket would be expected.

As a starting point, consider the following sample code...

/** 
 * Determines the Unix file descriptor number of the given  {@link ServerSocket}.
 */
private int getUnixFileDescriptor(ServerSocket ss) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  Field $impl=ss.getClass().getDeclaredField("impl");
  $impl.setAccessible(true);
  SocketImpl socketImpl=(SocketImpl)$impl.get(ss);
  Method $getFileDescriptor=SocketImpl.class.getDeclaredMethod("getFileDescriptor");
  $getFileDescriptor.setAccessible(true);
  FileDescriptor fd=(FileDescriptor)$getFileDescriptor.invoke(socketImpl);
  Field $fd=fd.getClass().getDeclaredField("fd");
  $fd.setAccessible(true);
  return (Integer)$fd.get(fd);
}

The code makes it appear that it may be possible to "recreates a bound {@link ServerSocket} on the given file descriptor." Does this mean that it is possible to "recreates a bound {@link java.net.Socket} on the given file descriptor" as well? What about a bound {@link java.net.DatagramSocket}?

/** 
 * Recreates a bound  {@link ServerSocket} on the given file descriptor.
 */
private ServerSocket recreateServerSocket(int fdn) throws Exception {
  FileDescriptor fd=new FileDescriptor();
  Field $fd=FileDescriptor.class.getDeclaredField("fd");
  $fd.setAccessible(true);
  $fd.set(fd,fdn);
  Class $PlainSocketImpl=Class.forName("java.net.PlainSocketImpl");
  Constructor $init=$PlainSocketImpl.getDeclaredConstructor(FileDescriptor.class);
  $init.setAccessible(true);
  SocketImpl socketImpl=(SocketImpl)$init.newInstance(fd);
  ServerSocket ss=new ServerSocket();
  ss.bind(new InetSocketAddress(0));
  Field $impl=ServerSocket.class.getDeclaredField("impl");
  $impl.setAccessible(true);
  $impl.set(ss,socketImpl);
  return ss;
}

Answer:

You're asking two different questions. Can you pass a bound socket from C code written in a separate process and can you pass a bound socket from C code written in the same process.

For the first part, no, it's not possible if the C code is in one application and the Java code is another because if it were possible, than multiple different applications would be able to pass around a socket (without SCM_RIGHTS). Killing the application that created and bound the socket initially would create problems for the other applications using/sharing that socket.

As for having the C code be in the native part of a Java application (i.e. via jni), in that case the operating system wouldn't be able to differentiate whether the socket is in the Java part of the user code or the C part, so you don't run into the problem introduced in the previous paragraph. It is possible to pass a socket (file descriptor int and native socket descriptor) between Java and native code (see link), but that doesn't tell you if it would be practical in this scenario.

As for making a java.net.Socket or a java.net.DatagramSocket from a bound socket file descriptor that came from jni code, I have no idea. You would have to try it yourself.

Question:

I need to interact with a server over TCP/IP with a basic message/response protocol (so for each request I shall receive a defined response).

In the JVM ecosystem, I think Java Socket was the tool to use 15 years ago, but I'm wondering if there is anything more suitable nowadays in the JDK? For example, with Java Sockets one still needs to manually timeout a request if no answer is received, which feels really old fashioned.

So is there anything new in the JDK or JVM universe?


Answer:

No, there are much better option nowadays which allow you to implement your client/server asynchronously without additional threading.

Look at SocketChannel from nio or even better AsynchronousSocketChannel from nio2. Check this tutorial

Especially the latter option will allow you to just start the connection listener and register callback which will be called whenever new connection is requested, data arrived, data was written etc.

Also consider looking at some high level solutions like Netty. It will take care of the network core, distribute load evenly to executors. Additionally it provides clears separation of the network layer and processing layer. For the processing layer it will provide you with lot of reusable codecs for common protocols.

Question:

I have a Tcp client that connect to a old mainframe (52 years) that send and receive request and response from it.

Here is core connection part of the my client ,

public class SimpleConnector {

    private String carrier;
    private SocketChannel socketChannel;
    public static final byte END_OF_MESSAGE_BYTE = (byte) 0x2b;

    public SimpleConnector(String carrier, InetSocketAddress inetSocketAddress) throws IOException {
        this.carrier = this.carrier;
        socketChannel = SocketChannel.open();
        socketChannel.socket().connect(inetSocketAddress, 30000);
    }

    public void shutDown() throws IOException {
        this.socketChannel.close();
    }
    //Send Request
    public String sendRequest(String request) throws Exception {
            final CharsetEncoder charsetEncoder = Charset.forName("ISO-8859-1").newEncoder();
            int requestLength = 12 + request.length() + 1;
            ByteBuffer buffer = ByteBuffer.allocate(requestLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            buffer.putInt(requestLength);
            buffer.put(charsetEncoder.encode(CharBuffer.wrap(carrier)));
            buffer.put(charsetEncoder.encode(CharBuffer.wrap(request)));
            buffer.put(END_OF_MESSAGE_BYTE);
            buffer.flip();
            socketChannel.write(buffer);
            return readResponse();

    }
    //Read Response
    protected String readResponse() throws Exception {
            CharsetDecoder charsetDecoder = Charset.forName("ISO-8859-1").newDecoder();
            int responseHeaderLength = 12;
            ByteBuffer responseHeaderBuf = ByteBuffer.allocate(responseHeaderLength);
            responseHeaderBuf.order(ByteOrder.BIG_ENDIAN);
            int bytesRead = 0;
            do {
                bytesRead = socketChannel.read(responseHeaderBuf);
            } while (bytesRead!=-1 && responseHeaderBuf.position()<responseHeaderLength);

            if (bytesRead==-1) {
                throw new IOException(carrier + " : Remote connection closed unexpectedly");
            }
            responseHeaderBuf.flip();
            int lengthField = responseHeaderBuf.getInt();
            int responseLength = lengthField - responseHeaderLength;
            responseHeaderBuf.clear();
            ByteBuffer responseBuf = ByteBuffer.allocate(responseLength);
            bytesRead = socketChannel.read(responseBuf);
            if (bytesRead>responseBuf.limit() || bytesRead ==-1) {
                throw new IOException(carrier + " : Remote connection closed unexpectedly");
            }
            responseBuf.flip();
            if (responseBuf.get(responseBuf.limit()-1)==END_OF_MESSAGE_BYTE) {
                responseBuf.limit(responseBuf.limit()-1);
            }
            responseBuf.clear();
            String response = charsetDecoder.decode(responseBuf).toString();
            return response;

    }

    public static void main(String[] args) throws Exception{
        SimpleConnector simpleConnector = new SimpleConnector("carrier",new InetSocketAddress("localhost",9999));
        String response=simpleConnector.sendRequest("Request");
        System.out.println(response);
    }
}

I'm trying to rewrite the following piece using Netty. By using following tutorial as reference.

The problem I'm facing is I was able to connect to server but couldn't read or write from it . I'm using a ChannelInboundHandlerAdapter to do the read and write operations.

Here is my Netty Client

public class NettyClient {
    int port;
    Channel channel;
    EventLoopGroup workGroup = new NioEventLoopGroup();

    public NettyClient(int port){
        this.port = port;
    }

    public ChannelFuture connectLoop() throws Exception {
        try{
            Bootstrap b = new Bootstrap();
            b.group(workGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new NettyClientHandler());
                }
            }); 
            ChannelFuture channelFuture = b.connect("remote-ip", this.port).sync();
            this.channel = channelFuture.channel();

            return channelFuture;
        }finally{
        }
    }
    public void shutdown(){
        workGroup.shutdownGracefully();
    }

    public static void main(String[] args) throws Exception{

        try {
            NettyClient nettyClient = new NettyClient(12000);
            ChannelFuture channelFuture = nettyClient.connectLoop();
            System.out.println("Sleep 2sec");
            Thread.sleep(2000);
            String command ="username";
            final Charset charset = Charset.forName("ISO-8859-1");
            int length = 13 + command.length();
            if (channelFuture.isSuccess()) {
                ByteBuf byteBuf = Unpooled.buffer(1024);
                byteBuf.writeInt(length);
                byteBuf.writeCharSequence("Some Info",charset);
                byteBuf.writeCharSequence(command,charset);
               channelFuture.channel().writeAndFlush(byteBuf).addListener(new ListenerImpl());

            }
        }
        catch(Exception e){
            System.out.println(e.getMessage());
            System.out.println("Try Starting Server First !!");
        }
        finally {
        }
    }
private static final class ListenerImpl implements ChannelFutureListener{

    public void operationComplete(ChannelFuture channelFuture) throws Exception {
        if (channelFuture.isSuccess()){
            System.out.println("Success"); //I can see success in Listener after write, but couldn't read response

        }else {
            System.out.println("Failed");
        }
    }
}
}

Handler

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("NettyClientHandler : channelRead" );
        ByteBuf byteBuf = (ByteBuf) msg;
        String message = byteBuf.toString(Charset.defaultCharset());
        System.out.println("Received Message : " + message);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        System.out.println("NettyClientHandler : channelActive" );
    }
}

I Initially thought netty will work only with netty servers.But this answer clear my doubt about that

Does a Netty client work with a netty server only?

Can some one guide me, what I'm doing wrong ???


Answer:

I think the problem is with your ClientHandler. you should writeAndFlush() in channelActive method invoked when a connection has been established between the tcp server and client. Please use the below updated code and see whether it fixes the problem.

    @Sharable
    public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

        @Override
        public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
            String message = byteBuf.toString(Charset.defaultCharset());
            System.out.println("Received Message : " + message);
        }

        @Override
        public void channelActive(ChannelHandlerContext channelHandlerContext){
            channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("Netty Rocks!", CharsetUtil.UTF_8));
        }

    }

Question:

I'm writing a chat program using sockets and Java and I have to specify a port that the servers listen on.

Here is the the questions I have:

  1. How can I be sure that that port is always free?

  2. Does it matter if another program is also listening on that port?

  3. If the port has to be free and the default port is occupied, how would I notify the clients of a change in port number?

  4. Should I just make it so the server keeps trying to bind to a new port, incrementing the port number until it finds a free port?


Answer:

How can I be sure that that port is always free?

You can use "netstat" to check whether a port is available or not. You can list all the ports being used by a service via:

netstat -anp

If you want to search for a specific port you can use:

netstat -anp | find "port number", eg netstat -anp | find ":8080".

Does it matter if another program is also listening on that port?

From a traditional look, Yes, for TCP you can only have one application listening on the same port and same local ip address at one time. You may be able to use the same port by having multiple local IP adresses either by using multiple network cards or virtual network interfaces.

However, it seems that using the SO_REUSEPORT socket option you may be able to reuse it, check this for more information.

If the port has to be free and the default port is occupied, how would I notify the clients of a change in port number? Should I just make it so the server keeps trying to bind to a new port, incrementing the port number until it finds a free port?

Personally I would either choose a port that is always free or a small list of ports I knew would be usually free and try one by one.

The general rules of thumb for choosing a port include choosing at least a 4 digit number and avoid anything below 1024. Also, even if the port was already in use by another service, you could re-assign it to listen to another port, its your network after all.

Question:

While learning how to use akka I/O I am trying to implement a simple protocal on top of akka i/o and was following the documentation here.

However in my gradle file I use version 2.3.9 as shown below

dependencies {
    compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.7'
    compile group: 'com.typesafe.akka', name: 'akka-actor_2.11', version: '2.3.9'
    compile group: 'com.typesafe.akka', name: 'akka-contrib_2.11', version: '2.3.9'
    compile group: 'org.scala-lang', name: 'scala-library', version: '2.11.5'
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

import of some things that are pipeline specific like

import akka.io.SymmetricPipelineStage;
import akka.io.PipelineContext;
import akka.io.SymmetricPipePair;

generate can not resolve symbol errors.

Hence my questions.

  1. Were these removed or there is some dependancy I need to add to my gradle file.
  2. If they were removed, how would the encod/decode stage be dealt with?

Answer:

Pipelines were experimental and indeed removed in Akka 2.3. The removal was documented in the Migration Guide 2.2.x to 2.3.x.

There is also mention of being able to package the "older" pipeline implementation with Akka 2.3 here, though it doesn't appear to be a simple addition of a dependency.

I would wager that Akka Streams is intended to be the better replacement of pipelines, coming in Akka 2.4, but available now as an experimental module. The encode/decode stage or protocol layer can be handled by using Akka Streams in conjunction with Akka I/O.

Question:

I want to send an object from my client to my localhost server to add to database, and send result back whether the object was sent successfully or not. The object was sent successfully, but my server doesn't send the result back to client, and causes my client frame form hanged due to waiting for response from server. I don't know what's wrong with my code. Can you tell me some ways to fix this?

Here is the function to send the result:

public void sendResult(String result) {
    try {
        Socket clientSocket = myServer.accept();
        System.out.println("Connected to client");
        ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());

        os.writeObject(result);
        System.out.println("Result sent");
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Where the send result function is called:

public void service() {
    try {
        if (receiveStudent() != null) {
            Student std = receiveStudent();
            if (dao.addStudent(std)) {
                System.out.println("OK");
                sendResult("OK");
            } else {
                System.out.println("FAILED");
                sendResult("FAILED");
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

In addition, in the Service function, the console printed "OK", which means the if condition was satisfied.

receive student method:

public Student receiveStudent() {
    Student s = new Student();

    try {
        Socket clientSocket = myServer.accept();
        System.out.println("Connect to client successfully");
        ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());

        Object o = ois.readObject();
        if (o instanceof Student) {
            s = (Student) o;
            return s;
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

Answer:

Because of myServer.accept() in sendResult(), the server is again waiting for an incoming client connection while this already happened in receiveStudent(). Reuse that connection.

Share the client socket you've obtained in receiveStudent() by, e.g., turning it into a field.

public Student receiveStudent() {
    ...

    try {
        clientSocket = myServer.accept();
        ...
    } catch (Exception ex) {
        ...
    }
    ...
}

and then reuse that socket in sendResult() to send the result to the client.

public static void sendResult(String result) {
    try {
        ...
        ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
        ...
    } catch (Exception ex) {
        ...
    }
}

Question:

I'm new at network programming and i have been searching for a solution to my problem here but couldn't find one. What I want is to have a server that can receive files from multiple sockets at the same time. When a server accepts new connection socket it wraps that socket with a ClientThread class. Here is the code:

public class Server extends Thread {
    private ServerSocket server;
    private Vector<ClientThread> clients;

    @Override
    public void run() {
        listen();
    }

    private void listen() {

    new Thread("Listening Thread") {

        @Override
        public void run() {
            while (true) {
                try {
                    Socket socket = server.accept();

                    ClientThread newClient = new ClientThread(socket);
                    newClient.start();
                    clients.addElement(newClient);

                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}

ClientThread is a private class inside the Server class. It's always listening for an Object from ObjectInputStream, but also I want to be able to receive one big file after the object. And that is why I think i should use multithreading. Here is the code:

private class ClientThread extends Thread {

    public Socket socket;
    private boolean loggedIn;
    private ObjectInputStream ois;
    private BufferedInputStream bis;

    public ClientThread(Socket socket) {
        this.socket = socket;
        loggedIn = true;

        InputStream is = socket.getInputStream();
        ois = new ObjectInputStream(is);
        bis = new BufferedInputStream(is);
    }

    @Override
    public void run() {
        receive();
    }

    private void receive() {

        while (loggedIn) {
            try {
                // this method blocks i guess
                Object object = ois.readObject();

                // after the object comes the large file
                byte[] bytes = new byte[SOME_SIZE];

                int bytesRead;
                int totalRead = 0;

                // reading the large file into memory
                while ((bytesRead = bis.read(bytes, totalRead, bytes.length - totalRead)) > -1) {
                    totalRead += bytesRead;
                }

                // rest of the code for handling received bytes.......

            } catch (ClassNotFoundException | IOException e) {
                e.printStackTrace();
            }
        }
    }

}

I'm not sure if receiving data like this is even possible since all these client sockets are sending data to the same port on this server (i guess?). And if clients are sending data at the same time, Server needs to know which data is for which client. Is this already taken care of, or i need entirely different approach here?

I don't know if this is a stupid question, but like I said I'm just starting learning this stuff. Also i couldn't test my program because i don't even have code for the Client yet. Just want to make sure I don't go wrong at the very start. If this is wrong, feel free to post some ideas. :) Thanks!


Answer:

For a start it's not bad :) You can improve later on by using a Selector but that's another topic.

Some clarifications though: the ServerSocket listens on a specific port. When a remote client connects to it, a communication channel (i.e. socket) is created. If another client connects, another socket is created. Both sockets are different channels and won't interfere with each other because they are connected to a different remote IP and port.

It all has to do with how TCP headers and IP headers are formed: a TCP data packet is sent with its header containing the source and destination port, on top of IP header containing the source and destination IP. Those are used to discriminate between the different sockets.


Regarding the "broadcast" you want to do (as per your comment in @Rajesh's answer), you have options:

  • Do it yourself in pure TCP with ServerSocket and Socket like you started
  • Switch to UDP and use MulticastSocket, which has the advantage of issueing a single send, but you'll have to deal with missing/unordered datagrams in your client code (UDP does not guarantee delivery or ordering, like TCP does)
  • Check NIO with Selector and SocketChannel
  • Investigate frameworks like jGroups or Netty which do the I/O stuff for you

As you're learning, I suggest you do that in the above order. Using a framework is nice, but going through coding yourself will teach you a lot more.

Question:

in the PLC4X project we are using Netty for the clients to connect to PLCs which act as server. Sometimes, either by user error or by PLC error the connections are not accepted but rejected. If we retry to build up the connection ASAP multiple times, we run into the error message Too many open files. I try to clean up everything in my code, so I would assume that there are no filedescriptors that could leak:

try {
  final NioEventLoopGroup workerGroup = new NioEventLoopGroup();

  Bootstrap bootstrap = new Bootstrap();
  bootstrap.group(workerGroup);
  bootstrap.channel(NioSocketChannel.class);
  bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
  bootstrap.option(ChannelOption.TCP_NODELAY, true);
  // TODO we should use an explicit (configurable?) timeout here
  // bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000);
  bootstrap.handler(channelHandler);
  // Start the client.
  final ChannelFuture f = bootstrap.connect(address, port);
  f.addListener(new GenericFutureListener<Future<? super Void>>() {
      @Override public void operationComplete(Future<? super Void> future) throws Exception {
          if (!future.isSuccess()) {
              logger.info("Unable to connect, shutting down worker thread.");
              workerGroup.shutdownGracefully();
          }
      }
  });
  // Wait for sync
  f.sync();
  f.awaitUninterruptibly(); // jf: unsure if we need that
  // Wait till the session is finished initializing.
  return f.channel();
} catch (InterruptedException e) {
  Thread.currentThread().interrupt();
  throw new PlcConnectionException("Error creating channel.", e);
} catch (Exception e) {
  throw new PlcConnectionException("Error creating channel.", e);
}

From my understanding, the Listener should always shutdown the group and free up all descriptors used. But in reality, when running it on macOS Catalina I see that about 1% of the fails that its not due to "rejection" but due to "Too many open files". Is this a ulimit thing, as Netty (on macOS) simply needs a number of fd's to use? Or am I leaking something?

Thanks for clarification!


Answer:

I found out the solution, kind of myself. There are 2 issues (probably even 3) in an original implementation, which are not really related to Mac OS X:

  • connect and addListener should be chained
  • workerGroup.shutdownGracefully() is triggered in another thread, so the main (called) thread already finishes
  • its not awaited that the workerGroup really finishes.

This together can lead to situations as it seems, where new groups are spawned faster than old groups are closed. Thus, I changed the implementation to

try {
    final NioEventLoopGroup workerGroup = new NioEventLoopGroup();

    Bootstrap bootstrap = new Bootstrap();
    bootstrap.group(workerGroup);
    bootstrap.channel(NioSocketChannel.class);
    bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
    bootstrap.option(ChannelOption.TCP_NODELAY, true);
    // TODO we should use an explicit (configurable?) timeout here
    // bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000);
    bootstrap.handler(channelHandler);
    // Start the client.
    logger.trace("Starting connection attempt on tcp layer to {}:{}", address.getHostAddress(), port);
    final ChannelFuture f = bootstrap.connect(address, port);
    // Wait for sync
    try {
        f.sync();
    } catch (Exception e) {
        // Shutdown worker group here and wait for it
        logger.info("Unable to connect, shutting down worker thread.");
        workerGroup.shutdownGracefully().awaitUninterruptibly();
        logger.debug("Worker Group is shutdown successfully.");
        throw new PlcConnectionException("Unable to Connect on TCP Layer to " + address.getHostAddress() + ":" + port, e);
    }
    // Wait till the session is finished initializing.
    return f.channel();
}
catch (Exception e) {
    throw new PlcConnectionException("Error creating channel.", e);
}

which adresses the issues above. Thus, the call only finishes when its properly cleaned up.

My tests now show a constant number of open file descriptors.

Question:

Our application is using JeroMQ 0.4.3 to send messages between a client application and an API. (using curve encryption with ZAuth).

We're getting client messages from a ROUTER socket in our broker (MDP pattern).

What's the best way to find the sender's IP when receiving a message in the broker?

In ZeroMQ, it seems it might be possible using ZMQ_SRCFD message option and getpeername() but I have not found a way to translate that to JeroMQ.


Answer:

The more recent ZeroMQ API indeed defines ZMQ_SRCFD property a message may carry.

Fact A) one is principally never sure, what ZeroMQ API version ( 2.x ~ 3.x ~ 4.2.2 ~ ? as of EoY-2017 ) does the remote system use, unless some indeed rigid and intrusion-robust version-enforcement policy is put in place and active.

Fact B) recent ZeroMQ API defines for tcp:// transport-class this:

ZMQ_SRCFD Returns the file descriptor of the socket the message was read from. This allows application to retrieve the remote endpoint via getpeername(2). Be aware that the respective socket might be closed already, reused even. Currently only implemented for TCP sockets.

Fact C) Any language wrapper or binding, including one's preferred JeroMQ or other, has to cover the selected scope ( be it a full or a partial scope-coverage ) on its own.

If one lacks a feature in some particular language port/binding version, the best next step is to assess a feasibility of extending the published source code, so as to also cover a wished feature by (re)-implementing the language port/binding so as to best meet the desired API feature as specified by the ZeroMQ published specification.

Fact D) In cases, where C) gets unfeasible or incomplete as per principal uncertainty expressed under B) , one may still proceed to rather implement one's own, high level IP-address node-(re)-discovery strategy, based on any suitable grade of security-concerns, starting from even a { naive self-declaration | two-step IP-validation | ... | a trust-less IP-validation }-protocol, if one needs it.

Question:

When I write a Java program that talks to an HTTP endpoint/server I would ideally use some library to create my HTTP request using the classes provided by that library and make the call.

I am trying to figure out where exactly does the packet creation happen for each step in the network stack? As in when I use these HTTP libraries are the HTTP packet creation handles by these libraries? Is it them who puts all the HTTP header information and append the data and create the packet?

And then where are the TCP packets assembled? Is it done at the kernel level? Is the created HTTP packet submitted to the kernel network module by the jvm and the kernel wraps the packet with TCP information and so on?

I'm trying to draw a clear picture of where each of these things happens so I could figure out where exactly I want to hack into for a project idea I have.

Thank You Shabir


Answer:

When I use these HTTP libraries are the HTTP packet creation handles by these libraries?

There is no such thing as an HTTP packet. There are HTTP requests and responses. See below.

Is it them who puts all the HTTP header information and append the data and create the packet?

The library creates the headers. The application provides the data.

And then where are the TCP packets assembled?

There is no such thing as a TCP packet. There are TCP segments, and IP packets (and Ethernet frames, ...). See below.

Is it done at the kernel level?

Yes.

Is the created HTTP packet submitted to the kernel network module by the JVM

Essentially yes.

and the kernel wraps the packet with TCP information and so on?

Yes. Specifically, the TCP layer of the network stack provides the TCP header and segment isding, the IP layer provides the IP header and packetising, etc.

Question:


Answer:

That doesn't appear to be an all debug log - I suggest you run the following test case (from the framework tests)...

@Test
public void testNetClientAndServerSSLDifferentContexts() throws Exception {
    System.setProperty("javax.net.debug", "all"); // SSL activity in the console
    TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(0);
    TcpSSLContextSupport serverSslContextSupport = new DefaultTcpSSLContextSupport("server.ks",
            "server.truststore.ks", "secret", "secret");
    DefaultTcpNetSSLSocketFactorySupport serverTcpSocketFactorySupport =
            new DefaultTcpNetSSLSocketFactorySupport(serverSslContextSupport);
    serverTcpSocketFactorySupport.afterPropertiesSet();
    server.setTcpSocketFactorySupport(serverTcpSocketFactorySupport);
    final List<Message<?>> messages = new ArrayList<Message<?>>();
    final CountDownLatch latch = new CountDownLatch(1);
    server.registerListener(new TcpListener() {

        @Override
        public boolean onMessage(Message<?> message) {
            messages.add(message);
            latch.countDown();
            return false;
        }

    });
    server.start();
    TestingUtilities.waitListening(server, null);

    TcpNetClientConnectionFactory client = new TcpNetClientConnectionFactory("localhost", server.getPort());
    TcpSSLContextSupport clientSslContextSupport = new DefaultTcpSSLContextSupport("client.ks",
            "client.truststore.ks", "secret", "secret");
    DefaultTcpNetSSLSocketFactorySupport clientTcpSocketFactorySupport =
            new DefaultTcpNetSSLSocketFactorySupport(clientSslContextSupport);
    clientTcpSocketFactorySupport.afterPropertiesSet();
    client.setTcpSocketFactorySupport(clientTcpSocketFactorySupport);
    client.start();

    TcpConnection connection = client.getConnection();
    connection.send(new GenericMessage<String>("Hello, world!"));
    assertTrue(latch.await(10, TimeUnit.SECONDS));
    assertEquals("Hello, world!", new String((byte[]) messages.get(0).getPayload()));
}

The debug log starts like this...

***
found key for : sitestserver
chain [0] = [
[
  Version: V3
  Subject: CN=Spring Integration Test Server, OU=SpringSource, O=VMware, L=Palo Alto, ST=CA, C=US
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 145953694279918711466593323385178894247518594695766350354036273697592524406041558890428426220351711997889835331198023000923126848152011583237597808196751267657648195434943824515101123741288592866628375132742429927417934808064049810040188644453056781002083733535076342958460726082218474705117624658622289918247
  public exponent: 65537
  Validity: [From: Sat Feb 25 14:31:38 EST 2012,
               To: Mon Feb 01 14:31:38 EST 2112]
  Issuer: CN=Spring Integration Test Server, OU=SpringSource, O=VMware, L=Palo Alto, ST=CA, C=US
  SerialNumber: [    4f49371a]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: AC 69 48 78 22 9F 32 3F   88 2F DB 49 53 87 F1 10  .iHx".2?./.IS...
0010: 64 D3 30 22 0D 04 13 90   07 9B 0E 9A FB 1F 65 97  d.0"..........e.
0020: 5D 2D C1 C6 A1 8A C5 C7   16 71 A9 47 95 C2 FF D5  ]-.......q.G....
0030: 1D 10 06 51 EE 64 37 A9   D3 B0 69 F9 84 5B 9D 1D  ...Q.d7...i..[..
0040: E1 6C C0 48 31 FD 82 10   B5 D4 56 D4 76 2D DE EB  .l.H1.....V.v-..
0050: B2 66 1F B6 D1 C3 AA E2   E6 8D 4B B6 05 BC F0 88  .f........K.....
0060: 7B BC 81 B1 C2 BB 3D 1C   0A AD 5B 29 55 94 05 2C  ......=...[)U..,
0070: 5B 5C 44 82 54 90 5F B4   70 EA 10 45 AC A0 5F 2B  [\D.T._.p..E.._+

]
***
adding as trusted cert:
  Subject: CN=Spring Integration Test Client, OU=SpringSource, O=VMware, L=Palo Alto, ST=CA, C=US
  Issuer:  CN=Spring Integration Test Client, OU=SpringSource, O=VMware, L=Palo Alto, ST=CA, C=US
  Algorithm: RSA; Serial number: 0x4f4936f4
  Valid from Sat Feb 25 14:31:00 EST 2012 until Mon Feb 01 14:31:00 EST 2112

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
...

Question:

I have a TCP client that sends a 14 byte String once a second to a TCP server that just prints the string.

Client is an Android app, Server is a simple Java app running on a laptop. Comms are wifi from client to router then ethernet to laptop.

Client connects to server OK and starts sending messages, but after an indeterminate time the server stops receiving the messages.

Looking at the wireshark traffic from the server shows the last message was ACKed by the server but the client clearly never receives the ACK because it retransmits the message and the server sends a DUP ACK. After that no more messages appear until I explicitly close the socket.outputStream() on the client at which point the server receives all of the messages and Wireshark shows a TCP frame containing all the missing messages.

NB I am flushing after each message. And TCP_NODELAY has zero effect.

  1. Why are the messages suddenly being buffered?
  2. What do I can do stop it?

NB the code below is not designed for production use. It is just so I can debug this.

Client:

private class SocketSender implements Runnable {

    private final Socket socket = new Socket();

    public void run() {
        Log.d(TAG, "Starting SocketSender");
        toggleButtons(SocketState.Transmitting);
        try {
            startSending();
        } catch (IOException e) {
            Log.d(TAG, "", e);
        }
        toggleButtons(SocketState.AwaitingClose);
        Log.d(TAG, "Stopping SocketSender");
    }

    private void startSending() throws IOException {
        int counter = 1;
        Log.d(TAG, "Opening Socket to " + HOST_ADDRESS + ":" + HOST_PORT);
        //socket.setTcpNoDelay(true);
        //socket.setPerformancePreferences(0, 1, 0);
        socket.connect(new InetSocketAddress(HOST_ADDRESS, HOST_PORT), 3000);
        Log.d(TAG, "OpenedSocket");
        try {
            final OutputStream stream = socket.getOutputStream();
            final PrintWriter output = new PrintWriter(stream);
            while (sending) {
                final String message = "Ping pingId=" + counter;
                output.println(message);
                output.flush();
                Log.d(TAG, "Sent message : " + message);
                counter++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Log.d(TAG, "Sleep interrupted", e);
                }
            }
            output.close();
        } finally {
            //socket.close();
        }
    }

    private void closeSocket() {
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                Log.d(TAG, "Could not close Socket", e);
            }
        }
    }
}

Server:

private void readStream() throws IOException {
    final ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
    final Socket socket = serverSocket.accept();
    final InputStreamReader streamReader = new InputStreamReader(socket.getInputStream());
    final BufferedReader in = new BufferedReader(streamReader);

    final SimpleDateFormat format = new SimpleDateFormat("YY-MM-DD HH:mm:ss.SSS");
    long lastMessage = System.currentTimeMillis();
    while (true) {
        final String inputLine = in.readLine();
        long thisMessage = System.currentTimeMillis();
        if (inputLine == null) {
            System.out.println("  No more input from : " + socket);
            break;
        }
        System.out.println(format.format(new Date(thisMessage)) + "  '" + inputLine + "' from : " + socket + "  millisSinceLastMsg=" + (thisMessage - lastMessage));
        lastMessage = thisMessage;
    }
    socket.close();
}

Answer:

The key here is that the sender isn't receiving the ACKs. That's a network problem, not a coding problem. It's surprising that the sender didn't fill its send buffer, block, ultimately time out the pending send, and reset the connection.

You might be better off setting a read timeout at the receiver, and closing the connection if it fires. That way the client will get a connection reset and will at least know something's wrong, then it can reconnect or whatever is appropriate.

Question:

So, I've been creating a wireless mouse app that utilizes Bluetooth and WiFi (the user decides), I've recently decided to go from UDP to TCP connection as I noticed one of the mainstream mouse apps uses TCP instead of UDP.

My problem: I am sending multiple byte arrays over TCP-IP to my server end but it feels as though there is a lag, is there any way I could potentially speed up how fast I am receiving the byte arrays?

Server code involving receiving:

Socket client = null;
BufferedInputStream bis = null;
try {
    client = serverSocket.accept();
} catch (IOException e) {
    e.printStackTrace();
}
try {
    bis = new BufferedInputStream(client.getInputStream());
} catch (IOException e) {
    e.printStackTrace();
}
byte data[] = new byte[2];

if (bis != null) {
    try {
        while(alive && (bis.read(data)) != -1) {
            System.out.println(data[0] + " " + data[1]);

            PointerInfo a = MouseInfo.getPointerInfo();
            Point b = a.getLocation();
            int x = (int)b.getX();
            int y = (int)b.getY();

            dx = data[0];
            dy = data[1];

            newX = x + dx;
            newY = y + dy;

            if(dx == -98 && dy == -98) {
                // Right click
                r.mousePress(InputEvent.BUTTON3_DOWN_MASK);
                r.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);

            } else if (dx == -99 && dy == -99) {
                // Left click
                r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
                r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
            } else if (dx == -97 && dy == -97) {
                // Middle click
                r.mousePress(InputEvent.BUTTON2_DOWN_MASK);
                r.mouseRelease(InputEvent.BUTTON2_DOWN_MASK);
                Main.wifiDisconnect.doClick();
            } else {
                if (!recieve && (dx != 0 || dy != 0)) { // No current thread and non empty values - Start a new one
                    newX = x + dx;
                    newY = y + dy;
                    i = 0;
                    recieve = true;
                    mmThread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            while (recieve){
                                r.mouseMove(newX + i * dx, newY + i * dy);
                                r.delay(8);
                                i++;
                            }
                        }
                    });
                    mmThread.start();
                } else if (recieve && dx == 0 && dy == 0) {
                    recieve = false;
                    try {
                        mmThread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mmThread = null;
                } else {
                    newX = x + dx;
                    newY = y + dy;
                    i = 0;
                }
            }
        }

Client code (Android) involving sending:

public class sendTask extends AsyncTask<Byte, Void, Void> {

@Override
protected Void doInBackground(Byte ...bytes) {
    try {
        byte x = bytes[0].byteValue();
        byte y = bytes[1].byteValue();
        System.out.println("Message sending: " + x + " " + y);
        byte buf[] = {x, y};
        bos.write(buf); //buffered output stream
        bos.flush();

    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (SocketException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
}

Answer:

First, get a network sniffer like WireShark and find out for certain what is going on. It's impossible to know without that.

But I will speculate... TCP has what is called "Nagle's Algorithm" for dealing with small packets. Basically, it delays the transfer of a small packet on the chance that more data will be ready to send very soon and it can be aggregated into a single larger packet, the overall benefit being a more efficient network connection at the cost of some milliseconds.

You can set the socket option TCP_NODELAY to disable this and have all written bytes sent immediately.

Question:

I need a java 7 TCP/IP client that will block until it receives a user specified character sequence (in my case a message terminator/separator - this would automatically "chunk" the data into individual messages for further processing). I expected that this would be very standard code freely available on the web - but so far no luck.

Complicating things, "chunking" the received data using standard line separators (e.g. readLine() in Oracle's KnockKnock Client), is not possible since those characters are valid data inside the messages. The message format is an international standard and can't be changed.

After trying a few things (see below) I'm wondering if I'm taking the right approach. Is there a freeware example somewhere that I could draw on for inspiration? Or perhaps a class meeting my needs already exists somewhere in the depths of "rt.jar" or elsewhere. (BTW I used eclipse to take a look at rt.jar's contents - the huge number of packages/classes (according to http://www.findjar.com/jar/com.sun/jars/rt.jar.html?all=true JVM 6 contains 13200+ classes) makes a manual search impractical).


I've used Oracles example "KnockKnock" client as a starting point. My first thought was that all that would be necessary is to modify one line:

while ( (fromServer = in.readLine()) != null )  

to something like:

while ( (fromServer = in.readLine( separator = UserSpecifiedRegExValue )) != null )  

Unfortunately this extremely useful overloading/generalization of readLine() does not exist in Java.

Oracle's example works because readLine() blocks until it receives the line separator value on the TCP/IP link. My thinking was that a generalized verson of readLine() would also block until it received the user specified character string (i.e. the message terminator) thus giving me exactly what I want. Since that approach isn't available my next thought was to replace readLine() with a getNextMessage() function that would block until the user specified character string was received by TCP/IP. Based on other posts I came up with this function:

static String getNextMessage( java.io.BufferedReader MessageSource, 
                              String                 EndOfMessage_RegEx ) 
{           
    try ( java.util.Scanner s = new java.util.Scanner( MessageSource ) ) 
    { 
        return s.useDelimiter( EndOfMessage_RegEx ).hasNext() ? s.next() : ""; 
    }
}

and tested it by emulating readLine(), passing in the O/S specific line separator, as done in this variant:

final static String  LineSeparator     = System.getProperty( "line.separator" );  // LineSeparator = ODOA (<CR><LF>) on Win7
final static String  MessageSeparator  = Pattern.quote( LineSeparator );          // MessageSeparator = 5C510D0A5C45 (the RegEx string "\Q<CR><LF>\E")
final static Pattern EndOfMessageRegEx = Pattern.compile( MessageSeparator );

static String getNextMessage( java.io.BufferedReader MessageSource ) 

// This function needs to block until a complete message (terminated by 
// "EndOfMessageRegEx") is received by TCPIP from the other machine.

{           
    try ( java.util.Scanner s = new java.util.Scanner( MessageSource ).useDelimiter( EndOfMessageRegEx ) ) 
    { 
        if ( s.hasNext() ) 
        {
            return s.next();
        } 
        else 
        {
            return "";
        }
    }
}

Unfortunately both versions always return the null string, immediately terminating my client - which makes sense if hasNext() does not block. (The hasNext() documentation says it "may" - i.e. not guaranteed to - block.) How do I get the blocking effect?

Another problem I see with both versions is that they pointlessly recreate a scanner every time the function is invoked.

Or am I forced into using the much more primitive approach of creating a buffer, using .read() and searching for the specified character string instead?


SOLUTION: Moved to accepted answer


Answer:

Consider this InputStream derived from PushbackInputStream:

public static class TerminatorInputString extends PushbackInputStream {

    private String terminator;

    public TerminatorInputString(InputStream inputStream, String string) {
        super(inputStream, 256);
        terminator = string;
    }

    public String nextMessage() throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] data = new byte[8];
        int len = read(data,  0,  data.length);
        while(len > 0) {
            baos.write(data, 0, len);
            byte[] all = baos.toByteArray();
            int idx = baos.toString().indexOf(terminator);
            if(idx >= 0) {                  
                String message = baos.toString().substring(0,  idx);
                byte[] unread = new byte[all.length-idx-terminator.length()];
                System.arraycopy(all, idx+terminator.length(), unread, 0, unread.length);
                super.unread(unread);
                return message;
            }
            len = read(data,  0,  data.length);
        }
        baos.flush();
        return new String(baos.toByteArray());
    }
}

It reads until terminator is found, then skips terminator and continues after that. End of stream will close final message.

Test frame:

public static void main(String[] args) {
    try {
        //System.in is a bad stream (if used in eclipse at least)
        // - it will only flush and make data available
        // on new line
        TerminatorInputString tis = new TerminatorInputString(System.in, "SCHWARZENEGGER");
        String message = tis.nextMessage();
        while(message != null) {
            System.out.println("MSG:>" + message + "<");
            message = tis.nextMessage();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

With this input

oneSCHWARZENEGGERtwoSCHWARZENEGGERthreeSCHWARZENEGGER

produces this output:

MSG:>one<
MSG:>two<
MSG:>three<

Question:

I have two Real Ip address 220.xx.xxx.xxx in my work place. I tried to make a simple java tcp server program and android tcp client program. The android client works fine when:

  1. Server and emulator program in the same pc.
  2. Server in one pc having real IP address emulator is in another pc with a real ip address.
  3. Server and emulator both within under private network within same pc or different pc or device.

does not work when:

  1. client is a smart phone having wifi or 3g network, and server have a real IP address on different network.
  2. client is an emulator running on wifi connected device, server have a real ip address.

So, how to connect to a Java TCP server socket having Public IP From Android Tcp Client Socket? I dont think pasting code is really necessary here. However if some one ask I can provide. According to my search on the internet some people provide suggestion to configuring the router on the server side. this seems to me little bit annoying. if I run a websever it can be accessed from anywhere any place. code included here: Server side:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.*;

public class Server {

    private static ServerSocket serverSocket;
    private static Socket clientSocket;
    private static InputStreamReader inputStreamReader;
    private static BufferedReader bufferedReader;
    private static OutputStreamWriter outputStreamWriter;
    private static BufferedWriter bufferedWriter;
    private static PrintWriter printWriter;
    private static String message;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            System.out.println(InetAddress.getLocalHost());
            serverSocket = new ServerSocket(4444); // Server socket

        } catch (IOException e) {
            System.out.println("Could not listen on port: 4444");
        }

        System.out.println("Server started. Listening to the port 4444");

        while (true) {
            try {

                clientSocket = serverSocket.accept(); // accept the client connection
                System.out.println("connection initiated");

                DataInputStream din = new DataInputStream(clientSocket.getInputStream());

                DataOutputStream dout= new DataOutputStream(clientSocket.getOutputStream());

                String msg = din.readUTF();
                System.out.println(msg);

                dout.writeUTF("hello from server");
                System.out.println("sent to client");



                clientSocket.close();

            } catch (IOException ex) {
                System.out.println("Problem in message reading "+ex);
            }
        }
    }

}

Client Side:

package com.example.client;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

 TextView textResponse;
 EditText editTextAddress, editTextPort; 
 Button buttonConnect, buttonClear;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  editTextAddress = (EditText)findViewById(R.id.address);
  editTextPort = (EditText)findViewById(R.id.port);
  buttonConnect = (Button)findViewById(R.id.connect);
  buttonClear = (Button)findViewById(R.id.clear);
  textResponse = (TextView)findViewById(R.id.response);

  buttonConnect.setOnClickListener(buttonConnectOnClickListener);

  buttonClear.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    textResponse.setText("");
   }});
 }

 OnClickListener buttonConnectOnClickListener = 
   new OnClickListener(){

    @Override
    public void onClick(View arg0) {
     MyClientTask myClientTask = new MyClientTask(
       editTextAddress.getText().toString(),
       Integer.parseInt(editTextPort.getText().toString()));
     myClientTask.execute();
    }};

 public class MyClientTask extends AsyncTask<Void, Void, Void> {

  String dstAddress;
  int dstPort;
  String response = "";

  MyClientTask(String addr, int port){
   dstAddress = addr;
   dstPort = port;
  }
  private PrintWriter printwriter;
  private InputStreamReader inputStreamReader;
  private BufferedReader bufferedReader;
  @Override
  protected Void doInBackground(Void... arg0) {

   Socket socket = null;

   try {
    socket = new Socket(dstAddress, dstPort);

    DataInputStream din = new DataInputStream(socket.getInputStream());
    DataOutputStream dout = new DataOutputStream(socket.getOutputStream());

    dout.writeUTF("hello from client");

    response="sent to serve;r";

    String msg = din.readUTF();
    response+=msg;

    socket.close();

   } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    response = e.toString();
   }
   return null;
  }

  @Override
  protected void onPostExecute(Void result) {
   textResponse.setText(response);
   super.onPostExecute(result);
  }

 }

}

Answer:

I just changed the port number from 4444 to 6667 and It worked on everywhere now. I dont think port 4444 was used on somewhere else because the program works on local network

Question:

I´m trying to implement a TCP client that sends to a server each 50ms. So I`ve developed a quick TCP test program where I can change the time between each message and I don't really get the message to send each X ms and they are accumulating as you can see at the Wireshark capture. Any ideas?

It is supposed to be only one letter a and Time since the previous frame in this TCP stream should be near to the value introduced by the console in this example 0.08 seconds

public class TCPClient {

static Socket clientSocket;
static DataOutputStream outToServer;
public static class enviar extends TimerTask {
    public void run() {
        try{
            outToServer.writeBytes("a");
            System.out.println("Packet Sent");
        }catch(Exception e){
            System.out.println(e);
        }
    }
}



public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int tiempo = 1000;
    System.out.print("Tiempo: ");
    tiempo = scanner.nextInt();
    try{
        clientSocket = new Socket("192.168.1.21", 1337);
        outToServer = new DataOutputStream(clientSocket.getOutputStream());
    }catch(Exception e){
        System.out.println(e);
    }
    Timer timer = new Timer();
    timer.schedule(new enviar(), 0, tiempo);
}

}


Answer:

You can affect the sender behavior by setting the socket option "TCP_NODELAY" (local spelling may vary), which makes it more likely that the bytes will be sent immediately (subject to flow control, etc) but that does not change the underlying nature of TCP.

TCP is not a message-oriented protocol, it is a sequential byte-stream protocol. There is no guarantee that separate execution of 'send' results in the same number, with the same content, of 'receives' at the other end. It often happens especially on LANs that you get unlucky and 'message' boundaries appear to be preserved, but it ain't necessarily so.

If you want messages, you have to invent them. Standard techniques: fixed-length messages (sounds like you're doing this: length 1), a header giving the length, delimiter bytes. The receiver has to be coded to reconstruct the messages. The on-the-wire packetization does not matter.

Question:

Is there a way (in Java) to read IP-layer headers (I'm interested in src & dst IPs), using TCP or UDP socket?

I know it's possible using pcap (packet capture), but I didn't find a way to do it using sockets. What's the reason behind that?


Answer:

At the operating system level, you need raw sockets to access IP-layer headers. But fortunately raw sockets don't exist in pure Java so you need native code to make the relevant syscalls.

There are Java libraries that use a JNI component for the native calls. One example (which I used successfully in the past) is Rocksaw.

Question:

I'm migrating my app from Ipv4 (TCP) to Ipv6 (TCP).

To contact the server, the client send a message to

fe80::cc3a:61ff:fe5d:bed5

instead of

192.168.0.16

The rest of the code remains identical.

Curiously, sometimes it works, sometimes it doesn't work. After a few hours of searching, I realized that a "scope" has been added to the end of the Ipv6 address (fe80::d6ae:5ff:fe43:c6e9%wlan0).

I noticed that it can be %p2p0, %eth0 or %wlan0. Knowing that to work through the Wi-Fi, the scope has to be %wlan0, how could I impose the use of a specific scope?

I looked all the Inet6Address methods without finding anything.


Answer:

MulticastSocket.setNetworkInterface() is the solution.

MulticastSocket multicastSocket = new MulticastSocket("5678");
NetworkInterface wifiInterface = null;
for (NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces()))
    if (networkInterface.getName().equalsIgnoreCase("wlan0")) {
        wifiInterface = networkInterface;
        break;
        }

multicastSocket.setNetworkInterface(wifiInterface);

Question:

All, Not sure whether to create some Java code or use an 'off-the-shelf' product to produce a listener / router / redirector, one which will listen to a single incoming IP stream and then 'redirect' packets based on a fixed position string variable to an appropriate TCP server.

i.e. If the incoming packet has variable = 1 redirect to a TCP server at 192.168.150.211, if a 2 then redirect to TCP server at 192.168.150.212.

Ideally the code / product should also be able to pre-launch multiple TCP servers (either at one IP address and different IP ports or at different IP addresses) on the same machine prior to the listener / router starting.

Was thinking of using an OPC server but these seem too complex / costly for a single, relatively slow, incoming stream.

Thoughts appreciated.


Answer:

This depends on the depth of analyzing. If you would like to analyze each packet at TCP-level then low-level language like C will be the best choice: just listen everything that comes to eth0 (or whatever interface), search for specific string (BTW "string" definition is too wide. The times when a string could be considered as ready-to-process data are in the '80s. Nowadays string is a piece of rubbish until you know what encoding is, how lines are terminated, etc).

As already mentioned by @f1sh you can redirect traffic using Java. But Java operates with streams, it knowns nothing about network packets. Also, in Java you can listen only on certain port(s) - there is no way to filter on the whole network interface (but JNI can be real saver).

If you would like to get PoC without huge amount of coding lets consider Socat. Socat can not only transmit data from one socket to another. It can also write data to files. So you can combine Socat (don't forget about fork option), tail, grep and a bit of Bash stuff and get simple redirection server working.

Question:

I've developed a decent amount of multiplayer games lately in java (board/turn based games running on a tcp connection with data in/out streams) but they only work locally, I want to go a step further and make them run online, what do I need to change to make it work?

It seems like there are many ways to accomplish that yet i don't know where to start, as I don't know much about networking.

Besides that I don't have a real server, I'm only using my home router and my pc.

So here is what I've tried so far:

  • I enabled port forwarding in my router and I think it works (I used a port forwarding checking tool online)
  • I created a dynamic DNS for my public ip using noip.com

So the server side should be fine at least, my problem is with the client side, the client's socket won't connect to my public ip, when I searched for a solution I concluded that the client shouldn't be in the same LAN where the server is, so I used a mobile hotspot as a second network and tried again, but got the same results. (connection refused exception) is it because of the mobile hotspot (should I use another router) ? or is it just some coding tweaks ?

This is a minimal server class example

 public static void main(String[] args) {
    try {
        ServerSocket ss = new ServerSocket(50895);
        Socket cs = ss.accept();
        DataOutputStream out = new DataOutputStream(cs.getOutputStream());
        DataInputStream in = new DataInputStream(cs.getInputStream());
        out.writeInt(123456);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

And this a minimal client class example

public static void main(String[] args) {
    try {
        String ip = Inet4Address.getByName("my Dynamic IP address").getCanonicalHostName();
        System.out.println(ip);
        InetSocketAddress sa = new InetSocketAddress(ip, 50895);
        Socket cs = new Socket();
        cs.connect(sa);
        DataOutputStream out = new DataOutputStream(cs.getOutputStream());
        DataInputStream in = new DataInputStream(cs.getInputStream());
        System.out.println("received : " + in.readInt());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

The method that i've tried always gives me a connection refused exception, so any solution would be appreciated.


Answer:

I found a software solution to the problem through virtual lan (using LogMeIn Hamachi) which is basicly used for creating game servers, you just need to create an account and a network so your friends can join it, after that everything should be fine and runs as if it's locally hosted.

You can download the software through here but there are many alternatives to choose from, that one gives you up to 5 people on the network for free, it's not the best, but still a free solution.

I still want more of a java solution to this problem that doesn't require a third-party software.

Question:

I have an app in eclipse that was written in java and an app in visual studio that is written in C#. I have a tcp connection between them.

My project sends an ID message. The message sending worked fine until now. It shows me in Visual Studio that it's sending the ID number 120 for example but when I do readbyte in eclipse it reads it as -136. As I said it worked fine last week (I didn't used it for a week and suddenly it doesn't work now). Why it is ? I don't know if it is related or not but 136+120 = 256. If I send 125 it get -131 (Every send gives 256). Please help me with it for tommorow. Thanks.


Answer:

It seems like the most significant bit in the byte is being flipped somehow. Without seeing the code there isn't much more to say. 0-127 use the first three bits, and under a signed representation, this is the max value. 128 unsigned is -127 signed under two's complement.

Question:

I'm trying to read content from the web(more specifically wikipedia) and whenever it's a wiki page that doesn't exist(ie. http://en.wikipedia.org/wiki/Asdfasdfasdfasdf) my BufferedReader hangs on init. I've narrowed it down to init and not readLine() which I find weird. My code is as follows:

URL url = new URL("http://en.wikipedia.org/wiki/" + query.replace(" ", "_"));
URLConnection connection = url.openConnection();
BufferedReader wikiReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

Any code after the init of wikiReader never executes however this isn't a problem with wiki pages that exist...any help would be appreciated.


Answer:

I strongly suspect that it's not hanging - it's just throwing an exception without you noticing. I'd expect it to throw a FileNotFoundException, which is what happens when I tried it.

It's happening before readLine() because getInputStream() is going to make the HTTP request, and that's failing. It's never getting as far as the BufferedReader constructor itself - you can see this if you change the code to:

InputStream inputStream = connection.getInputStream();
// You won't get to here whne the page doesn't exist
BufferedReader wikiReader = new BufferedReader(new InputStreamReader(inputStream));

Basically, you need to look at where in your stack you're catching exceptions... and make sure it's appropriate. For a start, you should make sure you're logging the exception, and then work out what you want to do afterwards... that will very much depend on what your application does.

Question:

I want to write a client that can communicate to Vowpal Wabbit over TCP. Essentially, I need to send messages like a b | c d e to VW host over port 26542. VW responds with a message like 0.400000 0.200000 0.200000 0.200000 (not sure how the message terminates).

So, I need to do this multiple times - send message, receive message, send message, receive message, and so on.

I have the following code in Java.

public class MyClient {
    protected String host;
    protected int port;
    protected Socket socket;
    protected PrintWriter outputWriter;
    protected BufferedReader inputReader;

    public MyClient(String host, int port) throws IOException {
        socket = new Socket(host, port);
        outputWriter = new PrintWriter(socket.getOutputStream());
        inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    public void send(final String message) throws IOException {
        outputWriter.print(message+"\n"); // important to add a newline
        outputWriter.flush();

        String responseStr = inputReader.readLine();
        System.out.println(responseStr);
        if (StringUtils.isBlank(responseStr)) {
            return;
        }
    }
}

I use this class as follows:

MyClient client = new MyClient("host_ip", 26542); // the port used by VW
client.send("1:0.5:0.3 | feature11 feature21 feature31");
client.send("1:0.5:0.3 | feature12 feature22 feature32");
client.send("1:0.5:0.3 | feature13 feature23 feature33");

With the above code, only the response of the first "send" is printed. The other two return null responses.

I also tried with "send" only code:

    public void send(final String message) throws IOException {
        outputWriter.print(message+"\n"); // important to add a newline
        outputWriter.flush();
    }

It turns out that only the first message is sent (I have a way of verifying/logging on server side what it receives from my client).

Why is it that only the first send succeeds but all other sends fail (although no exception is raised)? How do I fix this?


Answer:

If readLine() returns null, the peer has closed the connection.

Question:

I am using this AES Encrption and decryption method for encrypting my data. There is no problem with udp but when i use tcp i get this error "javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher"

AES Encryption/Decryption Code:

    public class AESEncDec {

     private static final String ALGO = "AES";
    private static final byte[] keyValue =  new byte[] { 'T', 'h', 'e', 'B','e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };


public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        System.err.println("encVal: "+encryptedValue.length());

        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        //byte[] decValue = c.doFinal(encryptedData.getBytes());
        String decryptedValue = new String(decValue);
        System.err.println("decVal: "+decryptedValue.length());

        return decryptedValue;
    }
    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
}

}

TCP SERVER CODE:

    class TCPServer
    {
      public static void main(String argv[]) throws Exception
      {
          AESEncDec edData= new AESEncDec();
           // AES edData= new AES();

         String msg="Message_";
         String clientSentence="";
         String capitalizedSentence;
         ServerSocket welcomeSocket = new ServerSocket(6789);
         Socket connectionSocket = welcomeSocket.accept();
          for (int i = 0; i < 10; i++) 
         {
            clientSentence=edData.encrypt(msg+i)+"\n";
            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
            outToClient.writeBytes(clientSentence);
            Thread.sleep(100);
         }
      }
}

TCP CLIENT CODE:

    class TCPClient {

    public static void main(String argv[]) throws Exception {

        AESEncDec edData= new AESEncDec();
        String modifiedSentence;
        String DecData="";
        Socket clientSocket = new Socket("localhost", 6789);
        while(true){
         BufferedReader inFromServer = new BufferedReader(new  InputStreamReader(clientSocket.getInputStream()));
         modifiedSentence = inFromServer.readLine();
         DecData=edData.decrypt(modifiedSentence);
         System.out.println("FROM SERVER: " + DecData);   
        }

        //clientSocket.close();
    }
    }

For the Same code when the message is small it gets decrypted correctly. but when the message is long i get the illegalBlocksize Exception. I tried to use AES/CBC/PKCS5Padding so that the message gets padded and the blocksize comes in a multiple of 16. But still i get either the same error or BadPaddingException. if am specifying PKCS5Padding as the padding technique then the message should be padded correctly and shouldn't be giving this error. why isn't that working. What can i do to decrypt the data correctly. please help..


Answer:

The problem is that TCP gives you a stream. If you read a chunk and try to decrypt it, it may fail, because the size of the chunk may not be in multiples of 16 (or 128). AES works on 16 byte or 128 byte chunks of data. So, you may have to wait for a while till you gather that much amount of data before you decrypt.

Since UDP is message oriented, it doesn't face such problem.

@Kiara, Please use the Java8's built-in encoding and see how it works out. Refer here for documentation. Example:

String asB64 = Base64.getEncoder().encodeToString(data.getBytes("utf-8")); 

That was tested to work good with messages of lengths as much as 7 megabytes. It didn't introduce newlines into the encoded messages.

Question:

So I've been given a school exercise, where I am to make a chatserver in java. I've done it in TCP, but I could just aswell have done it in UDP.

I'm starting to do some thread implementations, but now I'm not really sure how I should approach it, and how many threads to make. So fare, this is my approach:

Server needs 1 thread for running, 1 thread for receiving messages, and 1 thread to send messages. Furthermore, I've made a thread for each Client connected, which the server puts in a ClientThread[], which is then used for messaging each client. This comes to a total of 13 threads ( 10 clients max )

Furthermore, I guess each local client needs a local thread, for sending and receiving messages aswell.

Is this the right approach here? Will it be problematic to have a server running 13 threads?

Thanks in advance!


Answer:

Your approach looks solid, but you don't really want to handle an array of so much client threads. You should use Threadpools

You store in memory a list of already initialized threads, you only open them at startup and close them at shutdown. every time a client/server needs to send a message, you will use a thread, then return it to the pool (instead of closing it). you can also configure a pool to grow on demand

Question:

I have a problem with my client - server apps which I developed in JAVA. I use Socket and ServerSocket from java.net* package. When client connect to the server, client sends message for example 7200 bytes. In server I use InputStream. Sometimes I receive whole message (7200 bytes), but many times I receive less than 7200 bytes. Is there any way in JAVA to receive whole message and close connection? Maybe should I use other library to tcp/ip connection in JAVA?


Answer:

Probably this will help: InputStream.read() documentation.

Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer.

This method will not block until the entire byte buffer filled up or stream end reached. Instead, it returns as much data as available at the moment.

This is not likely to happen when reading from files, but quite normal for sockets.

The actual number of bytes, which were written into byte-buffer is returned, so you can you that to decide if there's enough data.

You can use read(buf, start, len), to start not from beginning of buffer but continue data block. For example, if you are reading exactly 7200 bytes, do:

byte [] buf = new byte[7200];
int len = 7200;
int pos=0;

while(len > 0) {
  int rd = is.read(buf, pos, len);
  if(rd<0) {
      //premature EOF
      break;
  }
  pos += rd;
  len -= rd;
}

Otherwise if you do not know message length up front you have several options. Among them:

  1. Send message length as first 4 bytes, then always read 4 bytes first, then allocate buffer of necesary size and read into it
  2. Read into buffer until you receive "END-OF-MESSAGE" marker. Like, for example "END-OF-LINE". When you find it - stop reading and process message.

Question:

Does the transition of a Channel into the ChannelInactive state clear the associated pipeline? In a unit test, I'm observing that after a handler is added and then a client disconnects, attempting to remove the handler results in NoSuchElementFoundException. I'm struggling to explain this behavior and any guidance would be much appreciated.

My model of the possible Channel state's comes from "Netty in Action" which provides this diagram.


Answer:

Yes once a Channel becomes inactive and unregistered it will teardown the ChannelPipeline which means it will remove all previous added handlers.

Question:

So - I've created a TCP Server with Netty 4. The set up is simple, I'm using Netty's codecs to deal with serialisation.

I'm trying to filter based on IP address, it works but the channel is created and the handler is created. I dont want the handler to be created if its a filtered IP.

I add the filter in the server, here -

channelPipeline.addFirst(filter)

However my ServerHandler is always called first

channelPipeline.addLast(serverHandler)

The log:

Handler added - /127.0.0.1:58781 -- ServerHandler
2019-10-06 12:04:11.673 INFO - FILTER! - /127.0.0.1 -- Filter

I've tried to look for examples, but I'm finding it hard. I've also tried adding it in the same .addLast () Filter first with no joy.

TIA!

UPDATE

Thanks to Norman for his answer, as perhaps I was looking in the wrong area. Our ELB on AWS has a healthchecker, which is hitting the Server 4 times a second, when a genuine client connects, it doesn't receive a message back. If I disable the health checker -it works perfectly.

Any way to get around this?


Answer:

You will need to use something like iptables to filter on the kernel level.

Question:

I'm new to Java (basically had to learn it on the fly for this project), but I'm trying to send an XML command to a server (a sensor in my lab) to get some data from it. To do this, I've written a Java program and I'm running it from the command line. The connection establishes successfully, and (I think) the message is being successfully sent - however it is getting stuck "Awaiting a Response".

Here's my Java code for a reference. I got most of this from a client/server TCP tutorial, and adjusted the IP, port, and outgoing message accordingly. Again, I'm very new to this, so any help is appreciated.

// Java Socket Example - Client

import java.io.IOException; // Throws exception if there is an issue with input or output
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress; // This class represents an Internet Protocol address
import java.net.Socket;
import java.net.UnknownHostException;

/**
* This class implements java socket Client
*/

public class SocketClientExample {
	public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException, InterruptedException {
		// get the localhostIP address, if server is running on some other IP, use that 
		System.out.println("Attempting connection to GE Reuter Stokes");
		InetAddress host = InetAddress.getByName("10.212.160.4"); // IP GOES HERE
		Socket socket = null; // start out as null, protocal
		ObjectOutputStream oos = null; // This will change, just setting default
		ObjectInputStream ois = null;
		// establish the socket connection to the server
		socket = new Socket("10.212.160.4", 3010); // 9876 is just the port number
		System.out.println("Made it past Socket Initialization");
		// write to socket using ObjectOutputStream
		oos = new ObjectOutputStream(socket.getOutputStream()); // new instance of OOS that will write to the socket
		System.out.println("Sending request to Socket Server"); 
		// Initializing request string
		String request = new String("0xF00041 " + "<Discovery><CommChannelName>Unknown</CommChannelName></Discovery>");
		// In our version, this is where the XML script would go
		oos.writeObject(request);
		System.out.println("Request was sent. Awaiting response.");
		// read the server response message
		ois = new ObjectInputStream(socket.getInputStream());
		// convert the response into a string
		String message = (String) ois.readObject();
		System.out.println("Message: " + message);
		// close your resources
		ois.close();
		oos.close();
		Thread.sleep(100);
	}
}

Answer:

The sensor expects the XML to be preceded by a binary 5-byte header, but you are sending the header as an 8-character hex encoded string instead.

Also, you are using ObjectOutputStream and ObjectInputStream, which are meant for serializing Java objects, but you are not sending/reading Java objects. So these are the completely wrong stream classes to use.

So, your code is not sending what the sensor is expecting, so it will not receive your request correctly, let alone send a response that you can receive.

Try something more like this instead (assuming the sensor sends back a response in a similar header+XML format as the request):

import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import jva.io.BufferedInputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.ByteBuffer;

public class SocketClientExample {
    public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException, InterruptedException {
        System.out.println("Attempting connection to GE Reuter Stokes");

        // establish the socket connection to the server
        // using the local IP address, if server is running on some other IP, use that 
        Socket socket = new Socket("10.212.160.4", 3010);
        System.out.println("Socket Connected");

        // write to socket using OutputStream
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

        // Initializing request content
        byte[] request = "<Discovery><CommChannelName>Unknown</CommChannelName></Discovery>".getBytes(StandardCharsets.UTF_8);

        // DataOutputStream.writeInt() writes in big endian and
        // DataInputStream.readInt() reads in big endian.
        // using a ByteBuffer to handle little endian instead.

        byte[] header = new byte[5];
        ByteBuffer buf = ByteBuffer.wrap(header, 1, 4);
        buf.order(ByteOrder.LITTLE_ENDIAN);

        // Initializing request header
        header[0] = (byte) 0xF0;
        buf.putInt(request.length);

        System.out.println("Sending request to Socket Server"); 

        // Sending request
        dos.write(header);
        dos.write(request);
        dos.flush();

        System.out.println("Request was sent. Awaiting response.");

        // read from socket using InputStream
        DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

        // Read response header
        dis.readFully(header);
        buf.flip();

        // Read response content
        byte[] response = new byte[buf.getInt()];
        dis.readFully(response);

        // convert the content into a string
        String message = new String(response, StandardCharsets.UTF_8);
        System.out.println("Message: " + message);

        // close your resources
        dis.close();
        dos.close();
        socket.close();

        Thread.sleep(100);
    }
}

Question:

I have a small problem. I am new to multiplayer programming. My problem is that one packet that gets sent only gets sent to the last client. It can support 2 players easily, but 3 players doesn't fully work. The login and disconnect packets work, but not the move packet. Can you tell me what I'm missing or need to remove?

Client:

public class Client extends Thread{
private InetAddress ip;
private DatagramSocket dp;

public Client(String ia) {
    try {
    dp = new DatagramSocket();
    ip = InetAddress.getByName(ia);
    } catch (SocketException | UnknownHostException e) {
    e.printStackTrace();
    }
}

@Override
public void run() {
    while (true) {
        byte[] rdata = new byte[1024];
        DatagramPacket dg = new DatagramPacket(rdata, rdata.length);
        try {
            dp.receive(dg);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        byte[] data = dg.getData();
        String msg = new String(data).trim();
        switch (Packet.find(msg.substring(0, 2))) {
            default:
            case INVALID:
                break;
            case LOGIN:
                Login00 l = new Login00(data);
                if (getPlayer(l.getUser()) == null) {
                Main.visible.add(new MPlayer(100, 100, l.getUser(), dg.getAddress(), dg.getPort(), false));
                System.out.println("("+dg.getAddress().getHostAddress()+":"+dg.getPort()+") > " + msg.substring(2) + " has joined!");
                }
                break;
            case DISCONNECT:
                Dis01 d = new Dis01(data);
                Main.visible.remove(getPlayer(d.getUser()));
     System.out.println(("+dg.getAddress().getHostAddress()+":"+dg.getPort()+") > " + d.getUser() + " has left!");
                break;
            case MOVE:
                Move02 m = new Move02(data);
                handleMove(m);
                break;
        }
    }
}

public void sendData(byte[] data) {
    try {
    DatagramPacket dg = new DatagramPacket(data, data.length, ip, 1111);
    dp.send(dg);
    } catch (Exception ex) {
        //ex.printStackTrace();
    }
}



public MPlayer getPlayer(String u) {
    for (Player p : Main.visible) {
        if (p.user.equals(u)) {
            return (MPlayer) p;
        }
    }
    return null;
}

public int getPlayerId(String u) {
    int dex = 0;
    for (Player p : Main.visible) {
        if (p.user.equals(u)) {
            break;
        }
        dex++;
    }
    return dex;
}

private void handleMove(Move02 m) {
    int dex = getPlayerId(m.getUser());
    Main.visible.get(dex).moveTo(m.getX(), m.getY(), m.getUser());
}
}

Server:

public class Server extends Thread{
private DatagramSocket dp;
List<MPlayer> cplayers = new ArrayList<>();

public Server() {
    try {
    dp = new DatagramSocket(1111);
    } catch (SocketException e) {
    e.printStackTrace();
    }
}

@Override
public void run() {
    while (true) {
        byte[] rdata = new byte[1024];
        DatagramPacket dg = new DatagramPacket(rdata, rdata.length);
        try {
            dp.receive(dg);
        } catch (IOException ex) {
        }
        pp(dg.getData(), dg.getAddress(), dg.getPort());
    }
}

public void sendData(byte[] data, InetAddress i, int port) {
    try {
        DatagramPacket dg = new DatagramPacket(data, data.length, i, port);
        dp.send(dg);
    } catch (Exception ex) {
    }
}

public void sendDataAll(byte[] data) {
    for (MPlayer p : cplayers) {
        sendData(data, p.ip, p.port);
    }
}

private void pp(byte[] data, InetAddress address, int port) {
    String msg = new String(data).trim();
    types t = Packet.find(Integer.parseInt(msg.substring(0, 2)));
    Packet pp;
    switch (t) {
        default:
        case INVALID:
            break;
        case LOGIN:
            pp = new Login00(data);
            System.out.println("("+address.getHostAddress()+":"+port+") > " + ((Login00) pp).getUser() + " has joined!");
            MPlayer pl = new MPlayer(100, 100, ((Login00) pp).getUser(), address, port, false);
            addPlayer(pl, (Login00) pp);
            break;
        case DISCONNECT:
            pp = new Dis01(data);
            System.out.println("("+address.getHostAddress()+":"+port+") > " + ((Dis01) pp).getUser() + " has left!");
            removePlayer((Dis01) pp);
            break;
        case MOVE:
            pp = new Move02(data);
            handleMove((Move02) pp);
            break;
    }
}

public void addPlayer(MPlayer pl, Login00 l) {
    boolean ac = false;
    for (MPlayer p : cplayers) {
        p.ip = pl.ip;
        p.port = pl.port;
        if (Main.username.equalsIgnoreCase(l.getUser())) {
            ac = true;
        } else {
            sendDataAll(l.getData());
            Login00 ll = new Login00(p.user);
            sendData(ll.getData(), p.ip, p.port);
        }
    }
    if (true) {
        cplayers.add(pl);
        Main.visible.add(pl);
    } 

}

public void removePlayer(Dis01 dis) {
    Main.visible.remove(getPlayer(dis.getUser()));
    cplayers.remove(getPlayer(dis.getUser()));
    dis.write(this);
}

public MPlayer getPlayer(String u) {
    for (MPlayer p : cplayers) {
        if (p.user.equals(u)) {
            return p;
        }
    }
    return null;
}

public int getPlayerId(String u) {
    int dex = 0;
    for (Player p : Main.visible) {
        if (p.user.equals(u)) {
            break;
        }
        dex++;
    }
    return dex;
}

public void handleMove(Move02 m) {
        Integer dex = getPlayerId(m.getUser());
        Main.visible.get(dex).moveTo(m.getX(), m.getY(), m.getUser());
        m.write(this);
}
}

EDIT: So I figured out that i need to change the addPlayer method in the Server class to:

public void addPlayer(MPlayer pl, Login00 l) {
    cplayers.add(pl);
    Main.visible.add(pl);
    for (MPlayer p : cplayers) {
        sendDataAll(l.getData());
        Login00 ll = new Login00(p.user);
        sendDataAll(ll.getData());
    }
}

Answer:

When you add a player, you overwrite all existing player ip's and port's

// Server code
public void addPlayer(MPlayer pl, Login00 l) {
    boolean ac = false;
    for (MPlayer p : cplayers) {
        // At this point, you overwrite all existing player data
        p.ip = pl.ip; // overwrites existing player
        p.port = pl.port; // overwrites existing player
        if (Main.username.equalsIgnoreCase(l.getUser())) {
            ac = true;
        } else {
            sendDataAll(l.getData());
            Login00 ll = new Login00(p.user);
            sendData(ll.getData(), p.ip, p.port);
        }
    }
}

Question:

I create a small app with mixed mode of h2. Database is local and allow remote connections at the same time. Remote connection are by tcp. To start tcp server I use this code:

 public Server h2Server() throws SQLException {
        return Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092");
    }

Problem is that app server listen only on tcp6 (IPv6).

How can I change settings that app will listen on tcp (IPv4)?


Answer:

You can change it by starting java, i.e your app, with -Djava.net.preferIPv4Stack=true

Question:

I have an unknown number of peers that I will need to make TCP connections to. I'm running into a few problems and not certain whether my overall approach is correct. My current set up on the client side consists of a Peer Manager that shares its EventLoopGroup and creates clients as needed:

public class PeerManagement
{
  public PeerManagement()
  {
   // this group is shared across all clients
   _eventLoopGroup = new NioEventLoopGroup();
   _peers = new ConcurrentHashMap<>();
  }

  public void send(String s, String host)
  {
   // ensure that the peer exists
   setPeer(host);

   // look up the peer
   Peer requestedPeer = _peers.get(host);

   // send the request directly to the peer
   requestedPeer.send(s);
  }

  private synchronized void setPeer(String host)
  {
    if (!_peers.containsKey(host))
    {
     // create the Peer using the EventLoopGroup & connect
     Peer peer = new Peer();
     peer.connect(_eventLoopGroup, host);
     // add the peer to the Peer list
     _peers.put(host, peer);
    }
  }
}

The Peer class:

public class Peer
{
  private static final int PORT = 6010;

  private Bootstrap _bootstrap;
  private ChannelFuture _channelFuture;

  public boolean connect(EventLoopGroup eventLoopGroup, String host)
  {
    _bootstrap = new Bootstrap();
    _bootstrap.group(eventLoopGroup)
   .channel(NioSocketChannel.class)
   .option(ChannelOption.SO_KEEPALIVE, true)
   .handler(new ChannelInitializer<SocketChannel>()
   {
    @Override
    public void initChannel(SocketChannel socketChannel) throws Exception
    {
        socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder( 1024,0,4,0,4));
        socketChannel.pipeline().addLast(new LengthFieldPrepender(4));
        socketChannel.pipeline().addLast("customHandler", new CustomPeerHandler());
      }
    } );

   // hold this for communicating with client
   _channelFuture = _bootstrap.connect(host, PORT);
   return _channelFuture.syncUninterruptibly().isSuccess();
  }

  public boolean send(String s)
  {
   if (_channelFuture.channel().isWritable())
   {
    // not the best method but String will be replaced by byte[]
    ByteBuf buffer = _channelFuture.channel().alloc().buffer();
    buffer.writeBytes(s.getBytes());

    // NEVER returns true but the message is sent
    return _channelFuture.channel().writeAndFlush(buffer).isSuccess();
   }
   return false;
  }

}

If I send the following string "this is a test" then writeAndFlush.isSuccess() is always false but sends the message and then I get the following on the server side:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| ff 00 00 00 00 00 00 00 01 7f                   |..........      |
+--------+-------------------------------------------------+----------------+

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 0e 74 68 69 73 20 69 73 20 61 20 74 65 |....this is a te|
|00000010| 73 74                                           |st              |
+--------+-------------------------------------------------+----------------+
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1024: 4278190084 - discarded

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| ff 00 00 00 00 00 00 00 01 7f                   |..........      |
+--------+-------------------------------------------------+----------------+
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1024: 4278190084 - discarded

Answer:

The reason that writeAndFlush().isSuccess() returns false is that, like all outbound commands, writeAndFlush() is asynchronous. The actual write is done in the channel's event loop thread, and this just hasn't happened yet when you call isSuccess() in the main thread. If you want to block and wait for the write to complete you could use:

channel.writeAndFlush(msg).sync().isSuccess();

The error you see on the server side is because of this frame that arrives before your "this is a test" message:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| ff 00 00 00 00 00 00 00 01 7f                   |..........      |
+--------+-------------------------------------------------+----------------+

The LengthFieldBasedFrameDecoder tries to decode the first 4 bytes ff 00 00 00 as the length, which is obviously too large. Do you know what is sending this frame? Could it be your CustomPeerHandler?

Question:

I see this "Input length must be multiple of 16 when decrypting with padded cipher" error when I run the program

RealEchoServer.java

import java.io.*;
import java.net.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RealEchoServer {

public static void main(String[] args) {
    int i = 1;
    try {
        ServerSocket s = new ServerSocket(9003);

        for (;;) {
            Socket incoming = s.accept();
            System.out.println("Spawning " + i);
            new RealEchoHandler(incoming, i).start();
            i++;
        }
    } catch (Exception e) {
        System.out.println(e);
    }
 }
}

class RealEchoHandler extends Thread {

DataInputStream in;
DataOutputStream out;
private Socket incoming;
private int counter;

public RealEchoHandler(Socket i, int c) {
    incoming = i;
    counter = c;
}

public void run() {
    try {

        String key1 = "1234567812345678";
        byte[] key2 = key1.getBytes();
        SecretKeySpec secret = new SecretKeySpec(key2, "AES");
        String msg = "Singapore Malaysia Japan India Indonesia HongKong Taiwan China England";
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] encrypted = cipher.doFinal(msg.getBytes());

        in = new DataInputStream(incoming.getInputStream());
        out = new DataOutputStream(incoming.getOutputStream());

        boolean done = false;
        String str = "";
        out.writeUTF("Connected!\n");
        out.flush();
        while (!done) {
            out.writeUTF(">");
            out.flush();
            str = in.readUTF();
            System.out.println(in + ":" + str);
            if (str == null) {
                done = true;
            } else {
                System.out.println("Sending Ciphertext : " + new String(encrypted));
                out.writeUTF(new String(encrypted));
                out.flush();
            }
        }
        incoming.close();
    } catch (Exception e) {
        System.out.println(e);
    }
 }
}

RealSocketTest.java

   import java.io.*;
   import java.net.*;
   import java.security.*;
   import javax.crypto.*;
   import javax.crypto.spec.*;
   import java.util.*;

 class RealSocketTest {
 public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

    String str = "";
    String str2 = "";
    DataOutputStream out;
    DataInputStream in;

    try {
        Socket t = new Socket("127.0.0.1", 9003);
        in = new DataInputStream(t.getInputStream());
        out = new DataOutputStream(t.getOutputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        boolean more = true;
        System.out.println(in.readUTF());

        while (more) {
            str = in.readUTF();
            System.out.print(str);
            str2 = br.readLine();
            out.writeUTF(str2);
            out.flush();
            str = in.readUTF();

            System.out.println("Encrypted Info: " + str);

            try {

                String key1 = "1234567812345678";
                byte[] key2 = key1.getBytes();
                SecretKeySpec secret = new SecretKeySpec(key2, "AES");
                Cipher cipher = Cipher.getInstance("AES");
                cipher.init(Cipher.DECRYPT_MODE, secret);
                byte[] decrypted = cipher.doFinal(str.getBytes());
                System.out.println("Decrypted Info: " + new String(decrypted));
            } catch (BadPaddingException e) {
                System.out.println("Wrong Key!");
            } catch (InvalidKeyException f) {
                System.out.println("Invalid Key!");
            }
        }
    } catch (IOException e) {
        System.out.println("Error");
    }
  }
}

I've read a similar problem here Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher , but I don't understand how I could change mine, because it looks very different from mine.

So what should be added/changed to get it decrypted?


Answer:

The problem is that ciphertexts may contain every possible byte value. Many byte values on the other hand are not printable and therefore not a valid UTF-8 encoding. When you make a String out of it new String(encrypted), it will silently drop some bytes and you won't be able to successfully decrypt the ciphertext.

Two possible fixes:

  • Encode the ciphertext as Base64 or Hex to be used in a text-based protocol.
  • Use the DataOutputStream::write() method to make it a binary protocol without encoding it.

Other security stuff:

  • Always specify the complete String for the expected Cipher instance. Different providers might have different defaults and it may happen that client and server don't use the same method. Example: AES/ECB/PKCS5Padding.

  • Never use ECB mode. It is not semantically secure. At least use CBC with a random IV (prepend the IV in front of the ciphertex or write it to the stream in order).

  • Check your ciphertext for manipulation. This is easily done, by employing an authenticated mode like GCM (AES/GCM/NoPadding with GCMParameters). If you don't want that, then at least try to implement an encrypt-then-MAC scheme where you HMAC the ciphertext (with a different key) and check it before decryption.

Question:

I just started using Spring-Integration, and I implemented the TCP server which just sends a "OK" message to the client. I would like to log the client IP address and the text received from the client.

I am able to successfully obtain the text sent by the client with the below configuration files, but I don't know how to obtain the IP address of the client.

Below is configuration file of the TCP server.

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:int="http://www.springframework.org/schema/integration"
   xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">

<context:property-placeholder />
<int-ip:tcp-connection-factory id="tcpServer"
                               type="server"
                               using-nio="true"
                               port="${tcpServer.port}"/>

<int-ip:tcp-inbound-gateway id="tcpGateway"
                            connection-factory="tcpServer"
                            request-channel="bytesChannel"
                            error-channel="errorChannel"/>


<int:service-activator input-channel="inputChannel" ref="myTcpService" method="processInput"/>

<bean id="myTcpService" class="MyTcpService" />

<int:transformer id="transformerBytes2String"
                 input-channel="bytesChannel"
                 output-channel="inputChannel"
                 expression="new String(payload)"/>

<int:transformer id="errorHandler"
                 input-channel="errorChannel"
                 expression="payload.failedMessage.payload + ':' + payload.cause.message"/>

<int:channel id="inputChannel" />
<int:channel id="bytesChannel"/>

</beans>

MyTcpService class:

public class MyTcpService  {
    public String processInput(String input){
       return "OK";
    }
}

I would like to know if it is possible to get the IP address along with the payload in the "processInput" method.


Answer:

Several connection attributes are stored in the MessageHeaders (TcpMessageMapper):

messageBuilder
        .setHeader(IpHeaders.HOSTNAME, connection.getHostName())
        .setHeader(IpHeaders.IP_ADDRESS, connection.getHostAddress())
        .setHeader(IpHeaders.REMOTE_PORT, connection.getPort())
        .setHeader(IpHeaders.CONNECTION_ID, connectionId);

Hence you can simple add one more argument to your processInput method to get a value from desired header:

public String processInput(String input, @Header(IpHeaders.IP_ADDRESS) String ip){

When the input argument without any annotations remains mapped to the payload.

Question:

Basically I'm writing a 2 way communication client server program. The client sends requests to the server and server responds accordingly. The requests have to do with adding or removing tokens from a list of tokens stored on the server. The client side seems to work fine, the requests are being sent to the server. However it seems that the server is not receiving any request from the client and I have no idea why. I've attached the code:

client

package;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class TokenClient {

    private static final int PORT_NUMBER = 9999;

    private Socket socket;

    private InputStream inStream;

    private OutputStream outStream;

    private Scanner inStreamScanner;

    private PrintWriter outStreamPrinter;

    public static void main(String[] args) {

        new TokenClient().go();

    }

    void go() {

        try {

            System.out.println(
                    "Enter commands of the form \"CONNECT IP-address\", \"SUBMIT token\", \"REMOVE token\" or \"QUIT\"\n");

            Scanner consoleScanner = new Scanner(System.in);
            // java.io.BufferedReader consoleInputReader = new
            // BufferedReader(new InputStreamReader(System.in));

            String command = "";

            while (!command.equals("QUIT") && consoleScanner.hasNextLine()) {

                command = consoleScanner.nextLine(); // consoleInputReader.readLine();

                processCommand(command);

            }

            System.out.println("Goodbye!");

            consoleScanner.close();

        } catch (IOException e) {

            System.out.println("An exception occurred: " + e);

            e.printStackTrace();

        }

    }

    void processCommand(String userCommand) throws IOException {

        if (userCommand.startsWith("SUBMIT"))  

            sendMessageToServer(userCommand);

        else if (userCommand.startsWith("REMOVE"))

            sendMessageToServer(userCommand);

        else if (userCommand.equals("QUIT"))

            closeConnectionToServer();

        else if (userCommand.startsWith("CONNECT")) {

            closeConnectionToServer();

            connectToServer(userCommand);

        } else
            System.out.println("Invalid user command: " + userCommand);

    }

    void closeConnectionToServer() {

        if (socket != null && !socket.isClosed()) {

            try {

                System.out.println("Disconnecting from server...");

                sendMessageToServer("QUIT");

                socket.close();

                System.out.println("Connection to server closed.");

            } catch (IOException e) {
                System.out.println("An exception occurred: " + e);
                e.printStackTrace();
            }
        }
    }

    void connectToServer(String connectCommand) throws IOException {
        String ipAddress = connectCommand.substring(8).trim();
        System.out.println("Connecting to server at " + ipAddress + ", port " + PORT_NUMBER + "...");
        socket = new Socket(ipAddress, PORT_NUMBER);
        inStream = socket.getInputStream();
        outStream = socket.getOutputStream();
        inStreamScanner = new Scanner(inStream);
        outStreamPrinter = new PrintWriter(outStream);
        System.out.println("Connected to server.");

    }

    void sendMessageToServer(String command) {

        System.out.println("Sending message to server: " + command + "...");

        if (socket == null || socket.isClosed())
            System.out.println("Not possible - not connected to a server");
        else {

            outStreamPrinter.println(command); // send the message to the server

            // NB: client doesn't check if tokens are valid

            outStreamPrinter.flush(); // do so immediately

            // Receive response from server:

            if (!command.equals("QUIT") && inStreamScanner.hasNextLine()) {
                String response = inStreamScanner.nextLine();
                System.out.println("Response from server: " + response);
            }
        }
    }
}

server

package;

import java.net.*;
import java.util.ArrayList;
import java.util.Scanner;
import java.io.*;

public class server {
    private static Socket s;
    private static Scanner inStreamScanner;
    private static int PORT_NUMBER = 9999;
    private static InputStream inStream;
    private static OutputStream outStream;
    private static PrintWriter outStreamPrinter;
    private static ArrayList<String> ts = new ArrayList<String>();
    public static void main(String[] args) throws IOException{
        ServerSocket ss = new ServerSocket(PORT_NUMBER);
        server serverInstance = new server();
        server.s = ss.accept();
        System.out.println("Client connected");
        inStream = s.getInputStream();
        outStream = s.getOutputStream();
        inStreamScanner = new Scanner(inStream);
        outStreamPrinter = new PrintWriter(outStream);
        serverInstance.run();
    }
    public void run() {
        try {
            try {
                doService();
            } finally {
                s.close();
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }
    public void doService() throws IOException{
        while(true) {
            if(inStreamScanner.hasNext())
                return;
            else {
                outStreamPrinter.println("NO REQUEST");
                outStreamPrinter.flush();
            String request = inStreamScanner.next();
            outStreamPrinter.println("Request received: " +request);
            outStreamPrinter.flush();
            handleServerRequest(request);
        } 
        }
    }
    public void handleServerRequest(String request) throws IOException{
        if(request.startsWith("SUBMIT")) {
            String token = extractNum(request);
            addtoTS(token);
        } else if(request.startsWith("REMOVE")) {
            String token = extractNum(request);
            removefromTS(token);
        } else if(request.startsWith("QUIT")) {
            s.close();
        } else {
            outStreamPrinter.println("UNKNOWN REQUEST");
            outStreamPrinter.flush();
        }
    }
    public String extractNum(String request) {
        String str = request;
        String numberOnly = str.replaceAll("[^0-9]", " ");
        return numberOnly;
    }
    public void addtoTS(String token) {
        if(ts.contains(token)) {
            outStreamPrinter.println("OK");
            outStreamPrinter.flush();
        }else {
            ts.add(token);
            outStreamPrinter.println("OK");
            outStreamPrinter.flush();
        }
    }
    public void removefromTS(String token) {
        if(ts.contains(token)) {
            ts.remove(token);
            outStreamPrinter.println("OK");
            outStreamPrinter.flush();
        }else {
            outStreamPrinter.println("ERROR: TOKEN NOT FOUND");
            outStreamPrinter.flush();
        }
    }
}

Answer:

I haven't run the code, but there seems to be an issue in your doService() method on the server side. You have an infinite loop, but the entire method returns (and thus the program also quits) as soon as the input stream recieves a new line character (when the client sends a request). So, it seems your program would quit when it receives the first command from the client. I'd also recommend closing more gently (ie check in the loop for end rather than closing the socket directly).

So, I'd define a private class variable boolean listening; or something like that. Then in the main() method, set it to true after the socket has been initialized (when the client has connected).

Change your doService() to something similar to the following:

public void doService() throws IOException
{
  while(listening)
  {
    if(inputStreamReader.hasNext())
    {
      String request = inStreamScanner.next();
      outStreamPrinter.println("Request received: " +request);
      outStreamPrinter.flush();
      handleServerRequest(request);
    }
  }
}

And change how you handle the QUIT command:

from

else if(request.startsWith("QUIT"))
{
  s.close();
}

to

else if(request.startsWith("QUIT"))
{
  listening = false;
}

The socket will be closed by the finally in run().

Question:

I'm doing a program by sockets, from a single client to multiple servers, on the internet I have not found information about this

The system consists of connecting multiple servers to a single client, the client must request a number from a user, then, in the server, with that number an algorithm will be executed that will find the number of prime numbers between 0 and N , afterwards, the execution time of the algorithm is calculated, and then sent to the client. Each time of each server is sent to the client and the client stores them.

The problem is that this connection must be simultaneous between the number of servers to be desired, in addition to this connection being synchronized.

For the moment, I have made a simple code, from a client to a server.

MAIN SERVER

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Server s = new Server(5000, "Hilo servidor");
    s.start();
    }

}

MODULE SERVER

This is a method that is inside the server class, this class executes the algorithm to count how many cousins there are and to send that time to the client. It runs when calling c.start () in the main server

private void startServer() {

            try {
                ServerSocket ss = new ServerSocket(port);
                System.out.println("Esperando Conexion");
                Socket socket = ss.accept();


                DataInputStream in = new DataInputStream(socket.getInputStream());
                int n = in.readInt();
                long time = encontrarPrimeros(n);
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                out.writeLong(time);
                System.out.println(time);
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
}

MAIN CLIENT

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
            Client c = new Client("Hilo cliente", 5000, "192.168.0.19");
            c.start();
    }

}

MODULE CLIENT

    private void startClient() {
            try {
                    Socket socket = new Socket(ip, port); 
                    DataOutputStream out = new DataOutputStream(socket.getOutputStream());


                    System.out.println("Ingrese dato...");
                    Scanner scanner = new Scanner(System.in);
                    int n = scanner.nextInt();
                    out.writeInt(n);
                    DataInputStream in = new DataInputStream(socket.getInputStream());
                    long tiempo = in.readLong();
                    System.out.println(tiempo);
                    socket.close();
            } catch (IOException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
    }

The problem is, how can I connect several servers to a client, so they start synchronized?

Thank you

Update

I have modified the client's main method, because of this:

public class Main {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    Client c = new Client("Hilo cliente", 5000, "192.168.0.19");
    Client c2 = new Client("Hilo cliente", 5000, "192.168.0.19");
    c.start();
    c2.start();
}

}

But when executing, I get the following error:

mar 23, 2019 7:14:10 PM Client startClient
GRAVE: null
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:210)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.io.DataInputStream.readFully(DataInputStream.java:195)
    at java.io.DataInputStream.readLong(DataInputStream.java:416)
    at Client.startClient(Client.java:69)
    at Client.run(Client.java:41)
    at java.lang.Thread.run(Thread.java:748)

The instruction where the error is executed is the following: long tiempo = in.readLong();


Answer:

Actually, in socket programming:

  • a client can only connect to one server
  • a server can receive many client connections
  • The client manages his connection to the server through a socket object

If your client needs to connect to many servers, the client must create as many socket objects as the number of servers. And in order to manage the communication in parallel, you can create a separate thread on which you manage the IO for each socket.

So applied to your scenario:

  • you can keep your Client class as it manages one socket
  • you create N objects of the Client in the number of servers (you associate each Client instance with only one server)
  • you can make your Client class runnable (by inheriting from Thread class).
  • you run your Client as a thread (you can place the startClient() class in the protected void run() method that you inherit from Thread).
  • In your main you call each client object start() method (inherited from thread). this will run the run() method in background.
  • to collect all the results, you call join() on each Client object

Client Class Example

    public class Client extends Thread {

    private String ip;
    private int port;


    public Client(String serverIP, int serverPort) {
        this.ip = new String(serverIP);
        this.port = serverPort;
    }

    private void startClient() {
        try {
            Socket socket = new Socket(ip, port); 
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());

            System.out.println("Ingrese dato...");
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt();
            out.writeInt(n);
            DataInputStream in = new DataInputStream(socket.getInputStream());
            long tiempo = in.readLong();
            System.out.println(tiempo);
            socket.close();
        } catch (IOException ex) {
            ex.getStackTrace();
        }
    }

    @Override
    public void run() {

        startClient();

        super.run();
    }
}

Main

Client client1 = new Client("192.168.1.100", 8888);
    Client client2 = new Client("192.168.1.101", 8888);
    Client client3 = new Client("192.168.1.102", 8888);

    client1.start();
    client2.start();
    client3.start();

    try {
        client1.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    try {
        client2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    try {
        client3.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

Server Class

public class Server extends Thread {


ExecutorService threadPool = Executors.newCachedThreadPool();

//Private class
class ClientSocket implements Runnable {

    private Socket m_socket;

    ClientSocket(Socket sock) {
        m_socket = sock;
    }

    @Override
    public void run() {
        try {
            DataInputStream in = new DataInputStream(m_socket.getInputStream());
            int n = in.readInt();
            long time = n;
            DataOutputStream out = new DataOutputStream(m_socket.getOutputStream());
            out.writeLong(time);
            out.flush();
            System.out.println(time);
            System.out.flush();
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}


@Override
public void run() {
    startServer();
    super.run();
}

private void startServer() {

    try {
        ServerSocket ss = new ServerSocket(8888);
        System.out.println("Esperando Conexion");

        do {
            Socket socket = ss.accept();

            threadPool.execute(new ClientSocket(socket));

        } while(true);

    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
}
}

Question:

I am trying to develop software for torque. I connect to device by java sockets, but I don't know how to establish session with torque. Establish communication steps:

me(client):send- MID 0001

torque(server):send- MID 0002

To do this I have to convert message MID 0001 to OPEN Protocol, according to documentation the result is:002000010000000000000 When I send this message server don't answer. Maybe my message isn't converted to Open protocol good?

I was trying with sending message as bytes or string. Anyone know how to establish connection with Stanley torque using alpha open protocol and Java?

My client code:

     public class MyClientSocket {
        private static Socket socket;

        public static void main(String args[]) {


            try {
                String host = "192.168.1.15";
                int port = 4545;
                InetAddress address = InetAddress.getByName(host);
                socket = new Socket(address, port);

                //Send the message to the server
                DataOutputStream os = new DataOutputStream(socket.getOutputStream());

                String sendMessage = "002000010000000000000";

                byte[] bytes = sendMessage.getBytes(StandardCharsets.US_ASCII);


                os.write(bytes);
//              os.writeUTF(sendMessage);

                System.out.println("Message sent to the server : " + sendMessage);

                //Get the return message from the server
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String message = br.readLine();
                System.out.println("Message received from the server : " + message);


            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

this is output:

    Message sent to the server : 002000010000000000000
Message received from the server : null

Process finished with exit code 0

Please help me.


Answer:

I found solution by myself. The last zero in message is end message zero and i had to wrote message like this:

"00200001000000000000\0"

Question:

Can we run multiple clients & 1 server on a single machine? Let's say I have a server class (thread for multiple connections) and a client class as well. I want to run at least 2 clients at the same time but they have separate chat window(Server to client but not Group chat). Is it Possible? I have this code

public void server(){
    ss = new ServerSocket(port);

    chatprocess cp = new chatprocess(socket);// accept connection inside and input/output as well
}

public client(){
    socket = new socket("localhost",port);
    clientprocess(); //i/o inside
}

Answer:

Yes.

In order to do that you must create a thread assigned for each client. There are a lot of examples here in SO.

Question:

Good evening, I'm trying to pass a text data from a TextView from MainActivity to Client.class ( TCP client ) and set it to another string ( actually i'm passing IP set in a TextView in MainActivity and just trying to load it in Client.class ) but when i'm trying to visualize it with a toast ( for test if i've passed the variable there is a stuff like this )

Here Client code :

public class Client {

static Intent intent = getIntent();
static String getIp = intent.getExtra("key");
private String serverMessage;
public static final String SERVERIP = getIp; //your computer IP address
public static final int SERVERPORT = 4444;
private OnMessageReceived mMessageListener = null;
private boolean mRun = false;

MainActivity main;
PrintWriter out;
BufferedReader in;
/**
 *  Constructor of the class. OnMessagedReceived listens for the messages received from server
 */
public Client(OnMessageReceived listener) {
    mMessageListener = listener;
}

/**
 * Sends the message entered by client to the server
 * @param message text entered by client
 */
public void sendMessage(String message){
    if (out != null && !out.checkError()) {
        out.println(message);
        out.flush();
    }
}

public void stopClient(){
    mRun = false;
}

public void run() {

    mRun = true;

    try {
        //here you must put your computer's IP address.
        InetAddress serverAddr = InetAddress.getByName(SERVERIP);

        Log.e("TCP Client", "C: Connecting...");

        //create a socket to make the connection with the server
        Socket socket = new Socket(serverAddr, SERVERPORT);

        try {

            //send the message to the server
            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

            Log.e("TCP Client", "C: Sent.");

            Log.e("TCP Client", "C: Done.");

            //receive the message which the server sends back
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //in this while the client listens for the messages sent by the server
            while (mRun) {
                serverMessage = in.readLine();

                if (serverMessage != null && mMessageListener != null) {
                    //call the method messageReceived from MyActivity class
                    mMessageListener.messageReceived(serverMessage);
                }
                serverMessage = null;

            }

            Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + serverMessage + "'");

        } catch (Exception e) {

            Log.e("TCP", "S: Error", e);

        } finally {
            //the socket must be closed. It is not possible to reconnect to this socket
            // after it is closed, which means a new socket instance has to be created.
            socket.close();
        }

    } catch (Exception e) {

        Log.e("TCP", "C: Error", e);

    }

}

//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
//class at on asynckTask doInBackground
public interface OnMessageReceived {
    void messageReceived(String message);
}

}

MainActivity :

        Intent i = new Intent(MainActivity.this, Client.class);
        i.putExtra("STRING_I_NEED", String.valueOf(indr));

Answer:

In you MainActivity do something like this:

Intent i = new Intent(MainActivity.this, Client.class);
i.putextra("key", IPTextView);
// IPTextView is the IP address you want to toast

and in your Client class do the following:

String getIp = getIntent.getExtra("key")

The you can Toast it like:

Toast.makeText(context, getIp, Toast.LENGTH_SHORT).show();

The Other option you have is to save the IP address in SharedPreferences and get it back in Client class


Or you can create a static method with some return value, then you can get the IP in Client class through class name.

Question:


Answer:

(I agree in that multithreading would be an improvement for high availability and performance, though it's not strictly necessary.)

If you want an scheme like this:

                          { ---> slave server 1
client ---> master server { ---> slave server 2
                          { ---> slave server 3

... then, you'll have to add to the master server a client API, because it will have a double role: As a server, to receive requests from the client/s, and as a client to send requests to the slave servers.

If you have already implemented a client/server communication protocol, then it would be useful to reuse that same protocol for communicate master/slave servers.

You must also address the binding matter: How does the master know how many and which slaves there are?

  • If they run in the same host, the master itself could start the slaves.
  • If they run in different hosts, you'll have to provide this addressing information to the master: Either by static configuration in the master, either by making the slaves send the master an address message as soon as each one of them is started (this implies a complication in the master/slave protocol).

And there's still the availability problem: What if one of the slaves shuts down?

  • If the network data is wisely distributed between the slaves, in order to produce a high amount of redundant data, the problem gets solved just making the master poll the slaves one by one until he gets all the needed data (of corse, this will still serve for just one or two slaves being off simultaneously; if many of the slaves shut down, there can be no gurantee to maintain the data available. Redundancy has a limit).
  • If there is no redundancy at all, the master will have to detect this situation, and react properly:
    • If they run in the same host, the master can re-start any of the servers dynamiclly.
    • If they run in different hosts, the master can do no other thing than report the problem to the client through an apporpiate error message.

Data synchronization can be an issue if they share writable data. In this case, the master will have to broadcast the same writing to each affected slave.

Question:

This is my TCP client java code:

socket = new Socket("127.0.0.1", 8088);
out = new DataOutputStream(socket.getOutputStream());
inputStream = socket.getInputStream();
inputReader = new BufferedReader(new InputStreamReader(inputStream));
String result = "";
while (inputStream != null) {
    result += inputReader.readLine();
}
out.writeUTF(result);
System.out.println(result);

socket.close();
out.close();

The while loop is getting executed infinitely.

I need a solution for this problem.


Answer:

You need to check when readLine() returns null, not when inputStream becomes null (which it never will):

string s = inputReader.readLine();
while (s != null) {
    result += s;
    s = inputReader.readLine();
}

Or:

string s;
while ((s = inputReader.readLine()) != null) {
    result += s;
}

Question:

So I'm bounding my Java ServerSocket to 0.0.0.0. Imagine my machine has 3 network interfaces, each one with its own IP address. Now I want to programmatically discover the IP address that my clients can use to connect to my recently created ServerSocket. Calling:

serverSocket.getLocalSocketAddress()

or

serverSocket.getInetAddress()

Returns "0.0.0.0", which is of course what I don't want.

Any ideas?


Answer:

You can't get that information from the ServerSocket. You have to enumerate the actual interfaces separately, using NetworkInterface.getNetworkInterfaces() and NetworkInterface.getInetAddresses().

Per Listing Network Interface Addresses in the Java documentation:

One of the most useful pieces of information you can get from a network interface is the list of IP addresses that are assigned to it. You can obtain this information from a NetworkInterface instance by using one of two methods. The first method, getInetAddresses(), returns an Enumeration of InetAddress. The other method, getInterfaceAddresses(), returns a list of java.net.InterfaceAddress instances. This method is used when you need more information about an interface address beyond its IP address. For example, you might need additional information about the subnet mask and broadcast address when the address is an IPv4 address, and a network prefix length in the case of an IPv6 address.

The following example program lists all the network interfaces and their addresses on a machine:

import java.io.*;
import java.net.*;
import java.util.*;
import static java.lang.System.out;

public class ListNets {

    public static void main(String args[]) throws SocketException {
        Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
        for (NetworkInterface netint : Collections.list(nets))
            displayInterfaceInformation(netint);
    }

    static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
        out.printf("Display name: %s\n", netint.getDisplayName());
        out.printf("Name: %s\n", netint.getName());
        Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
        for (InetAddress inetAddress : Collections.list(inetAddresses)) {
            out.printf("InetAddress: %s\n", inetAddress);
        }
        out.printf("\n");
     }
}  

The following is sample output from the example program:

Display name: TCP Loopback interface
Name: lo
InetAddress: /127.0.0.1

Display name: Wireless Network Connection
Name: eth0
InetAddress: /192.0.2.0

Question:

The problem am having is that am not sure how to enable multiple clients to communicate with the server through threading, i've attempted it but I think am doing something wrong. Any help will be appreciated.

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
    ArrayList clientOutputStreams;

    public class ClientHandler implements Runnable {
        BufferedReader reader;
        Socket sock;

        public ClientHandler(Socket clientSocket) {
            try {
                sock = clientSocket;
                InputStreamReader isReader = new InputStreamReader(
                        sock.getInputStream());
                reader = new BufferedReader(isReader);
            } catch (Exception x) {

            }
        }

        public void run() {
            String message;
            try {
                while ((message = reader.readLine()) != null) {
                    System.out.println("read" + message);
                    tellEveryone(message);
                }
            } catch (Exception x) {

            }
        }
    }

    public void go() {
        clientOutputStreams = new ArrayList();
        try {
            ServerSocket serverSock = new ServerSocket(5000);

            while (true) {
                Socket clientSocket = serverSock.accept();
                PrintWriter writer = new PrintWriter(
                        clientSocket.getOutputStream());
                clientOutputStreams.add(writer);

                Thread t = new Thread(new ClientHandler(clientSocket));
                t.start();
                System.out.println("got a connection");
            }
        } catch (Exception x) {

        }
    }

    public void tellEveryone(String message) {
        Iterator it = clientOutputStreams.iterator();
        while (it.hasNext()) {
            try {
                PrintWriter writer = (PrintWriter) it.next();
                writer.println(message);
                writer.flush();
            } catch (Exception x) {

            }
        }
    }

    public static void main(String[] args) {
        new ChatServer().go();
    }`enter code here`

}

Answer:

To allow multiple client to connect to your server you need a server to be continually looking for a new client to connect to. This can be done like:

while(true) {
    Socket socket = Ssocket.accept();
    [YourSocketClass] connection = new [YourSocketClass](socket);
    Thread thread = new Thread(connection);
    thread.start();
}

This is probably also best done in a separate server java file that can run independent of the client.

Question:


Answer:

Ok just thinking out loud here: In the first scenario you don't really need to know the item from the list has anything to do with a TCP connection until you actually go to make the connection. Until then it's a hostname from a list you pulled from a database query. At the point of connection it's a simple connect() to a given host and do what you need.

In the second scenario I think perhaps you'd be better served using a UDP service. In this case the server would simply get a queue of messages from the various clients. If you use TCP each client forces its own channel (port mapping) so that every channel has only one client. You are then forced to use either select() to choose a connection to service, or write your app multithreaded to service them all at once upon connection. UDP is just simpler.

Question:

I want to create a chatroom that in it 3 (or more device ) connect to a server with Tcp protocol on hotspot and server and clients cant talk to each other this is my code that in when app start it try to connected to server (if existed) if it don't find server then it run server socket an wait for client but only one client can connect to server and send and receive message i know that i have to use multi-thread but i can't handle this please help me:(

 package com.app.wifi_chat;
    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import com.uncocoder.app.wifi_chat.R;
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.KeyEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;


    public class WifiChatActivity extends Activity {

    private Handler          handler = new Handler();
    private TextView         text;
    private EditText         input;
    private Button           btnSend;
    private Socket           socket;
    private DataOutputStream outputStream;
    private BufferedReader   inputStream;

//try to connect to server if find it return true 
    private boolean searchNetwork() {
        log("Connecting...");

        String range = "192.168.1.";
        for (int i = 1; i <= 255; i++) {
            String ip = range + i;
            try {
                //log("Try IP: " + ip);
                socket = new Socket();
                socket.connect(new InetSocketAddress(ip, 9000), 10);

                log("Connected!");
                return true;
            }
            catch (Exception e) {}
        }

        return false;
    }

//run server and wait for new client
    private void runChatServer() {
        try {
            log("Waiting for client...");

            ServerSocket serverSocket = new ServerSocket(9000);
            socket = serverSocket.accept();

            log("A new client Connected!");
        }
        catch (IOException e) {}
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView) findViewById(R.id.text);
        input = (EditText) findViewById(R.id.input);
        btnSend = (Button) findViewById(R.id.btnSend);

        //server
        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
//first time check for connect to server if not to find it then run server and wait for client
                if ( !searchNetwork()) {
                    runChatServer();
                }

                try {
                    outputStream = new DataOutputStream(socket.getOutputStream());
                    inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                }
                catch (IOException e1) {
                    log("Error: Connection is not stable, exit");
                    shutdown();
                }
//listen to client for get messeage
                while (true) {
                    try {
                        String message = inputStream.readLine();
                        if (message != null) {
                            log(message);
                        }
                    }
                    catch (IOException e) {}
                }
            }
        });
//send message to client or server
        btnSend.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (outputStream == null) {
                    return;
                }

                try {
                    String message = input.getText().toString() + "\n";
                    outputStream.write(message.getBytes());
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();
    }

//log  messeage form client or server
    private void log(final String message) {
        long timestamp = System.currentTimeMillis();
        final long time = timestamp % 1000000;

        handler.post(new Runnable() {

            @Override
            public void run() {
                text.setText(text.getText() + "\n @" + time + ": " + message);
            }
        });
    }

//when app is kill close socket 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            shutdown();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }


    private void shutdown() {
        try {
            if (socket != null) {
                socket.close();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }
    }

Answer:

Your code is a total mess.

Commonly you need to make something like this

class ClientClass implements Runnable //For managing clients { Socket socket;

public ClientClass(Socket s)
{
    socket = s;
}

void run()
{
    //Get InputStreams
    //Manage client
}

}

ServerClass

while(true)
{
    new Thread(new ClientClass(server.accept()));//Maybe you want to store it for future comunication
}

Hope this helps.

Question:

I am trying to run a program which tries to communicate with sockets TCP-IP creating server threads.

When I am running the program this is not doing anything.

The code for the client:

package benjagarrido.com.examen2;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

public class Mesa1 {
    public static void main(String[] args) {
        Socket soc;
        ObjectOutputStream objSalida=null;
        ObjectInputStream objEntrada=null;
        int puerto = 12345;

        ArrayList<Comensal> listComensales = solicitarComensales();

        try {
            // Creamos el socket de comunicacion
            soc = new Socket(InetAddress.getLocalHost(), puerto);
            // Creamos los canales de comunicación entrada/salida
            // objEntrada= new ObjectInputStream(soc.getInputStream());
            objSalida = new ObjectOutputStream(soc.getOutputStream());
            objSalida.writeUTF("Mesa 1");
            objSalida.writeObject(listComensales);
            soc.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static ArrayList<Comensal> solicitarComensales() {
        @SuppressWarnings("resource")
        Scanner sc = new Scanner(System.in);
        System.out.println("¿Cuantos comensales serán? (Máximo 4 comensales)");
        int iNumComensales;
        iNumComensales = sc.nextInt();
        ArrayList<Comensal> listComensales = new ArrayList<>();
        for (int i = 0; i < iNumComensales; i++) {
            Comensal comensal = solicitarMenu(i);
            listComensales.add(comensal);
        }
        return listComensales;
    }

    private static Comensal solicitarMenu(int i) {
        Comensal comensal = new Comensal();
        @SuppressWarnings("resource")
        Scanner sc = new Scanner(System.in);
        System.out
                .println("Comensal" + (i + 1) + " Elija el plato principal: ");
        for (Platos plato : Platos.values()) {
            System.out.println(plato.name());
        }
        comensal.setiPlato(sc.nextInt());
        System.out.println("Comensal" + (i + 1)
                + " Elija la bebida principal: ");
        for (Bebidas bebida : Bebidas.values()) {
            System.out.println(bebida.name());
        }
        comensal.setiBebida(sc.nextInt());
        System.out.println("Comensal" + (i + 1)
                + " Elija el postre principal: ");
        for (Postres postre : Postres.values()) {
            System.out.println(postre.name());
        }
        comensal.setiPostre(sc.nextInt());
        return comensal;
    }
}

The code for the Server:

package benjagarrido.com.examen2;

import java.io.*;
import java.net.*;
import java.io.*;
import java.net.*;

@SuppressWarnings("unused")
public class Servidor {

    public static void main(String[] args) {
        ServerSocket servidor;
        Socket serverCliente;
        int puerto = 12345;

        try {
            servidor = new ServerSocket(puerto);
            System.out.println("Servidor arrancado correctamente");
            //while (true) {
                // aceptamos la conexion de cliente
                serverCliente = servidor.accept();
                Thread hilo = new Thread(new ServidorHilo(serverCliente));
                hilo.start();
            //}
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

The code for the Server Thread:

package benjagarrido.com.examen2;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;

public class ServidorHilo implements Runnable {
    ObjectOutputStream objSalida=null;
    ObjectInputStream objEntrada=null;
    Socket soc;
    int puerto = 12345;

    public ServidorHilo(Socket sCliente) {
        this.soc = sCliente;
    }

    @Override
    public void run() {
        ArrayList<Comensal> listComensales = new ArrayList<>();
        try {
            // Creamos el socket de comunicacion
            soc = new Socket(InetAddress.getLocalHost(), puerto);
            // Creamos los canales de comunicación entrada/salida
            objEntrada= new ObjectInputStream(soc.getInputStream());
            //objSalida = new ObjectOutputStream(soc.getOutputStream());

            //String sMesa = objEntrada.readUTF();
            listComensales=(ArrayList<Comensal>) objEntrada.readObject();
            Date date = new Date();
            String sFechaHora = date.getDay()+"/"+date.getMonth()+"/"+date.getYear()+"-"+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
            System.out.println("Se ha recibido el pedido de "+""+" con fecha y hora "+sFechaHora);
            //salida.write();
            objSalida.close();
        } catch (IOException e) {
            // nothing
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

I need your help.


Answer:

The error was on class ServidorHilo when I try to create another socket:

// Creamos el socket de comunicacion
soc = new Socket(InetAddress.getLocalHost(), puerto);

Thanks and sorry.

Question:


Answer:

Use this function to get IP (v4 or v6) inside an activity:

// Get IP address from first non-localhost interface
// @param ipv4  true returns ipv4
//              false returns ipv6
// @return address or empty string
public static String getLocalIpAddress(boolean useIPv4) {
    try {
        List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface intf : interfaces) {
            List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
            for (InetAddress addr : addrs) {
                if (!addr.isLoopbackAddress()) {
                    String sAddr = addr.getHostAddress();
                    //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
                    boolean isIPv4 = sAddr.indexOf(':')<0;
                    if (useIPv4) {
                        if (isIPv4)
                            return sAddr;
                    } else {
                        if (!isIPv4) {
                            int delim = sAddr.indexOf('%'); // drop ip6 zone suffix
                            return delim<0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase();
                        }
                    }
                }
            }
        }
    } catch (Exception ex) { } // for now eat exceptions
    return "";
}

When you need it, just call it this way: getLocalIpAddress(true). You will get the IP as a string for you to use.

Question:

I'm using Java SE 8.

When I connect TLS (TCP/IP) server, I'd like to control (customize) hostname checking logic. For example, accepts only if hostname is matched, or always matched without any checking. For HTTP, I can use HttpsURLConnection's setHostnameVerifier() method.

https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/HttpsURLConnection.html#setHostnameVerifier-javax.net.ssl.HostnameVerifier-

I'd like to do the similar thing on TCP/IP not HTTP. For example MQTT(S) on TCP/IP TLS.

I've read the following sites, but I couldn't get useful information.

https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#SettingHostnameVerifier

Is there any convenient way to do that?

edit 2017/10/24

Some comments indicate that TCP/IP doesn't treat hostname. True. I should rephrase my question.

Updated question is "how to write checking hostname function between the hostname of connect target and the hostname from server certificate?"

Connection target IP address is gotten using getByName(). https://docs.oracle.com/javase/8/docs/api/java/net/InetAddress.html#getByName-java.lang.String-


Answer:

Get the SSLSession, either via a HandshakeCompletedListener or inline from the SSLSocket after you connect it, get the peer certificate from the session, get the subjectDN from the certificate, and check it against the hostname you thought you were connecting to. If any of that fails, close the connection.

Question:

I am trying to connect 2 computer in my home using DatagramSockets (or even Sockets) in java. What exactly should I do? Which IP Address should I use to connect them?


Answer:

If your machine is using DHCP then it's not upto you to decide which ip address you will use. Your machine will be assigned some dynamic ip address. To see that use ifconfig on Linux box and ipconfig on win machine. Once you have their IP address you can use these to connect your machine. Chances are high that your machine has dynamic ip's.