Android Lag in udp transmission - java

I have a problem with lag in udp transmission (over a local wifi network). The host sends data to all clients using UdpSender at 50Hz :
UDPSender:
public class UDPSender {
private DatagramSocket socket;
private DatagramPacket packet;
private ByteBuffer bb;
private InetAddress targetAddress;
private byte[] bytearray;
public UDPSender(int port,String targetAddress){
try {
this.targetAddress = InetAddress.getByName(targetAddress);
} catch (UnknownHostException e) {
}
try {
socket = new DatagramSocket();
} catch (IOException e) {
}
bb = ByteBuffer.allocate(169);
bytearray = bb.array();
packet = new DatagramPacket(bytearray, bytearray.length, this.targetAddress, port);
}
public void sendSignal(/*args*/){
if(!socket.isClosed()){
bb.putInt(pos, ...) //fill 'bb' with data from args
...
bytearray = bb.array();
packet.setData(bytearray);
try {
socket.send(packet);
} catch (IOException e) {
}
}
}
public void close(){
socket.close();
}
}
UDPReceiver:
public class UDPReceiver {
private DatagramSocket socket;
private DatagramPacket packet;
private byte[] packetDataBuffer = new byte[169];
private UDPSignalListener listener = null;
private ByteBuffer bb;
private String hostAddress;
private boolean isOpen = false;
private byte buffer;
private short bytes;
public UDPReceiver(int port, String hostAddress, UDPSignalListener listener){
try {
socket = new DatagramSocket(port);
} catch (IOException e) {
if(listener!=null)
listener.errorOpeningSocket(port);
}
packet = new DatagramPacket(packetDataBuffer, packetDataBuffer.length);
this.hostAddress = hostAddress;
this.listener = listener;
isOpen = true;
Thread t = new Thread(new Runnable(){
#Override
public void run() {
listen();
}
});
t.setDaemon(true);
t.start();
}
public void start(String hostAddress){
this.hostAddress = hostAddress;
isOpen = true;
Thread t = new Thread(new Runnable(){
#Override
public void run() {
listen();
}
});
t.setDaemon(true);
t.start();
}
private void listen(){
while(isOpen){
try {
socket.receive(packet);
} catch (IOException e) {
continue;
}
if(!isOpen)
return;
if(packet.getAddress().getHostAddress().equals(hostAddress)){
bb = ByteBuffer.wrap(packetDataBuffer);
//read data from bb
if(listener!=null)
listener.onSignalRecieved(/*pass data to program*/);
}
}
}
public int getPort(){
return socket.getLocalPort();
}
public void close(){
isOpen = false;
socket.close();
}
}
MainThread on host-side:
mainThread = new Thread(new Runnable(){
public void run(){
while(isMainLoopRunning){
...
for(int i=0;i<udpSender.length/*max 5*/;++i)
udpSender[i].sendSignal(...); //~50fps constantly //send data to client i
...
}
}
});
the client side gets the data via UDPSignalListener.onSignalReceived() (should be called every 20ms (50fps)). The data is saved and is used in the client's mainThread (which also runs at 50fps constantly). Unfortunately there is sometimes a lag (a delay up to 1 second), i.e onSignalReceived is not called every 20ms constantly. What could be the reason for the lag?

Related

Application doesn't enter thread

