My code can't receive UDP messages from outside my home net. The communication is between Android and Java computer application, with IP inside my LAN (for example 192.168.0.3) the code works, if I put my Java computer application inside my online server (and obviously I changed every IP with external IPs) this doesn't work; Android can send but it can't receive.
Android code :
#Override
protected Integer doInBackground(Void... params) {
DatagramSocket socket = null;
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
socket = new DatagramSocket(25565);
} catch (Exception e) {
Log.i("Ex ", "");
}
while (true) {
try {
socket.receive(packet);
String message = new String(packet.getData(), 0,packet.getLength());
Log.i("message", "" + message);
} catch (IOException e) {
Log.i("IO Ex", "");
}
catch (Exception e){
}
}
}
Java computer application code :
http://pastebin.com/2hVGeP6R
192.168.0.X is an internal NAT address. Any network can use it, but it can't be reached from anywhere outside. You either need to configure your router to pass it through to your PC and hit the router's external IP, or you need a real network address.
Read carefully this example. I suppose you that you are trying to read and write in the same socket while it is open. In case it not working paste some more code in order to help you
Related
I am currently trying to get a little network communication going between a qt server and a java client.
In my example, the client wants to send an image to the Server. My problem is now, that the server never sees the data, so bytesAvailable() returns 0.
I already tried QDataStream, QTextStream and readAll(), still no data.
Server:
QTcpServer* tcpServer;
QTcpSocket* client;
tcpServer = new QTcpServer();
if(!tcpServer->listen(QHostAddress::Any, 7005)){
tcpServer->close();
return;
}
...
tcpServer->waitforNewConnection();
client = tcpServer->nextPendingConnection();
client->waitForConencted();
while(client->state()==connected){
// Syntax here might be iffy, did it from my phone
if(client->bytesAvailable()>0){
//do stuff here, but the program doesnt get here, since bytesAvailable returns 0;
}
}
CLient:
public SendPackage() {
try {
socket = new Socket(ServerIP, Port);
socket.setSoTimeout(60000);
output = new BufferedOutputStream(socket.getOutputStream());
outwriter = new OutputStreamWriter(output);
} catch (ConnectException e) {
System.out.println("Server error, no connection established.");
} catch (Exception e) {
e.printStackTrace();
}
}
public void Send(BufferedImage img) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, GUI.imageType, baos);
baos.flush();
byte[] imgbyte = baos.toByteArray();
System.out.println(imgbyte.length);
System.out.println("sending");
outwriter.write(imgbyte.length);
outwriter.flush();
// here i'd send the image, if i had a connection ...
output.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
The connection and everything builds up fine, the code even tells me when the socket was disconnected when trying to send, so I guess connection isn't a problem.
I just started using Qt, so if you guys have any idea to why this wouldn't work, I'd be pleased to try it.
client->waitForConencted();
// At this point the client is connected, but it is likely that no data were received yet
client->waitForReadyRead(-1); // <- Add this
// Now there should be at least 1 byte available, unless waitForConencted or waitForReadyRead failed (you should check that)
if(client->bytesAvailable() > 0) {
// ...
}
Note that you can not expect all the data to arrive at once. The TCP stream can get fragmented in any way and the data will be received in randomly sized pieces. You must repeat waiting and reading until you receive everything. This also means that you must somehow know when you did receive everything. So you need to know how much data is coming, or somehow recognize the end of it. You can for example disconnect right after the data transfer, or send the data length first. Depends on your application.
Also have a look at QIDevice::readyRead signal which would allow you to handle reading asynchronously.
What I'm trying to do is simply send an mp3 file over http/tcp with my own http headers. On the client side I have a webpage with the following line:
<audio src="http://192.168.0.21:14441" controls autoplay loop>
The Java server side has a ServerSocket and accepts basically any connection. It will then send a hardcoded http header followed by the binary data of the mp3-file.
My server class:
public class Server {
private int port = 14441;
private String localIPAddress;
private BufferedReader in;
private BufferedOutputStream out;
private ServerSocket serverSocket;
private Socket clientSocket;
public Server() {
}
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
startAcceptingConnections();
}
}).start();
}
private void startAcceptingConnections() {
tryToOpenPort();//try to open external port with upnp
clientSocket = null;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port:" + port);
System.exit(1);
}
System.out.println("Waiting for connection.....");
try {
clientSocket = serverSocket.accept();
System.out.println("Connection successful");
System.out.println("Waiting for input.....");
out = new BufferedOutputStream(clientSocket.getOutputStream());
in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
boolean isSendingMp3 = false;
while ((inputLine = in.readLine()) != null) {
//just output any line the client sends me
System.out.println("Received: " + inputLine);
//Whenever the client sends an empty line this means
//it's ready to receive
if (inputLine.equals("") && !isSendingMp3) {
isSendingMp3 = true;
//Making sure to keep listening to the InputStream
//so I send from a different thread
new Thread(new Runnable() {
#Override
public void run() {
sendMp3File();
}
}).start();
}
}//end of listening to client loop
out.close();
in.close();
clientSocket.close();
serverSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendMp3File() {
try {
//I've tried all sorts of headers
String response = "HTTP/1.x 200 OK\r\n"
+ "Content-Type: audio/mpeg\r\n"
+ "Content-Size: 2911084\r\n"
+ "Range: bytes 0-2911083/2911084\r\n"
+ "X-Content-Duration: 300.1\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Duration: 300.1\r\n"
+ "\r\n";
out.write(response.getBytes(Charset.forName("UTF-8")));
byte[] bytesRaw = new byte[1024 * 10];
InputStream is = new FileInputStream("C:/sample.mp3");
int byteCount = 0;
while ((byteCount = is.read(bytesRaw)) != -1) {
System.out.println("sending bytes:" + byteCount);
out.write(bytesRaw, 0, byteCount);
}
out.flush();
is.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
//Use Cling to open the port via upnp
private void tryToOpenPort() {
try {
localIPAddress = Inet4Address.getLocalHost().getHostAddress();
PortMapping desiredMapping
= new PortMapping(
port,
localIPAddress,
PortMapping.Protocol.TCP,
"Test server"
);
UpnpService upnpService = new UpnpServiceImpl(new PortMappingListener(desiredMapping));
upnpService.getControlPoint().search();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
This always works on a PC browser (Firefox, Chrome, IE) and gives no problems machine to machine (no firewall interference).
However, as soon as I run the webpage from a mobile device (both iOS and Android) the connection is suddenly closed after sending what seems to be a random amount of data. This is somewhere between 0 and 2 seconds after the connection has been established.
The Java application throws the exception:
java.net.SocketException: Connection reset by peer: socket write error
When I profile with Wireshark it shows me everything goes well and then suddenly the client starts sending a bunch of RST messages. I've tried multiple types of headers, even copied a number of headers from existing webservers, but nothing seems to work.
Even simple headers like
"HTTP/1.1 200 OK\r\n"
+ "Content-Type: audio/mpeg \r\n"
+ "\r\n";
Work when I open them from a computer browser, but reset the connection on mobile. Am I forgetting something important?
UPDATE
On mobile browsers it closes the connection after a bit of data has been send. It connects and disconnects again at what seems like random intervals, sometimes with a range in the header and sometimes not. Even when it has received the entire file it will continue to open connections.
I'm guessing some sort of high protocol 'protection' when sending big requests, maybe specifically for when on unstable mobile networks.
Is there some way to bypass this? Whatever it is, it seems a bit unduly.
What happens is that the html5 audio element asks for the first 2 bytes with a range header. When I then (according to rfc2616 validly) ignore this range and send the whole file, the audio player starts behaving as if it's an audio stream (or at-least becomes very confused). This still only happens on mobile browsers somehow.
The solution might be to start accepting range request so that the player doesn't get "confused". I'll post the results as soon as I get the time to try this.
I think the problem is in the code you have not shown. My guess is that you accept the connection and then simple send the response without reading the request. But if the connections gets closed with the request not read this will cause a connection reset. How this reset affects the client depends on the timing, i.e. it might be that the client processed the response before it got the reset or that it found the reset before it had time to process the response.
To fix it you need to read the HTTP request before you sent the response.
I've written a basic udp client server where one android sends message to the server and server relays it to the rest of the clients.
The issue is, the incoming udp messages get to the server and server relays them back but they never reach the rest of the devices.
Whats really amazing is that if I use the server as echo server (i.e relaying only to sender) then everything works. All client and server sockets use same port 2706
Server code
while (true) {
DatagramPacket packetToReceive = new DatagramPacket(new byte[2048], 2048);
try {
listenerSocket.receive(packetToReceive);
InetAddress senderAddress = packetToReceive.getAddress();
relayedBytes += packetToReceive.getLength();
if (!connectedClients.contains(senderAddress)) {
connectedClients.add(senderAddress);
}
for (InetAddress addr : connectedClients) {
// commenting this line will make it an echo server
if (!addr.equals(senderAddress))
{
//The following actually prints the ips of the android
//devices so it knows where to send
System.out.println(senderAddress.getHostAddress().toString() +
" to " + addr.getHostAddress().toString());
byte[] data = packetToReceive.getData();
packetToReceive.setData(data, 0, packetToReceive.getLength());
packetToReceive.setAddress(addr);
listenerSocket.send(packetToReceive);
}
}
} catch (IOException) {
e.printStackTrace();
}
}
android sender logic:
mainSocket=new DatagramSocket(homePort);
//targetAddressString is the public IP of server
target = InetAddress.getByName(targetAddressString);
while (true) {
byte[] data = getdata();
if (data == null)
continue;
DatagramPacket packet = new DatagramPacket(data, data.length, target, targetPort);
mainSocket.send(packet);
}
meanwhile on other thread the reciever just waits with the same udp socket:
while (true) {
Log.d("Player", "Waiting for data");
DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
try {
mainSocket.receive(packet);
Log.d("Player", "packet received");
//do something with the packet
} catch (IOException e) {
e.printStackTrace();
}
}
It never moves further than waiting for data since it'll block until it receives a packet
Moreover I can also see it in the wifi and Mobile data icons that no data is ever received but data sending is always on and is seen received on the server
**EDIT:- Echo server **
while (true) {
DatagramPacket receivedPacket = new DatagramPacket(new byte[2048], 2048);
try {
listenerSocket.receive(receivedPacket);
InetAddress senderAddress = receivedPacket.getAddress();
if (!connectedClients.contains(senderAddress)) {
connectedClients.add(senderAddress);
}
for (InetAddress addr : connectedClients) {
byte[] data = receivedPacket.getData();
DatagramPacket sendPacket= new DatagramPacket(data, 0, receivedPacket.getLength(), addr, receivedPacket.getPort());
listenerSocket.send(sendPacket);
}
} catch (IOException e) {
// ...
}
}
Basically it should relay the message to every single client who've ever sent any data but somehow it only sends its to its original sender the rest of clients miss it. the code is trolling with me
This is the NAT traversal problem as you have figured out.
Here's a few hints:
The server can be hardcoded to listen on port 2706. But it shouldn't make any assumptions about what source port of received packets are. From your code, it doesn't look like you ever attempt to call setPort. So even if the NAT wasn't mapping your port number differently, I'm not sure how your original code was even getting the any destination port set. But I think you figured this out based on your own answer and your updated code.
Don't hardcode a client port on the client's socket. Choose port "0" (or don't set one) on your socket to let the OS choose the first available port for you. If you have multiple clients behind the same NAT, this behavior will allow for quicker client restarts, multiple devices behind the same NAT, and other nice things.
Holly Molly! I finally figured it out , it was my own fault I wasn't considering my cellphone provider's Nat and was assuming 2706 port in public IP as well.
Turns out actually I was under my cellphone network's NAT and my port 2706 was converted to some hideous port number by the time it reached the server. So I had to consider the port no of the actual packet received rather than the one set on the phone.
In a nutshell it was like this
cellphone (port 2706)-> NAT (port 40234) -> Server (port 40234)
and so I was actually trying to send back data to 2706 instead of 40234 -_-'
Once I start to send back the packets at 40234 (or whatever came with the packet) instead of 2706 , it gracefully followed the path back to my android cellphone and everything was fine.
I'm trying to monitor a port to get the outgoing/incoming packets (or sockets) from my PC using Java, more like what Wireshark does.
I'm using this code:
int portNumber = 5816;
try {
System.out.println("New ServerSocket...");
ServerSocket serverSocket = new ServerSocket(portNumber);
serverSocket.setSoTimeout(5000);
System.out.println("Accepting...");
serverSocket.accept();
System.out.println("Done Accepting.");
} catch (IOException e) {
System.out.println(e.getMessage());
}
Now I can see the packets using Wireshark, and I can see the connection is established using Process Hacker 2, but I always get this output:
New ServerSocket... Accepting... Accept timed out
EDIT:
The question,
I got an application installed, that exchange packets with an external server (nor the client or the server are mine), i just want to intercept these packets and log them.
and they are using 5816 port.
Wireshark is using pcap library to intercept network communication. You can use pcap wrapper for java to achieve similar functionality.
Note:
You are not closing sockets. However, this code is still incorrect approach to achieve your goal.
int portNumber = 5816;
System.out.println("New ServerSocket...");
try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
serverSocket.setSoTimeout(5000);
System.out.println("Accepting...");
try(Socket socket = serverSocket.accept()) {
System.out.println("Done Accepting.");
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
I a having some serious problems, communicating between my android app and my java program with datagram sockets. My android app should be the client and have the following code for socket etc.:
try {
InetAddress ipAdress = InetAddress.getLocalHost();
int portNo = 4324;
DatagramSocket clientSocket = new DatagramSocket();
String sendString = "&%#!check_connection!#%&";
DatagramPacket packet = new DatagramPacket(sendString.getBytes(), sendString.length(), ipAdress, portNo);
clientSocket.send(packet);
// Receive response
} catch (Exception e) {
e.printStackTrace();
}
My java program should receive it like this:
while(waitingForClient) {
try {
System.out.println("test 1");
DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length);
System.out.println("test 2");
serverSocket.receive(packet);
System.out.println("test 3");
String getData = new String(packet.getData());
System.out.println(getData);
mainFrame.logArea.append(getData + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
All of the code in the android app is executed, but in my java program's code, it only reaches "test 2" (never prints out test 3)...
Both my android devices and my pc is connected to the same router..
Any help will be greatly appreciated :)
InetAddress ipAdress = InetAddress.getLocalHost();
your android app is trying to connect to itself, pass in the ip address of the computer running the java program