unable to receive all datagrampackets - java

Goodevening everyone.
I am trying to create an application using Eclipse(Kepler) where I send an array of DatagramPackets. My server side application is receiving all packets sent by the client. But when the server tries to respond back by sending the response packets back to client, my client is unable to receive all the packets.
I would be really obliged if someone helped me out.
here is my client side application code:
public static void main(String [] args) throws IOException
{
timing t=new timing(); // timing is the name of my class
InetAddress inet;
DatagramSocket ds;
int k=1024*60;
DatagramPacket[] p=new DatagramPacket[64];
DatagramPacket []recd=new DatagramPacket[64];
byte[] buf=new byte[1024*60];
if(args[0]==null)
{
args[0]="localhost";
}
inet=InetAddress.getByName(args[0]);
ds=new DatagramSocket(6443);
for(int i=0;i>64;i++)
{
p[i]=new DatagramPacket(sent.getBytes(),sent.length(),inet,7443);
recd[i]=new DatagramPacket(buf,buf.length);
}
ds.setSoTimeout(120000);
int buffer=ds.getReceiveBufferSize();
int j=ds.getSendBufferSize();
while(h<64)
{
p[h]=new DatagramPacket(sent.getBytes(),sent.length(),inet,7443);
ds.send(p[h]);
System.out.println("Client has sent packet:"+h);
h++;
}
System.out.println("Receiving.");
h=0;
while(h<64) // UNABLE TO RECEIVE ALL SERVER SIDE PACKETS . PROBLEM CODE
{
recd[h]=new DatagramPacket(buf,buf.length);
ds.receive(recd[h]);
System.out.println("Client has recd packet:"+h);
h++;
}
SERVER SIDE APPLICATION:
try{
byte[] buf=new byte[60*1024];
InetAddress add=InetAddress.getByName("localhost");
for(int i=0;i<64;i++)
dp[i]=new DatagramPacket(buf,buf.length,add,6443);
ds.setSoTimeout(120000);
System.out.println("SERVER READY AND LISTENING PORT 6443");
int h=0;
while(h<64)
{
dp[h]=new DatagramPacket(buf,buf.length,add,6443);
ds.receive(dp[h]);
System.out.println("Packet "+h+"recd.");
h++;
}
String x1=new String(dp[63].getData());
System.out.println("Server recd:"+x1);// correct. no problem here
InetAddress add2=dp[63].getAddress();
int port=dp[63].getPort();// this is fine. same data sent in all packets
h=0;
while(h<64)
{
dp[h]=new DatagramPacket(buf,buf.length,add2,port);
ds.send(dp[h]);
System.out.println("Server has sent packet:"+h);
h++;
}
kindly help me as when i send a single datagrampacket its being recd. but this array of packets isnt.

I do not know much about your code, but if I really want this 'for' loop:
for (int i=0;i>64;i++)
to be executed at least once I would change it to i<64.

You don't show what sent is in the client, or therefore how long it is, but I suspect it is some reasonable size that can actually be sent.
By contrast, in the server you are attempting to send 60k datagrams, which won't work unless the sender's socket send buffer and the receiver's socket receive buffer are at least that size.

Related

TCP Send Buffer not doing anything

So i am experimenting with socket buffer sizes and have created 2 test cases
Case 1[server sends data to client]
First we have a server which sends 100 bytes of data to a client
public static void main(String[] args)throws Exception
{
try(ServerSocket server=new ServerSocket())
{
server.bind(new InetSocketAddress(InetAddress.getLocalHost(),2500));
byte[] data=new byte[100];
for(int i=0;i<data.length;i++){data[i]=(byte)i;}
while(true)
{
try(Socket client=server.accept())
{
try(OutputStream output=client.getOutputStream())
{
output.write(data);
}
}
}
}
}
And next we have an Client which simply reads the 100 bytes received and prints it but i have set the Receive Buffer size to 25 bytes. Therefore i expect the server to send 4 packets each of size 25 bytes.
public static void main(String[] args)throws Exception
{
try(Socket client=new Socket())
{
//receive window as 25 bytes
client.setReceiveBufferSize(25);
client.setSoLinger(true,0);
client.bind(new InetSocketAddress("192.168.1.2",5000));
client.connect(new InetSocketAddress(InetAddress.getLocalHost(),2500),2000);
try(InputStream input=client.getInputStream())
{
int length;
byte[] data=new byte[100];
while((length=input.read(data))>0)
{
System.out.println(Arrays.toString(Arrays.copyOfRange(data,0,length)));
System.out.println("============");
}
}
}
}
And sure enough upon examining the packets sent from the server end using wire shark i see 4 packets[ignore malformed packets as i get no errors when receiving data on the client side and sometimes it shows malformed and sometimes no error] each with payload of size 25 bytes.
Further confirmation that each packet is 25 bytes is examining the ACK window packets sent from the client side
So case 1 is complete upon setting Receive Buffer Size from the client side server sends packets of that much size
Case 2[Client sends data to server]
The roles are reversed and this time we set the ServerSocket Receive Buffer size before binding as follows
public static void main(String[] args)throws Exception
{
try(ServerSocket server=new ServerSocket())
{
//server receive window
server.setReceiveBufferSize(10);
server.bind(new InetSocketAddress(InetAddress.getLocalHost(),2500));
int length;
byte[] data=new byte[100];
while(true)
{
try(Socket client=server.accept())
{
try(InputStream input=client.getInputStream())
{
while((length=input.read(data))>0)
{
System.out.println(Arrays.toString(Arrays.copyOfRange(data,0,length)));
System.out.println("============");
}
}
}
}
}
}
And the client sends data with no additional settings as follows
public static void main(String[] args)throws Exception
{
try(Socket client=new Socket())
{
client.setReuseAddress(true);
client.connect(new InetSocketAddress(InetAddress.getLocalHost(),2500),2000);
byte[] data=new byte[100];
for(int i=0;i<data.length;i++){data[i]=(byte)i;}
try(OutputStream output=client.getOutputStream()){output.write(data);}
}
}
Since the server has said it is willing to receive packets of only 10 bytes i expect the client to send 10 packets each of size 10 bytes. And sure enough upon examining the packets received on the server end using wire shark i get the expected output
So this completes understanding of the Receive Buffer on both the client and the server side. If one side broadcasts its receive buffer size the other side sends only that much data with each packet transmission which makes total sense.
Now comes the harder to understand part the Send Buffers. My understanding of an Send Buffer is that
Holds bytes sent by the socket and gets emptied out only after
receiving an ACK from the recipient . And if it gets full it blocks the
socket from sending any more data until an ACK is received.
Thus if the sender has an send_buffer=10 bytes and if the receiver has an receive_buffer=30 bytes. The sender should still send only 10 Bytes as it is capable of holding on to only that much data which must then be Acknowledged by the receiver and then it can send the next 10 bytes and so on. But despite all my combinations of setting send buffer on the server and client side as follows
1)Client sends data to server
server side=ServerSocket.setReceiveBufferSize(30);
client side=client.setSendBufferSize(10);
2)Server sends data to client
server side=serverSocket.accept().setSendBufferSize(10);
client side=client.setReceiveBufferSize(30);
The packets received on the recipient side using wire shark is always the same. i.e sender always sends packets of size 30 bytes. i.e sender is always dominated by the receiver's settings
a) Where have i gone wrong in my understanding ?
b) An very simply test case as presented above where Send Buffer actually makes an difference in both client & server side would be appreciated
I filed an incident report a few days ago and it has been confirmed as a bug

