Is there any good option to send broadcast message on UDP port while receiving data from other devices on the same port?
I have this currently:
First I initialize 1 DiagramSocket for both reading and sending:
private void startSocket(){
try {
if(socket == null) {
socket = new DatagramSocket(3040);
socket.setBroadcast(true);
socket.setReuseAddress(true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
In first Thread I have reading/receiving for current socket:
public class Server implements Runnable {
public Server(iBroadcastResponse iBResponse){
BroadcastClass.this.iBResponse = iBResponse;
}
#Override
public void run() {
startSocket();
while (DataHandler.isEmergencyMode.get() ) {
try {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
if(socket == null)
return;
socket.receive(packet);
String command = stringFromPacket(packet);
Log.d(TAG, command);
addToBroadcastCalls(command);
if(iBResponse != null)
iBResponse.onResponse();
} catch (Exception e) {
Log.e(TAG, "Server: Error!\n");
}
}
Log.e(TAG, "Stop!");
}
String stringFromPacket(DatagramPacket packet) {
return new String(packet.getData(), 0, packet.getLength());
}
}
If I run this, it works normally, reads receiving data. But if I try to send data in another thread:
socketThread = new Thread(){
#Override
public void run() {
startSocket();
String message = "Message";
byte[] buf = message.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
if(!socket.isConnected())
socket.connect(InetAddress.getByName("255.255.255.255"), 3040);
if (socket != null) {
socket.send(packet);
}
Log.d(TAG, "Send: " +message);
} catch (Exception e) {
e.printStackTrace();
}
}
};
socketThread.start();
When .send() is called it stops receiving data from other devices so now it only send message but stops receiving it from other devices.
Is there any good solution to this problem?
This was the solution
https://stackoverflow.com/a/25520279/1088975
I only changed
System.log...
To
Log.w(TAG, "Message...");
And I changed IP to be always "255.255.255.255" instead of
getBroadcastAddress()
which returns broadcast IP for current WIFI, which didn't work on my android devices
Related
I'm new to Android, somewhat new to socket programming. I have two devices, running Android 5.1, connected with WiFi direct (not sure if that's relevant). I have a service where the server listens for a request on a socket, then returns a reply back to the client.
Likewise the client code sends a request and listens for the reply from the server. The server is sending the response, but the client never gets the message and the socket times out.
Server test code:
while (true) {
try {
Log.i(TAG, "test waiting for a request");
mServer = new ServerSocket(PORT);
Socket socket = mServer.accept(); //Block to receive message //
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i(TAG, "Message received! " + in.readLine());
String msg = "This is my reply.";
OutputStream outputStream = socket.getOutputStream();
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
out.println(msg);
out.flush();
out.close();
} catch (SocketException e) {
Log.e(TAG, "Socket Accept Interrupted", e);
} catch (IOException e) {
Log.e(TAG, "Socket Failure", e);
} finally {
if (mServer != null && mServer.isBound()) {
try {
mServer.close();
} catch (IOException ioException) {
Log.e(TAG, "Failed to close socket trying to recover from SocketException", ioException);
}
}
}
}
Client test code:
Socket socket = null;
SocketAddress addr = new InetSocketAddress(host, PORT);
int socketTOms = 5000;
try {
socket = new Socket(host, PORT);
socket.setKeepAlive(false);
String syncReq = "Request to server.";
//Send Request//
OutputStream outputStream = socket.getOutputStream();
outputStream.write(syncReq.getBytes());
socket.setSoTimeout(socketTOms);
//Rcv reply//
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i(TAG, "Message received! " + in.readLine());
} catch (SocketTimeoutException e) {
Log.e(TAG, "Timeout while reading from socket: timeout=" + socketTOms);
} catch (Exception e) {
Log.e(TAG, "Exception", e);
} finally {
if (socket != null && socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Exception while closing socket", e);
}
}
}
I'm running the server and client on two different devices through Android Studio and can see in the logs that the server receives the request and sends the reply, but the client always throws SocketTimeoutException. I saw else where that socket.setKeepAlive(false) would fix the problem, but it doesn't seem to have any effect.
Seems simple enough, but I can't see what I'm missing here.
May be try this line of code before infinite loop mServer = new ServerSocket(PORT);
Did you try to create thread in sever side app. This makes the process to run in parallel so that while server is waiting for request the application does not gets hang. First of all try this code for localhost . To find Inetaddress just use InetAddress.getLocalHost(). Then run this. For communication with different devices there is service provided that is called (NSD) (Network Service Discovary).
But if you want to run this way I have written a code for you.
Server side code
TextView textView;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView=(TextView)findViewById(R.id.textView);
button=(Button)findViewById(R.id.button);
button.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
connect();
}
}
);
}
public void connect()
{
MyServer myServer= new MyServer();
myServer.setEventListener(this);
myServer.startListening();
}
#Override
public void Display(String message) {
textView.setText("Client - "+ message);
}
}
Client side code
TextView textView;
Button button;
Thread mThread;
Socket clientSocket;
Button sendBtn;
public String userText1;
ObjectOutputStream output;
EditText editText;
Object userText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView=(TextView)findViewById(R.id.textView);
button=(Button)findViewById(R.id.button);
sendBtn=(Button)findViewById(R.id.sendBtn);
editText=(EditText)findViewById(R.id.editText);
sendBtn.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
userText=editText.getText().toString();
start();
}
}
);
public void start()
{
mThread= new Thread(new Runnable() {
#Override
public void run() {
try {
clientSocket = new Socket("127.0.0.1", 2001);
Log.v("binaya", "client socket created");
output = new ObjectOutputStream(clientSocket.getOutputStream());
output.writeObject(userText);
Message serverObj = Message.obtain();
ObjectInputStream input = new ObjectInputStream(clientSocket.getInputStream());
String strMsg = input.readObject().toString();
serverObj.obj = strMsg;
mHandler.sendMessage(serverObj);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
});
mThread.start();
}
Handler mHandler= new Handler()
{
#Override
public void handleMessage(Message msg) {
msgDisplay(msg.obj.toString());
}
};
private void msgDisplay(String msg) {
textView.setText("Server - " + msg);
}
We have used handler because we cannot touch user interface from inside runnable in this case.
Thanks
Figured this out ....
On the client side I was using outputStream.write(...) to send the request to the server as in:
String syncReq = "Request to server.";
OutputStream outputStream = socket.getOutputStream();
outputStream.write(syncReq.getBytes());
But reading it on the server with BufferedReader.readLine():
Socket socket = mServer.accept(); //Block to receive message //
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i(TAG, "Message received! " + in.readLine());
My problem was that outputStream.write(...) does not append a '\n' at the end of the String, but in.readLine() on the server expects it. Therefore the server was blocking while waiting for '\n'; which in turn caused the client socket to timeout.
I am developing a android wifi -chat application .
Bit of Info about my app :
->A device calls startserver() to act as a server ,another device calls start client() to act as a client
What works:
->A Client can successfully send the data for the first time to the client, but not again and again
->I need to call startserver() again on first device , so that client can send data again .
The startserver() calls this Async task ,the following is its DoinBackgroundMethod
protected String doInBackground(Void... params) {
ServerSocket serverSocket = null;
try {
while(true) {
serverSocket = new ServerSocket(PORT);
Socket client = serverSocket.accept();
StartMSG(client);
}
} catch (IOException e) {
return null;
} finally {
try {
chatclient.changeserverrunning(false);
if (serverSocket == null) {
} else {
serverSocket.close();
}
return null;
} catch (Exception e) {
}
}
//return null;
}
protected void StartMSG(Socket client){
try {
InputStream inputstream = client.getInputStream();
ObjectInputStream ois = new ObjectInputStream(inputstream);
Message m = null;
try {
m = (Message) ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if (m != null) {
if (m.gettype() == 1) {
final String my_msg = m.getMessage();//Toast msg afterwards
}
}catch (Exception e){
}
}
Client Side Code :
It is started when the client hits send button and calls start client method .in which It sets up the Ip values before and bundles them and calls the message sending part as a Intent Service called FileTransferService
Its code is (abstracted) :
protected void onHandleIntent(Intent intent) {
Context context = getApplicationContext();
if(socket==null){
socket = new Socket();
}
if (intent.getAction().equals(ACTION_SEND_FILE)) {
final String msg_type=intent.getExtras().getString(MESSAGE_TYPE);
String host = intent.getExtras().getString(EXTRAS_ADDRESS);
int port = intent.getExtras().getInt(EXTRAS_PORT);
try {
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
Message m = (Message) intent.getExtras().getSerializable(MESSAGE_INTENT_STR);
final String my_message=m.getMessage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(m);
oos.flush();
oos.close();
InputStream is = new ByteArrayInputStream(baos.toByteArray());
OutputStream stream = socket.getOutputStream();
ChatClient.copyFile(is, stream);
} catch (IOException e) {
} finally {
if (socket != null) {
if (socket.isConnected()) {
try {
//socket.close();
} catch (Exception e) {
// Give up
e.printStackTrace();
}
}
}
}
}
}
You should try https://github.com/tavendo/AutobahnAndroid and run the client from a service, from an asyntask it will always end up finishing.
I want to make my android app open socket to my windows console app and they communicate with each other. The socket is opened and data is sent and received in windows app, but my android app does not receive the answer which sent by windows. I watch the packets in my android and I saw the packets are coming but I do not know why my app do not receive it!
windows app server class:
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public Server()
{
Console.WriteLine("\nStarting server...");
this.tcpListener = new TcpListener(IPAddress.Any, 1234);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
Console.WriteLine("\nWaiting for clients to connect...");
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
Console.WriteLine("\nIncoming from client...");
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
try
{
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
Console.WriteLine("\nReceived: \n\n" + encoder.GetString(message, 0, bytesRead));
//By FMR
string response = "random responsive: " + new Random().Next(1000).ToString() + "\n";//"\r\n";
//writeData(clientStream, response);
byte[] msg = System.Text.Encoding.ASCII.GetBytes(response);
// Send back a response.
clientStream.Write(msg, 0, msg.Length);
clientStream.Flush();
Console.WriteLine("\nResponed ..." + response);
}
}
catch (Exception ex)
{
Console.WriteLine("\nException while: " + ex.Message);
}
tcpClient.Close();
}
}
my android thread:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Socket socket = null;
ServerSocket serverSocket = null;
Boolean bRun = true;
try {
socket = new Socket(ip, port);
if(outputStream == null) {
outputStream = new DataOutputStream(socket.getOutputStream());
}
// become server
serverSocket = new ServerSocket(port);
Log.i(G.TAG, "before serverSocket.accept");
socket = serverSocket.accept();
Log.i(G.TAG, "response recieve: ");
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
catch (Exception e) {
try {
serverSocket.close();
} catch (IOException e1) {
Log.e(G.TAG, "serverSocket.close() e: " + e1.getMessage());
}
try {
socket.close();
} catch (IOException e1) {
Log.e(G.TAG, "socket.close() e: " + e1.getMessage());
}
}
Log.i(G.TAG, "after start recieve: ");
while (bRun) {
try {
Log.i(G.TAG, "while start: ");
String message = inputStream.readLine();
Log.i(G.TAG, "response message: " + message);
if (message != null) {
setListMessage(false, message);
}
}
catch (IOException e) {
bRun = false;
Log.e(G.TAG, "while bRun e: " + e.getMessage());
}
}
}
});
thread.start();
// in another function, my message is sent successfully from android and receive in windows
I found the problem, this line
socket = serverSocket.accept();
made the problem when I comment the line, the android app received the response!
Does anybody know why?
I'm pretty new to writing Android apps, and I wanted to write a piece of code that broadcasts the sensor data at a regular interval, say 1 second. Searching open-source codes I managed to write a sender class as below:
public class Sender extends Thread {
private static final String TAG = "Sending";
private static final int PORT = 12346;
private static final int TIMEOUT_MS = 500;
private static final int BUF_SIZE = 1024;
private WifiManager mWifi;
Sender(WifiManager wifi) {
mWifi = wifi;
}
public void run() {
try {
DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
socket.setSoTimeout(TIMEOUT_MS);
sendData(socket);
socket.close();
Thread.sleep(1000);
}
catch (IOException ioe) {
Log.e(TAG, "Couldn't send data", ioe);
}
catch (InterruptedException ie) {
Log.e(TAG, "Can't sleep", ie);
}
}
private void sendData(DatagramSocket socket) throws IOException {
byte[] buf = new byte[BUF_SIZE];
buf = object.toString().getBytes();
InetAddress addr = InetAddress.getByName("192.168.0.255"); // TO FIX
DatagramPacket packet = new DatagramPacket(buf, buf.length, addr, PORT);
socket.send(packet);
}
public void main(String[] args) {
new Sender(null).start();
while (true) {
}
}
}
And here's how I start it from within the onCreate method:
public void onCreate(Bundle savedInstanceState) {
...
new Sender((WifiManager) getSystemService(Context.WIFI_SERVICE)).start();
...
}
Now, if I open Wireshark on my laptop, I only see one packet sent at the time the app is started instead of every one second.
Could someone please point out where I did wrong? Honestly I'm not that familiar with threads and stuff, so I may just be missing something obvious here...
EDIT
OK, so the run method must be looped. See corrected code in the answer below.
Here's the corrected run method code:
public void run() {
while (true) {
try {
DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
socket.setSoTimeout(TIMEOUT_MS);
sendData(socket);
socket.close();
Thread.sleep(1000);
}
catch (IOException ioe) {
Log.e(TAG, "Couldn't send data", ioe);
}
catch (InterruptedException ie) {
Log.e(TAG, "Can't sleep", ie);
}
}
}
I use the following code to receive the data from a particular port. It's not working in Android. But sending data to particular port is working fine.
public class UDPDemo extends Activity {
private TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.recv_message);
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);
}
}
}
If you are using the emulator you may need setup redirects, remember the emulator is behind a virtual router.
In other words, type these commands in;
telnet localhost 5554
redir add udp:9876:9876
and try again.
Used Port numbers
Create Datagram packet
try {
mDataGramSocket = new DatagramSocket(Config.PORT_NUMBER);
mDataGramSocket.setReuseAddress(true);
mDataGramSocket.setSoTimeout(1000);
} catch (SocketException e) {
e.printStackTrace();
}
Call below function through AsyncTask
Create Function to receive infinitely
public void receive() {
String text;
byte[] message = new byte[1500];
DatagramPacket p = new DatagramPacket(message, message.length);
try {
while (true) { // && counter < 100 TODO
// send to server omitted
try {
mDataGramSocket.receive(p);
text = new String(message, 0, p.getLength());
// If you're not using an infinite loop:
//mDataGramSocket.close();
} catch (SocketTimeoutException | NullPointerException e) {
// no response received after 1 second. continue sending
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
// return "error:" + e.getMessage();
mReceiveTask.publish("error:" + e.getMessage());
}
// return "out";
}