Really simple TCP client
I want with my app to enter in the url of my server e.g. http://192.168.1.8/
and the port e.g. 1234
.
When my server receives the TCP Request message, it sends back a file (the server is already implemented).
I think that I don't need something complicated like an AsyncTask, as I do not want to keep the connection. Receiving the answer from the server, my connection must be closed.
Any indication for a way forward or a tip is highly appreciated.
Here is a simple TCP client that uses Sockets that I got working based on code in this tutorial (the code for the tutorial can also be found in this GitHub repository).
Note that this code is geared to sending strings back and forth between the client and server, usually in JSON format.
Here is the TCP client code:
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClient {
public static final String TAG = TcpClient.class.getSimpleName();
public static final String SERVER_IP = "192.168.1.8"; //server IP address
public static final int SERVER_PORT = 1234;
// message to send to the server
private String mServerMessage;
// sends message received notifications
private OnMessageReceived mMessageListener = null;
// while this is true, the server will continue running
private boolean mRun = false;
// used to send messages
private PrintWriter mBufferOut;
// used to read messages from the server
private BufferedReader mBufferIn;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TcpClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* @param message text entered by client
*/
public void sendMessage(final String message) {
Runnable runnable = new Runnable() {
@Override
public void run() {
if (mBufferOut != null) {
Log.d(TAG, "Sending: " + message);
mBufferOut.println(message);
mBufferOut.flush();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
/**
* Close the connection and release the members
*/
public void stopClient() {
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.d("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
//sends the message to the server
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//receives the message which the server sends back
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in this while the client listens for the messages sent by the server
while (mRun) {
mServerMessage = mBufferIn.readLine();
if (mServerMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(mServerMessage);
}
}
Log.d("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the Activity
//class at on AsyncTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
Then, declare a TcpClient as a member variable in your Activity:
public class MainActivity extends Activity {
TcpClient mTcpClient;
//............
Then, use an AsyncTask for connecting to your server and receiving responses on the UI thread (Note that messages received from the server are handled in the onProgressUpdate()
method override in the AsyncTask):
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
@Override
protected TcpClient doInBackground(String... message) {
//we create a TCPClient object
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
@Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//response received from server
Log.d("test", "response " + values[0]);
//process server response here....
}
To start the connection to your server, execute the AsyncTask:
new ConnectTask().execute("");
Then, sending a message to the server:
//sends the message to the server
if (mTcpClient != null) {
mTcpClient.sendMessage("testing");
}
You can close the connection to the server at any time:
if (mTcpClient != null) {
mTcpClient.stopClient();
}
Thanks for code. In my case I was having trouble receiving data, as I'm not using a line-based protocol. I wrote an alternate implementation that works with my specific server setup:
-
In TcpClient.java file, "run()" command you should replace with code fragment below
public void run() {
mRun = true; try { InetAddress serverAddr = InetAddress.getByName(SERVER_IP); Log.e("TCP Client", "C: Connecting..."); Socket socket = new Socket(serverAddr, SERVER_PORT); try { mBufferOut = new PrintWriter(socket.getOutputStream()); Log.e("TCP Client", "C: Sent."); mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream())); int charsRead = 0; char[] buffer = new char[1024]; //choose your buffer size if you need other than 1024 while (mRun) { charsRead = mBufferIn.read(buffer); mServerMessage = new String(buffer).substring(0, charsRead); if (mServerMessage != null && mMessageListener != null) { mMessageListener.messageReceived(mServerMessage);} mServerMessage = null; } Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");
//rest of code is OK, see original
-
doInBackgroud in your MainActivity.java posts received message to onProgressUpdate, you can display it in other object e.g. TextView
@Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); Log.d("test", "response " + values[0]); response.setText(response.getText() + "/n" +values[0]); }
//"response" is TextView object declared in your function
public class MainActivity extends AppCompatActivity {
TextView response; //...so on
and function
protected void onCreate(Bundle savedInstanceState) {
response = (TextView) findViewById(R.id.textView); //..so on
first of all give internet permission to your app in android manifest
<uses-permission android:name="android.permission.INTERNET"/>
you can use AsyncTask
to send your request and receive your file back so easily
public void send_request() {
send_request sr = new send_request();
sr.execute();
}
class send_request extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... voids) {
try { /*note : ip address must be in Quotation mark*/
/*note : port doesn't need to be inside the Quotation mark*/
Socket s = new Socket(/*ip address :*/"192.168.1.8",/*port :*/ 1234);
PrintWriter printWriter = new PrintWriter(s.getOutputStream());
printWriter.write("your message");
printWriter.flush();
printWriter.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
public void onPostExecute(final String Data) {
/*Data is what you receive from your server*/
Log.e("my_Data","Data is : " + Data);
}
}
Try this code in TcpClient :
public void run() {
mRun = true;
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.e("TCP Client", "C: Connecting...");
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
mBufferOut = new PrintWriter(socket.getOutputStream());
Log.e("TCP Client", "C: Sent.");
mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int charsRead = 0; char[] buffer = new char[2024]; //choose your buffer size if you need other than 1024
while (mRun) {
charsRead = mBufferIn.read(buffer);
mServerMessage = new String(buffer).substring(0, charsRead);
if (mServerMessage != null && mMessageListener != null) {
Log.e("in if---------->>", " Received : '" + mServerMessage + "'");
}
mServerMessage = null;
}
Log.e("-------------- >>", " Received : '" + mServerMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
Log.e("-------------- >>", "Close socket " );
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
It work correctly. This line in other code above to cause wrong.
mMessageListener.messageReceived(mServerMessage);
remove this line and your App work well. you can monitor your Log in android studio too.
You can use this code for your server in Golang.This is my server:
package main
import (
"bufio"
"flag"
"fmt"
"net"
"strconv"
)
var addr = flag.String("addr", "", "The address to listen to; default is \"\" (all interfaces).")
var port = flag.Int("port", 37533, "The port to listen on; default is 37533.")
func main() {
flag.Parse()
fmt.Println("Starting server...")
src := *addr + ":" + strconv.Itoa(*port)
listener, _ := net.Listen("tcp", src)
fmt.Printf("Listening on %s.\n", src)
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
fmt.Printf("Some connection error: %s\n", err)
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
remoteAddr := conn.RemoteAddr().String()
LocalAddr :=conn.LocalAddr().String()
fmt.Println("Client LocalAddr " + LocalAddr)
fmt.Println("Client connected from " + remoteAddr)
scanner := bufio.NewScanner(conn)
for {
ok := scanner.Scan()
if !ok {
break
}
handleMessage(scanner.Text(), conn)
}
fmt.Println("Client at " + remoteAddr + " disconnected.")
}
func handleMessage(message string, conn net.Conn) {
fmt.Println("> " + message)
if len(message) > 0 {
conn.Write([]byte("This is from Golang.\n"))
fmt.Println("----------> we send it....")
}
}