how to tell server has sent data successfully in socket programming?

i am working on a problem on socket programming in JAVA.
There is a server and a client.
1) server is connected to client
2) server sends N no of Strings which are stored in an array on server side(obviously ;)).
3)Client doesn't know the size of array
4)Server receives Strings from server one by one.
5)When Client reads all the Strings it sends one msg to server
6)Server receives the msg.
7)This process goes on(step 2-step 6) for multiple times.
The problem i am facing is, Client does not know when server sends the last String and it is waiting for its turn.
I have solved this problem using:
a)Multi threading.
b)Telling size of array to client at the beginning of the first msg
I want to know is there any in-built function which indicates if the server has stoped sending data?
here is the code for 1 iteration(step 1-step 6)
Server code:
public class server {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static ServerSocket server;
static Socket socket;
public static void main(String[] args)
{
a=new String[]{"String1","String2","String3"};
try {
server=new ServerSocket(8080);
socket=server.accept();
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
///sending array values
//String temp=null;
for(int i=0;i<a.length;i++)
{
dos.writeUTF(a[i]);
}
String msg_from_client=dis.readUTF();
System.out.println(msg_from_client);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client code:
public class client {
static String[] a;
static DataOutputStream dos;
static DataInputStream dis;
static Socket socket;
static Scanner sc;
public static void main(String[] args)
{
try {
socket=new Socket("127.0.0.1",8080);
System.out.println("connected");
dos=new DataOutputStream(socket.getOutputStream());
dis=new DataInputStream(socket.getInputStream());
sc=new Scanner(System.in);
//reading from server i dont know what is the size of array at server side
String temp=null;
while((temp=dis.readUTF())!=null)
{
System.out.println(temp);
}
System.out.println("out of the loop");
////now client sends the msg;
String msg=sc.nextLine();
dos.writeUTF(msg);
System.out.println("sent");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
output at client side:
connected String1 String2 String3
This is the time to learn more about protocols. You can setup your own protocol between your server and client i.e., the first message from the server would always contain the # of strings to follow. The client would keep a note of it and then it will request for # of strings that server told in first method.
EDIT: Little more enhanced protocol
If you chose the path to open a new connection for each message as suggested by other user, then you would have to add a little more to your protocol. You would need
Client Information, so that server knows what communication it has done with this client previously
Message information, so that server knows if this client is asking for new message or it sent some message earlier to this client and he is asking for next part of this message.
1 can be achieved by allotting a client ID. If you know how many clients you are dealing with, you can have it a hardcoded value. Otherwise generate at runtime
2 Message information could be "null" indicating that the client is asking for "any new message" for him. Keep in mind that having a "null" message_id doesn't mean that you skip this field. You have to make sure you add "message_id" "key" in the request but keep that field empty. The reply to this request would be expected # of strings that server would be returning plus a newly generated message_id. The client will use this message_id in all subsequent calls and will tell the server, I am asking for string x of y from message_id z
You need absolutely to exchange one information between server and client to indicate end of transmission:
by sending number of message before: as you suggest;
by sending special message at the end "END" for example.
Another solution: instead of looping 6/7, close the connection when data is read, and connect again.

Android can send udp but not receive

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.

Why does this thread only run once?

I have a server running on a separate thread, and for some reason, it only runs when it receives packets! Why is it doing this? Shouldn't it be running continuously?
public void run() {
while (running) {
System.out.println(true);
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
this.socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}
And I start it like this:
public static void main(String[] args) {
GameServer server = new GameServer();
server.start();
}
The class extends Thread.
socket.receive is a blocking method. So the code is waiting on receive untill you receive any data.
From here
public void receive(DatagramPacket p)
throws IOException
Receives a datagram packet from this socket. When this method returns,
the DatagramPacket's buffer is filled with the data received. The
datagram packet also contains the sender's IP address, and the port
number on the sender's machine.
This method blocks until a datagram is received. The length field of
the datagram packet object contains the length of the received
message. If the message is longer than the packet's length, the
message is truncated.
It clearly says that method blocks and wait for Datagram.
Your Thread is running correctly. The method DatagramSocket.receive(DatagramPacket) blocks until a packet is received.
The default behaviour is to block infinitely until a packet is received. You can specfiy a timeout using DatagramSocket.setSoTimeout(int), if you want to periodically log whether a packet is received or not, or to check if your Thread is still running.

Java Datagram Sockets not receiving packets

I'm attempting to use Java Datagrams to create a packet stream between server and client. The problem is that, although I receive confirmation that packets are being sent, they are all lost before they reach the client listener I set up. I have it right now so that there's a timeout after 5 seconds, which happens every time I run it.
class DGServer extends Thread
{
private DatagramSocket server;
public DGServer() throws IOException
{
server = new DatagramSocket();
}
public void run()
{
try
{
server.connect(App.Local, 4200);
System.out.println("Server starting...");
int i = 0;
while (server.isConnected() && (i < 256))
{
byte[] buffer = new byte[1];
buffer[0] = (byte) ++i;
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, App.Local, 4200);
System.out.println("Sedning " + i + " to client...");
server.send(packet);
Thread.sleep(500);
}
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("Server Finished!");
if (! server.isClosed())
server.close();
}
}
class DGClient extends Thread
{
private DatagramSocket client;
public DGClient() throws SocketException
{
client = new DatagramSocket();
}
public void run()
{
try
{
client.connect(App.Local, 4200);
client.setSoTimeout(5000);
System.out.println("Client starting...");
int i = 0;
while (client.isConnected() && (i < 256))
{
byte[] buffer = new byte[1];
DatagramPacket packet;
packet = new DatagramPacket(buffer, 1, App.Local, 4200);
//System.out.println("Sedning " + i + " to server...");
client.receive(packet);
buffer = packet.getData();
System.out.println("Client Received:\t" + packet.getData()[0]);
Thread.sleep(500);
}
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("Client Finished!");
if (! client.isClosed())
client.close();
}
}
You may choose to skim over the second class. They're widely the same, it just replaces server.send, with client.receive. Also, this class was not designed to really do anything important. So, a lot of the code(like, Exception handling), is written very simplistically.
Is there anything I can do to prevent the loss of packets? I have the port forwarded on my computer(not that it should matter, I'm using my localhost, which is App.Local in case you wondered).
Also, side question. I originally had it set up as a single class, coded to send a packet, then turn around and receive one. But it threw an exception because the 'ICMP Port is unreachable'. Does anyone know why this happens?
Ok first off, I think you are testing both the server and the client at the same time, so you don't have any idea whether which one fails.
You should use either netcat (nc) or wireshark to test the client
with netcat, you can run the following command
nc -l -u -p 4200 -vv
This will tell netcat to listen (-l) on udp (-u) on port (-p 4200) and be very verbose (-vv)
This way you'll be able to check if your client can connect to anything.
You can use the same program to check if your server can receive connections from a known working program with
nc -u [target ip] 4200
There is a netcat cheatsheet here
You can also check netcat to netcat to diagnose if it is purely a network issue. Maybe the firewalls/NAT aren't configured correctly
Why both server and client doing a connect ?
Shouldn't one side be sending the data ?
Something like :
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(buf, buf.length,
address, 4200);
socket.send(packet);
It sounds to me like there is some packet filter / firewall interfering with UDP traffic between the client and server on the port that you are using. It could be simple packet filtering, it could be NAT (which interferes with UDP traffic unless you take special steps), it could be some accidental network misconfiguration.
But it threw an exception because the 'ICMP Port is unreachable'. Does anyone know why this happens?
IMO, this is more evidence of packet filtering.
(However, its also a bit unexpected that you should receive this in response to trying to sent a datagram. I'd simply expect there to be no response at all, and any ICMP responses to a UDP request to have been dropped on the floor by the OS. But, I may be wrong about this ...
Now if you were using a regular stream socket; e.g. TCP/IP, this behaviour would be understandable.)
You're not binding the sending socket to a specific port number, so the client won't be able to send to it if connected. I suspect you have the same problem in reverse as well, i.e. the client socket isn't bound to port 4200. That would explain everything.
I would get rid of the connects and use explicit port numbers when sending, and the incoming port number when replying.
I am sure you are aware that UDP is a lossy proocol and you have allowed for this. Still you should expect to get some packets.
I suggest you test whether your program works by using the client and server on the same host and on different hosts, avoiding any firewalls. If this works then you have a network configuration issue.
If you are running both of them in the same machine this is never going to work because you are connecting both (server and client) to the same port.

Categories

Resources