Home > Blockchain >  Java TCP Socket Programming: Client and Server communicate well on the same computer, but fail to se
Java TCP Socket Programming: Client and Server communicate well on the same computer, but fail to se

Time:11-30

I am trying to set up a program where the server can communicate with multiple clients. The program is written in Java. I got it all working on the same machine so I decided to try LAN. I converted the program to JAR files and I tried connecting my laptop to my PC (both are on the same network). The connection is successful but unfortunately only 1 message arrives to the server. As you can see in the code below, I send multiple messages (Meaning that i write multiple times) via DataOutputStream. One defines the datatype (in the following example 0 means that it's a String) and the other sends the actual message data. I also print the size of the packets in bytes and it always matches the size of the DataOutputStream instance.

DataOutputStream dOut = new DataOutputStream(clientSocket.getOutputStream());
String str = "Hello";
//Type
System.out.println("Type output size: 1");
dOut.writeByte(0);
//Message
System.out.println("Message output size: "   (str.getBytes(StandardCharsets.UTF_8).length   2));
dOut.writeUTF(str);

System.out.println("Length of all: "   (dOut.size()));
dOut.flush();

So now when the data from the client is sent we need to handle it on the server, which the code below does. It retrieves the InputStream from the Socket called client and inserts it into the DataInputStream. This is were it gets weird on LAN as the stream only contains the first message.

InputStream stream = client.getInputStream(); 
DataInputStream dIn = new DataInputStream(stream); 

while(dIn.available() > 0) {
   byte type = dIn.readByte();
    
  switch(type) {
                    
    case 0:
      System.out.println(dIn.readUTF());
      break;
    case 1:
      System.out.println(dIn.readInt());
      break;
    case 2:
      System.out.println(dIn.readByte());
      break;

    default:
      throw new IllegalStateException("Unexpected value: "   type);       
  }
}

If you run the Client in the IDE on lets say a laptop connected to the same network and then you run the Server on a PC connected to the same network it will work. However, not if the programs are in JARS.

The actual stacktrace is the following:

java.net.SocketException: Connection reset at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323) at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350) at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966) at java.base/java.net.Socket$SocketInputStream.read(Socket.java:961) at java.base/java.io.DataInputStream.readInt(DataInputStream.java:393)

The stacktrace does not tell me anything, but it points at case 0: in the switch case. It can't read the String as the DataInputStream does not contain any data (I guess?).

I would also like to state that the Server is multithreaded! I have one thread that adds the sockets when they are accepted through ServerSocket.accept() and I use the second (main thread) to read the data sent from clients.

I have selected the code above as I believe that the issue lies within it, however I am new to Socket Programming and I know that some of you would like to see other parts of the code. I will add more relevant code when I am asked.

I do not know why it acts like this, does anyone know why?

What have i tried?

  • I have tried waiting for packets - but that has only resulted in the Server looping forever. With waiting for packets I mean not going forward until the DataInputStream contains enough bytes.
  • I have disabled Nagels Algorithm through setTCPNoDelay(false).
  • Tried to send different datatypes, but that also failed
  • I tried changing the first packet to a String which resulted in the String showing up in the DataInputStream.
  • I have tried portforwarding the port used and I have tried disabling the firewall on both computers.

Update 1

I have been taking advice from the comments which has led a to a few discoveries:

  • Closing the DataOutputStream successfully sends all packets to the client.
  • It is also possible to build your own buffer and decode it in the server. However, it is still not possible to send any more messages after this.
  • It worked as a JAR because IntelliJ was being nice (Eclipse threw the same error when running in IDE)

Update 2: I think this post is relevant. It states that SocketException is sent when a client closes it's socket "ungracefully". And because my Client closes (as it is not in a loop) and I don't close the socket properly - it will close "ungracefully" and the data will be lost. Hence the error.

CodePudding user response:

The issue is now solved, and the solution is quite logical. My client does not operate in a loop, rather it sends the data and closes the program. That sounds fine, but I forgot to properly close the socket of the client.

The reason why the second 'packet' never arrived was due to me doing this tiny mistake. The packet was on it's way through the local network but the client socket improperly closed it's socket before the packet arrived to the server, which is why I got a SocketException error. See this.

I solved the issue by putting socket.close() ,where socket is the client's socket, after I had sent all the messages I wanted to send.

  • Related