i'm trying to create a chat application using multhitreading functionalities and here's the code of the session class that handles connections and of the server class that accept connections:
Session class:
public class Session extends Thread{
Socket Sock;
BufferedReader din;
PrintWriter dout;
Thread receive;
Server serv;
boolean connected = false;
String lineSep = System.getProperty("line.separator");
public Session(Socket s, Server n){
super("ThreadSessions");
this.Sock = s;
this.serv = n;
}
public void run(){
try{
din = new BufferedReader(new InputStreamReader(Sock.getInputStream()));
dout = new PrintWriter(Sock.getOutputStream());
connected = true;
Receive();
}
catch(IOException ioe){
ioe.printStackTrace();
}
receive.start();
}
public void sendTo(String text){
dout.write(text);
dout.flush();
}
public void sendToAll(String text){
for(int ind = 0; ind < serv.sessions.size(); ind++){
Session s = serv.sessions.get(ind);
s.sendToAll(text);
}
}
public void Receive(){
receive = new Thread(new Runnable(){
#Override
public void run() {
receive = new Thread(new Runnable(){
String msgIn;
public void run() {
while(connected){
try{
msgIn = din.readLine();
if(msgIn != "" || msgIn != null){
System.out.println(msgIn);
msgIn = "";
}else{
}
}
catch(SocketException exc){
exc.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
});
}
}
Server class:
public class Server {
private JFrame frame;
private JTextField txtPort;
JTextArea textArea, textSessions;
String lineSep = System.getProperty("line.separator");
ServerSocket ServSock;
Socket Sock;
String port;
public JTextField textField;
int numbSess = 0, actSess = 0;
ArrayList<Session> sessions = new ArrayList<Session>();
boolean shouldRun = true;
public static void main(String[] args)
{
Server window = new Server();
window.frame.setVisible(true);
}
public Server() {
initializeComponents(); //This void initializes the graphic components
}
private void Connect(){
port = txtPort.getText();
int portN = 0;
try{
portN = Integer.parseInt(port);
}
catch(NumberFormatException exc)
{
exc.printStackTrace();
}
try{
ServSock = new ServerSocket(9081);
while(shouldRun){
Sock = ServSock.accept();
String ip = Sock.getInetAddress().getHostAddress();
Session s = new Session(Sock, this);
s.start();
sessions.add(s);
numbSess++;
}
}
catch(Exception exc){
exc.printStackTrace();
System.exit(3);
}
}
private void initializeComponents() {
[...]
Button btnConn = new JButton("Open Connection");
btnConn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Connect();
}
});
btnConn.setBackground(new Color(0, 0, 0));
btnConn.setForeground(new Color(0, 128, 0));
btnConn.setBounds(160, 13, 137, 25);
frame.getContentPane().add(btnConn);
[...]
}
What i want to do is creating a chat application that can handle more connection at the same time but instead of entering the first connection(session in my app.) it continues waiting for other connections and adding those in the arrayList.
Probably the code is full of mistakes so forgive me.
If somebody knows a better way to create a server that can handle more client's connections those are welcome.
Hope someone can help me, thanks in advance.
instead of entering the first connection(session in my app.) it continues waiting for other connections and adding those in the arrayList
This is due to how your threads are set up
Each time you make and start a session, its run method is called...
public void run()
{
Receive();
[...]
receive.start();
}
...which in turn sets up receive in Receive();
public void Receive()
{
receive = new Thread(new Runnable()
{
public void run()
{
receive = new Thread(new Runnable()
{
public void run()
{
//your actual code that you wanted to run
}
});
}
});
}
The thread created when ran, will do one thing, set up receive yet again, with the code you wanted the first time
receive = new Thread(new Runnable()
{
public void run()
{
//your actual code that you wanted to run
}
});
But after you call Receive();, you only called receive.start(); once
You'll either need to call it twice, and somehow ensure that it updated in time, or just remove the excess thread

How to implement thread in succession

I would like to implement a transfer with socket for transfering pictures and check on the server if the picture is ever loaded and if it is true not transfering the picture simply change the imageView.
I have a client and a server which work for simply transfer picture between 2 devices. But i want to send a hash of each pictures once at each time before send them. My dificulty is primarily on the thread manager, i have implement a listener for the 1st thread (send / receive picture's hash on client / server) to know when it's finished and then start the second thread (send / receive pictures on client / server). But i don't know if my methodology is ok because it doesn't work well (the server receive the hash on the start but not the other).
I hope that i am clear, here is my parts of code concerned, thanks to someone who can give me a solution.
Server
private class ReceiverHash extends Thread {
private List<TaskListener> listeners = new ArrayList<TaskListener>();
public void addListener(TaskListener listener) {
listeners.add(listener);
}
void getTaskState(Boolean state) {
for (TaskListener listener : listeners) {
listener.getTaskState(state);
}
}
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(socketServerPORT);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
while (true) {
String str = br.readLine(); // lecture du message
if (str.equals("END")) {
serverSocket.close();
getTaskState(true);
break;
}
hashList.add(str);
Log.d("HASH_RECEIVER_LOG", str); // Log debug hash
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class Receiver extends Thread {
int pos = 0;
int cmpt = 0;
#Override
public void run() {
// create ServerSocket using specified port
try {
ServerSocket serverSocket = new ServerSocket(socketServerPORT);
while (true) {
//checkFileExist();
File f = new File(getFilesDir(), "img" + Integer.toString(pos) + ".png");
fileList.add(f);
Log.d("HASH_RECEIVER_LOG", "Attente d'une réponse du client");
Socket socket = serverSocket.accept();
Log.d("HASH_RECEIVER_LOG", "Reception d'une réponse");
f.createNewFile();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = new FileOutputStream(f);
byte[] bytes = new byte[2 * 1024];
int count;
while ((count = inputStream.read(bytes)) > 0) {
Log.d("RECEIVER_CMPT", Integer.toString(cmpt));
outputStream.write(bytes, 0, count);
cmpt = cmpt + count;
}
myBitmap = BitmapFactory.decodeFile(f.getAbsolutePath());
runOnUiThread(new Runnable() {
#Override
public void run() {
imgDiapo.setImageBitmap(myBitmap);
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
How i use listener on the activity :
ReceiverHash receiverHash = new ReceiverHash();
receiverHash.start();
receiverHash.addListener(this);
Client
public class Sender extends AsyncTask<Void, Void, Void> {
private String dstAddress;
private int dstPort;
private String fPath;
public Sender(String address, int port, String path) {
dstAddress = address;
dstPort = port;
fPath = path;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
FileInputStream inputStreamSend = new FileInputStream(fPath);
OutputStream outputStreamSend = socket.getOutputStream();
byte[] buffer = new byte[2 * 1024];
int count;
while ((count = inputStreamSend.read(buffer)) > 0) {
outputStreamSend.write(buffer, 0, count);
}
outputStreamSend.close();
inputStreamSend.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public class HashSender extends AsyncTask<Void, Void, Void> {
private String dstAddress;
private int dstPort;
String hash;
//private ArrayList <String> listHash;
private List<TaskListener> listeners = new ArrayList<TaskListener>();
public HashSender(String address, int port, String path) throws IOException, NoSuchAlgorithmException {
dstAddress = address;
dstPort = port;
hash = sha1(new File(path)); //methode encryption in sha1
}
public void addListener(TaskListener listener) {
listeners.add(listener);
}
void getTaskState(Boolean state) {
for (TaskListener listener : listeners) {
listener.getTaskState(state);
}
}
#Override
protected void onPostExecute(Void v) {
getTaskState(true);
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
OutputStream outputStreamSend = socket.getOutputStream();
BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(outputStreamSend));
buf.write(hash);
buf.newLine();
buf.flush();
Log.d("toto", hash);
buf.write("END");
buf.newLine();
buf.flush();
outputStreamSend.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
How i use listener on the activity :
HashSender hashSender = new HashSender(dstAddress.get(i), dstPort, selectedItemPath.get(pos));
hashSender.addListener(ControlsActivity.this);
hashSender.execute();

how to Receive UDP packets, when it comes from server? for android java

I have used a thread for UDP receive packet. When I am sending a packet to that particular IP, where the UDP receive program runs. The application will be stopped unfortunately. Then if I remove the thread called new Thread(new Runnable()) and public void run the application will run good, but only one data has received. My intention is to receive data at the receiver end continuously, when data comes. please acknowledge me.
udpserver.java:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class UdpServer extends Activity {
/** Called when the activity is first created. */
private TextView data;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
data = (TextView) findViewById(R.id.textView);
runUdpServer();
}
private static final int UDP_SERVER_PORT = 11111;
private static final int MAX_UDP_DATAGRAM_LEN = 1500;
private void runUdpServer() {
new Thread(new Runnable() {
public void run() {
String lText;
byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
DatagramSocket ds=null;
try {
ds = new DatagramSocket(UDP_SERVER_PORT);
//disable timeout for testing
//ds.setSoTimeout(100000);
ds.receive(dp);
lText = new String(dp.getData());
Log.i("UDP packet received", lText);
data.setText(lText);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
if (ds != null) {
ds.close();
}
}
}
}).start();
}
This is a working snippet I am using to receive and parse UDP packets.
try {
int port = 11000;
DatagramSocket dsocket = new DatagramSocket(port);
byte[] buffer = new byte[2048];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
dsocket.receive(packet);
lText = new String(buffer, 0, packet.getLength());
Log.i("UDP packet received", lText);
data.setText(lText);
packet.setLength(buffer.length);
}
} catch (Exception e) {
System.err.println(e);
e.printStackTrace();
}
You can setup a loop to read data from the udp socket.
try {
ds = new DatagramSocket(UDP_SERVER_PORT);
//disable timeout for testing
//ds.setSoTimeout(100000);
while (!ds.isClosed()) {
ds.receive(dp);
lText += new String(dp.getData());
Log.i("UDP packet received", new String(dp.getData());
runOnUiThread(new Runnable() {
public void run() {
data.setText(lText);
}
});
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ds != null) {
ds.close();
}
}
UPDATE: since the packet data is received in non-UI thread. Direct access to data.setText(lText) in worker thread is invalid.
Send data and get Answer example:
new Thread(()->{
String message = "Hello Madam Coco";
byte[] msgbyte = message.getBytes(StandardCharsets.UTF_8);
int port = 12345;
String ip = "123,123,123,123";
try {
byte[] receviebyte = new byte[1024];
DatagramSocket socket = new DatagramSocket();
InetAddress address = InetAddress.getByName(ip);
DatagramPacket sendPack = new DatagramPacket(msgbyte, msgbyte.length, address, port);
socket.send(sendPack);
DatagramPacket receviePack = new DatagramPacket(receviebyte, receviebyte.length);
while (true) {
socket.receive(receviePack);
String receivestr = new String(receviebyte, receviePack.getOffset(), receviePack.getLength());
System.out.println("GETTEXT " + receivestr);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
try {
DatagramSocket clientsocket=new DatagramSocket(9876);
byte[] receivedata = new byte[1024];
while(true)
{
DatagramPacket recv_packet = new DatagramPacket(receivedata, receivedata.length);
Log.d("UDP", "S: Receiving...");
clientsocket.receive(recv_packet);
String rec_str = new String(recv_packet.getData());
tv.setText(rec_str);
Log.d(" Received String ",rec_str);
InetAddress ipaddress = recv_packet.getAddress();
int port = recv_packet.getPort();
Log.d("IPAddress : ",ipaddress.toString());
Log.d(" Port : ",Integer.toString(port));
}
} catch (Exception e) {
Log.e("UDP", "S: Error", e);
}

send message (String) from file to MainActivity

I have a file with contains my server that get’s content from a client app. How can I send the content the server receives to my MainActvity?
if I try MainActivity main = new MainActivity(); in the server file the app crashes.
Server file.
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
connected_server = true;
} catch (IOException e) {
connected_server = false;
e.printStackTrace();
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
if (msg != null){
//Where I need to send the received content to the main activity
Log.e("INPUT", msg);
}
}
}
Main Activity
public class MainActivity extends Activity {
…
public void message_recieve(String msg){
// do stuff with messages
}
}
You need to implement a callback, so that you can receive the result correctly when the server request ends

Android sends UDP packets to a Java client over WiFi

I'm creating 2 programs which one of them sends UDP packets from an Adnroid device and a second one (Java) receives them. So it works good if I use WiFi-router. But if I use a direct connection the Java application doesn't receive these packets. Under the direct connection I mean creating HOTSPOT on computer and connecting to it by the Android device. I used code snippet bellow:
Server's code:
public class UDPServer {
InetAddress groupAddress;
DatagramPacket packet;
byte[] buffer;
DatagramSocket socket;
static String ip = "227.0.25.57";
static int port = 6789;
private boolean isRun = false;
private String message = "";
private int broadcastInterval;
public void StopBroadcasting(){
isRun = false;
}
public void StartBroadcasting(String message, int broadcastInterval){
isRun = true;
this.message = message;
this.broadcastInterval = broadcastInterval;
new Thread(runner).start();
}
Runnable runner = new Runnable() {
#Override
public void run() {
while(isRun){
try {
SendBroadcastMessage(message);
System.out.println("msg sended...");
Thread.sleep(broadcastInterval);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("Stopping UDPServer...");
}
};
public UDPServer() {
buffer = new byte[4096];
try {
groupAddress = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
socket = new DatagramSocket();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void SendBroadcastMessage(String msg) throws IOException{
if(msg==null) return;
buffer = msg.getBytes();
packet = new //DatagramPacket(buffer, buffer.length);
DatagramPacket(buffer, buffer.length, groupAddress, port);
socket.send(packet);
}
public static void Send(String msg){
try {
InetAddress group = InetAddress.getByName(ip);
MulticastSocket s = new MulticastSocket(port);
s.joinGroup(group);
DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(),
group, port);
s.send(hi);
System.out.println("send...");
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
Client's code:
public class UDPClient {}
MulticastSocket socket;
InetAddress groupAddress;
DatagramPacket packet;
byte[] buffer;
static String ip = "227.0.25.57";
static int port = 6789;
public interface OnReceiveDataListener{
public abstract void onReceiveData(String data);
}
private OnReceiveDataListener ReceiveDataListener = null;
public void setReceiveDataListener(OnReceiveDataListener ReceiveDataListener) {
this.ReceiveDataListener = ReceiveDataListener;
}
public OnReceiveDataListener getReceiveDataListener() {
return ReceiveDataListener;
}
private boolean isRun = false;
private Thread broadcastReceiver;
public void StopBroadcasting(){
isRun = false;
if(broadcastReceiver!=null)
broadcastReceiver.interrupt();
}
public void StartBroadcasting(){
isRun = true;
broadcastReceiver = new Thread(runner);
broadcastReceiver.start();
}
Runnable runner = new Runnable() {
#Override
public void run() {
while(isRun){
try {
String msg = ReceiveBroadcastMessage();
if(ReceiveDataListener!=null)
ReceiveDataListener.onReceiveData(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
public UDPClient(){
buffer = new byte[4096];
try {
groupAddress = InetAddress.getByName(ip);
socket = new MulticastSocket(port);
socket.joinGroup(groupAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String ReceiveBroadcastMessage() throws IOException{
packet = new DatagramPacket(buffer, buffer.length);
System.out.println("before receive");
socket.receive(packet);
System.out.println(packet.getData());
return new String(packet.getData());
}
public void DeInit(){
try {
socket.leaveGroup(groupAddress);
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
MulticastSocket msocket;
public static void Receive(){
MulticastSocket msocket;
try {
msocket = new MulticastSocket(port);
InetAddress group = InetAddress.getByName(ip);
msocket.joinGroup(group);
byte[] inbuf = new byte[1024];
DatagramPacket packet = new DatagramPacket(inbuf, inbuf.length);
System.out.println("before receive");
msocket.receive(packet);
System.out.println("after receive");
int numBytesReceived = packet.getLength();
System.out.println(new String(packet.getData()));
msocket.leaveGroup(group);
msocket.close();
System.out.println(numBytesReceived);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
If you could see I have 2 methods of sending and receiving packets. The both don't work! What do I wrong?
Help me please.
I've found solution:
http://code.google.com/p/boxeeremote/wiki/AndroidUDP

Categories