We have code using UDP socket for communication. In this code, application is sending a packet to a given server (identified by given hostname and port). This code is an extracted out from a large code base.
class Test {
private static int UDP_PORT_NUMBER=15000;
public static void main(String args[]) {
String host = “192.168.2.10”;
byte[] bytes = {(byte)0xd1, 0x35, (byte)0x39, (byte)0xea, (byte)0xa2, (byte)0xd8};
DatagramSocket datagramSocket = new DatagramSocket();
final InetAddress inetAddress = InetAddress.getByName(host);
final DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length,
inetAddress, UDP_PORT_NUMBER);
datagramSocket.send(sendPacket);
}
}
However, I am getting following exception in our case while calling send on datagram socket:
java.io.IOException: Network is unreachable
at java.net.PlainDatagramSocketImpl.send(Native Method) ~[?:1.8.0_91]
at java.net.DatagramSocket.send(DatagramSocket.java:693) ~[?:1.8.0_91]
What is the meaning of network unreachable in UDP and how does it get detected for UDP which is connectionless? What are cases where I can get network unreachable IOException in UDP socket?
The network unreachable message is an ICMP message. When a host tries to reach another host on a different network, it sends the layer-3 packet to its configured gateway. If the gateway ( or any router in the path) doesn't know how to reach the other network, it will generate an ICMP message and send it back to the host.
Related
I'm trying to make a chat program where the client and the server can chat with each other on different networks (not localhost) I'm currently faced with a problem that i don't know how to solve.
For some reason, the client and the server can't connect to each other, when i write a message to the server with the client, nothing pops up on the server. The tests were run on two different computers, on different networks (Mobile data and Ethernet)
I've used the public ip from my ethernet in the code, and portforwarded it with the matching port number in the code. The server is running on the portforwarded network.
This is my code:
CLIENT:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatClient {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
DatagramSocket client = new DatagramSocket(7000);
byte[] receivedData = new byte[1024];
byte[] sentData;
InetAddress address = InetAddress.getByName(" PUBLIC IP IS HERE, won't show it for obvious reasons ");
while (true) {
String message = scanner.nextLine();
sentData = message.getBytes();
DatagramPacket dp1 = new DatagramPacket(sentData, sentData.length, address, 7000);
client.send(dp1);
DatagramPacket dp4 = new DatagramPacket(receivedData, receivedData.length);
client.receive(dp4);
String receivedMessage = new String(dp4.getData());
System.out.println(receivedMessage);
}
}
}
SERVER:
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatServer {
public static void main(String[] args) throws IOException {
DatagramSocket server = new DatagramSocket();
Scanner scanner = new Scanner(System.in);
byte[] receivedData = new byte[1024];
byte[] sentData;
while (true) {
DatagramPacket dp2 = new DatagramPacket(receivedData, receivedData.length);
server.receive(dp2);
String storedData = new String(dp2.getData());
System.out.println(storedData);
InetAddress getIP = dp2.getAddress();
int port = dp2.getPort();
String sentMessage = scanner.nextLine();
sentData = sentMessage.getBytes();
DatagramPacket dp3 = new DatagramPacket(sentData, sentData.length, getIP, port);
server.send(dp3);
}
}
}
The code worked when altered to localhost only.
Does anyone know what i'm doing wrong? Any replies are greatly appreciated.
Assuming the client connects to the server, the server needs to specify the port to listen and the client needs to specify IP and port of the server.
Client:
InetAddress address = InetAddress.getByName(" PUBLIC IP IS HERE");
DatagramSocket client = new DatagramSocket();
//...
DatagramPacket dp1 = new DatagramPacket(sentData, sentData.length, address, 7000);//the port should be the publicly exposed port
client.send(dp1);
This connects to the server with specified IP and port.
Server:
DatagramSocket server = new DatagramSocket(7000);//port to forward
This means that the server listens on port 7000 so it is available under that port.
Aside from that, make sure the port forwarding works correctly. If you use UDP, you also need to configure it for TCP.
Also note that UDP does neither confirm nor validate packages. If you want to have those features, you will need to either use TCP or implement those features by yourself.
Here is use case I need to implement in Java:
Server is listening for push messages from some clients
If client has some data to push into server, it opens TCP connection and sends all messages
When client sends last message (special message saying that this is the last one) server should close connection by starting TCP closing handshake
I have problem with last step because I don't know how to close connection from server site. My current code is bellow. How to initiate connection closing TCP handshake form server site? Thank you for any help.
public class Server{
public static void main(String[] args) throws Exception {
while (true) {
int port = AppConfig.getInstance().getPort();
try (ServerSocket socket = new ServerSocket(port)) {
Socket server = socket.accept();
InetAddress ipAddress = server.getInetAddress();
MessageHandler handler = new MessageHandler(ipAddress);
InputStream in = server.getInputStream();
// reads all bytes from input stream and process them by given handler
processStream(in, handler);
in.close();
server.close();
} catch (Exception e) {
LoggingUtils.logException(e);
}
}
}
private static void processStream(InputStream in, MessageHandler handler) throws Exception {
// implementation is omitted
}
}
You've done it. in.close() closes the input stream, the socket output stream, and the socket.
What you should really close is whatever output stream was attached to the socket, to ensure it gets flushed, and you should probably do that in the processStream() method, with a saver server .close() in a finally block in the calling method.
NB Your socket names are really the wrong way round. It is customary to use ServerSocket serverSocket, and Socket socket = serverSocket.accept().
I may be not totally sure about this one, but I would believe that socket.close() will send all the commands (FIN/FIN-ACK)
I have the code below which creates a socket UDP-style. I run and compile the code and it works just fine. If I then use "netcat -u " I am able to send messages from the client to the server but not the other way around. So what I want and what I have been trying to do is to read from stdin and printing it(all this running in a second thread). Making it a two-way communication. Anyone know what I need to fix? Thanks in advance.
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class NetcatUDP {
public static void main(String[] args) throws IOException {
int port = Integer.parseInt(args[0]);
byte[] buffer = new byte[65536];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
DatagramSocket socket = new DatagramSocket(port);
new Thread() {
#Override
public void run() {
// Read from stdin and send somehow?
}
}.start();
while (true) {
socket.receive(packet);
System.out.println(new String(packet.getData()).trim());
}
}
}
UDP is a connection-less protocol, which means you can send a message to anyone and receive a message from anyone with a single socket.
For the simple example you're using, you can actually use the same program for both endpoints. Besides reading in the local port number from the command line, read in the remote IP address and port as well. Then in your thread, you read from stdin using Console.readLine(), construct a DatagramPacket with the line read from the console, remote IP, and remote port, and send it with the existing socket you have.
I have written a simple client and simple udp server that needs to read string messages from particular port. here is the UDP-socket:
public class UDPServer {
// boolean variable defines if the infinite loop
// in startServer() runs or not
private boolean isSwitched = false;
private DatagramSocket socket = null;
public UDPServer(int port) throws SocketException {
socket = new DatagramSocket(port);
Logger.getLogger(Main.class.getName()).log(Level.INFO, "Server started! Bound to port: " + port);
}
//this method start the server and switches on the infinite loop to
// listen to the incoming UDP-packets
public void startServer() throws IOException {
this.isSwitched = true;
Logger.getLogger(Main.class.getName()).log(Level.INFO, "Server starts listening!");
while (isSwitched) {
byte[] size = new byte[30];
DatagramPacket dp = new DatagramPacket(size, size.length);
try {
System.out.println("Debug: receive loop started!");
socket.receive(dp);
System.out.println("Debug: Packet received after socket.receive!");
Thread requestDispatch = new Thread(new Request(dp.getData()));
requestDispatch.start();
} catch (SocketException ex) {
Logger.getLogger(Main.class.getName()).log(Level.INFO, "Stops listening on specified port!");
}
}
}
// this method stops the server from running
public void stopServer() {
this.isSwitched = false;
socket.close();
Logger.getLogger(Main.class.getName()).log(Level.INFO, "Server is shut down after last threads complete!");
}
}
I deploy it on the remote server and switch on the program. The server prints out that it started listening so it reaches the socket.receive() stage. Then I send a UDP-message from a remote client. But nothing happens. The udp-server does not move any further - it justs holds and seems to receive no messages.
I tried to debug the ports with the tcpdump and it shows that messages come to the required port. but java program does not seem to receive them.
When I issue this command on the remote server:
tcpdump udp port 50000
and send a few packets thats what it writes:
12:53:40.823418 IP x.mobile.metro.com.42292 > y.mobile.metro.com.50000: UDP, length 28
12:53:43.362515 IP x.mobile.metro.com.48162 > y.mobile.metro.com.50000: UDP, length 28
I tested your server code locally with netcat and it works just fine, so the problem has to be somewhere else. Are you sure you're actually sending UDP packets? Did you run tcpdump on the remote server? When not, maybe your packets get filtered.
Ok, question resolved. The problem was:
FIREWALL on Red Hat linux, which I successfully switched off for the required port.
I have searched everywhere to find an answer for this question:
I have a TCP client on my android application that sends an message to the server which is written in Visual Basic .NET Framework 4.
Now i want to send an message from my server to the phone over 3g, it works on wifi and 3g..
private class startserver extends Thread
{
public void server() throws Exception
{
String clientSentence;
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(8765);
while(true)
{
Socket connectionSocket = welcomeSocket.accept();
BufferedReader inFromClient =
new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
clientSentence = inFromClient.readLine();
System.out.println(clientSentence.substring(1));
msgshower = clientSentence.substring(1);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "Received: " + msgshower , Toast.LENGTH_LONG).show();
}
});
capitalizedSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(capitalizedSentence);
}
}
#Override
public void run() {
try {
server();
} catch (Exception e) {
e.printStackTrace();
}
}
I start it in the OnCreate method
Now i send a message with (VB.NET)
Private Sub sends(ByVal message As String)
Dim tcp As New TcpClient
tcp.Connect(connectedIP, 8765)
Dim bw As New IO.BinaryWriter(tcp.GetStream)
bw.Write(message)
bw.Close()
tcp.Close()
End Sub
On wifi it will arrive, on 3g it wont... any idea's how to do this?
How do other applications archive this?
I think you're having problem with the ip address asigned by your mobile phone operator. The fact that works on wifi, but not on 3G, I think that is because your mobile(when connected through 3G) doesn't have a public IP address.
When you use SocketServer in your mobile, you're opening a port a waiting for others to connect to it. If your IP address is not reachable from internet, it won't happen (it's like having a computer behind a firewall.)
Could you try to implement the server in the VB machine, assuming that it has a public reachable address? This way, the phone wouldn't act as a server, it wouldn't be necessary to have a reachable address, as long as the VB machine has one. Then, you should use Socket class to bind to the server ip and port.
Totally confused by your code list above..
If you want to host a server in VB.NET, you should not use TcpClient class but TcpListener and if you need a better performance, use Socket class directly.
At the Android client side, you should new Socket(server,servPort), when you want to send message, write the outputStream, and read the inputStream to receive message.