[postad]
2. Create a java class named “Constants”. The code for this class is below:
/** * Description * * @author Catalin Prata * Date: 2/12/13 */ public class Constants { public static final String CLOSED_CONNECTION = "kazy_closed_connection"; public static final String LOGIN_NAME = "kazy_login_name"; }
3. Create another class called “TcpServer”. The code for this class is below:
import javax.swing.*; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * The class extends the Thread class so we can receive and send messages at the same time * * @author Catalin Prata * Date: 2/12/13 */ public class TcpServer extends Thread { public static final int SERVERPORT = 4444; // while this is true the server will run private boolean running = false; // used to send messages private PrintWriter bufferSender; // callback used to notify new messages received private OnMessageReceived messageListener; private ServerSocket serverSocket; private Socket client; /** * Constructor of the class * * @param messageListener listens for the messages */ public TcpServer(OnMessageReceived messageListener) { this.messageListener = messageListener; } public static void main(String[] args) { //opens the window where the messages will be received and sent MainScreen frame = new MainScreen(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } /** * Close the server */ public void close() { running = false; if (bufferSender != null) { bufferSender.flush(); bufferSender.close(); bufferSender = null; } try { client.close(); serverSocket.close(); } catch (Exception e) { e.printStackTrace(); } System.out.println("S: Done."); serverSocket = null; client = null; } /** * Method to send the messages from server to client * * @param message the message sent by the server */ public void sendMessage(String message) { if (bufferSender != null && !bufferSender.checkError()) { bufferSender.println(message); bufferSender.flush(); } } public boolean hasCommand(String message) { if (message != null) { if (message.contains(Constants.CLOSED_CONNECTION)) { messageListener.messageReceived(message.replaceAll(Constants.CLOSED_CONNECTION, "") + " disconnected from room."); // close the server connection if we have this command and rebuild a new one close(); runServer(); return true; } else if (message.contains(Constants.LOGIN_NAME)) { messageListener.messageReceived(message.replaceAll(Constants.LOGIN_NAME, "") + " connected to room."); return true; } } return false; } /** * Builds a new server connection */ private void runServer() { running = true; try { System.out.println("S: Connecting..."); //create a server socket. A server socket waits for requests to come in over the network. serverSocket = new ServerSocket(SERVERPORT); //create client socket... the method accept() listens for a connection to be made to this socket and accepts it. client = serverSocket.accept(); System.out.println("S: Receiving..."); try { //sends the message to the client bufferSender = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true); //read the message received from client BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); //in this while we wait to receive messages from client (it's an infinite loop) //this while it's like a listener for messages while (running) { String message = null; try { message = in.readLine(); } catch (IOException e) { System.out.println("Error reading message: " + e.getMessage()); } if (hasCommand(message)) { continue; } if (message != null && messageListener != null) { //call the method messageReceived from ServerBoard class messageListener.messageReceived(message); } } } catch (Exception e) { System.out.println("S: Error"); e.printStackTrace(); } } catch (Exception e) { System.out.println("S: Error"); e.printStackTrace(); } } @Override public void run() { super.run(); runServer(); } //Declare the interface. The method messageReceived(String message) will must be implemented in the ServerBoard //class at on startServer button click public interface OnMessageReceived { public void messageReceived(String message); } }
4. Create a new java class class called “MainScreen”. The code for this class is below:
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Description * * @author Catalin Prata * Date: 2/12/13 */ public class MainScreen extends JFrame { private JTextArea messagesArea; private JButton sendButton; private JTextField message; private JButton startServer; private JButton stopServer; private TcpServer mServer; public MainScreen() { super("MainScreen"); JPanel panelFields = new JPanel(); panelFields.setLayout(new BoxLayout(panelFields, BoxLayout.X_AXIS)); JPanel panelFields2 = new JPanel(); panelFields2.setLayout(new BoxLayout(panelFields2, BoxLayout.X_AXIS)); //here we will have the text messages screen messagesArea = new JTextArea(); messagesArea.setColumns(30); messagesArea.setRows(10); messagesArea.setEditable(false); sendButton = new JButton("Send"); sendButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // get the message from the text view String messageText = message.getText(); // add message to the message area messagesArea.append("\n" + messageText); if (mServer != null) { // send the message to the client mServer.sendMessage(messageText); } // clear text message.setText(""); } }); startServer = new JButton("Start"); startServer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //creates the object OnMessageReceived asked by the TCPServer constructor mServer = new TcpServer(new TcpServer.OnMessageReceived() { @Override //this method declared in the interface from TCPServer class is implemented here //this method is actually a callback method, because it will run every time when it will be called from //TCPServer class (at while) public void messageReceived(String message) { messagesArea.append("\n " + message); } }); mServer.start(); // disable the start button and enable the stop one startServer.setEnabled(false); stopServer.setEnabled(true); } }); stopServer = new JButton("Stop"); stopServer.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (mServer != null) { mServer.close(); } // disable the stop button and enable the start one startServer.setEnabled(true); stopServer.setEnabled(false); } }); //the box where the user enters the text (EditText is called in Android) message = new JTextField(); message.setSize(200, 20); //add the buttons and the text fields to the panel panelFields.add(messagesArea); panelFields.add(startServer); panelFields.add(stopServer); panelFields2.add(message); panelFields2.add(sendButton); getContentPane().add(panelFields); getContentPane().add(panelFields2); getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); setSize(300, 170); setVisible(true); } }
TCP CLIENT IN ANDROID
1. Create an xml file under res – layout and name it “list_item”. The code for this xml file is below:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/list_item" android:gravity="center_vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/list_item_text_view" android:textSize="20sp" android:padding="10dp" android:layout_marginLeft="5dp"/> </LinearLayout>
2. In main.xml file (the one which is generated by IDE) put the following code:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:transcriptMode="alwaysScroll" android:cacheColorHint="#00000000" android:listSelector="@android:color/transparent"/> <LinearLayout android:id="@+id/footer" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="bottom"> <EditText android:inputType="textMultiLine|textNoSuggestions" android:layout_width="0dp" android:layout_height="40dp" android:id="@+id/editText" android:layout_weight="1"/> <!-- send button --> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/send_button" android:layout_gravity="center_vertical" android:text="send" /> </LinearLayout> </LinearLayout>
3. If you don’t have the “menu” directory under res – menu, you should create one and after it’s done, create a new xml file called “main_menu.xml” in the menu directory. Then put the following code:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/connect" android:title="Connect"/> <item android:id="@+id/disconnect" android:title="Disconnect" android:enabled="false"/> </menu>
4. Now you have to create the java classes (in the src directory). The first class that you have to create is the activity class. So create a new java class and name it ClientActivity. The code for the activity is below:
import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import java.util.ArrayList; public class ClientActivity extends Activity { private ListView mList; private ArrayList<String> arrayList; private ClientListAdapter mAdapter; private TcpClient mTcpClient; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); arrayList = new ArrayList<String>(); final EditText editText = (EditText) findViewById(R.id.editText); Button send = (Button) findViewById(R.id.send_button); //relate the listView from java to the one created in xml mList = (ListView) findViewById(R.id.list); mAdapter = new ClientListAdapter(this, arrayList); mList.setAdapter(mAdapter); send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String message = editText.getText().toString(); //add the text in the arrayList arrayList.add("c: " + message); //sends the message to the server if (mTcpClient != null) { mTcpClient.sendMessage(message); } //refresh the list mAdapter.notifyDataSetChanged(); editText.setText(""); } }); } @Override protected void onPause() { super.onPause(); // disconnect mTcpClient.stopClient(); mTcpClient = null; } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (mTcpClient != null) { // if the client is connected, enable the connect button and disable the disconnect one menu.getItem(1).setEnabled(true); menu.getItem(0).setEnabled(false); } else { // if the client is disconnected, enable the disconnect button and disable the connect one menu.getItem(1).setEnabled(false); menu.getItem(0).setEnabled(true); } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.connect: // connect to the server new ConnectTask().execute(""); return true; case R.id.disconnect: // disconnect mTcpClient.stopClient(); mTcpClient = null; // clear the data set arrayList.clear(); // notify the adapter that the data set has changed. mAdapter.notifyDataSetChanged(); return true; default: return super.onOptionsItemSelected(item); } } public class ConnectTask extends AsyncTask<String, String, TcpClient> { @Override protected TcpClient doInBackground(String... message) { //we create a TCPClient object and 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); //in the arrayList we add the messaged received from server arrayList.add(values[0]); // notify the adapter that the data set has changed. This means that new message received // from server was added to the list mAdapter.notifyDataSetChanged(); } } }
5. Now create another java class and call it ClientListAdapter. The code is just below:
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.ArrayList; /** * Description * * @author Catalin Prata * Date: 2/12/13 */ public class ClientListAdapter extends BaseAdapter { private ArrayList<String> mListItems; private LayoutInflater mLayoutInflater; public ClientListAdapter(Context context, ArrayList<String> arrayList){ mListItems = arrayList; //get the layout inflater mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { //getCount() represents how many items are in the list return mListItems.size(); } @Override //get the data of an item from a specific position //i represents the position of the item in the list public Object getItem(int i) { return null; } @Override //get the position id of the item from the list public long getItemId(int i) { return 0; } @Override public View getView(int position, View view, ViewGroup viewGroup) { //check to see if the reused view is null or not, if is not null then reuse it if (view == null) { view = mLayoutInflater.inflate(R.layout.list_item, null); } //get the string item from the position "position" from array list to put it on the TextView String stringItem = mListItems.get(position); if (stringItem != null) { TextView itemName = (TextView) view.findViewById(R.id.list_item_text_view); if (itemName != null) { //set the item name on the TextView itemName.setText(stringItem); } } //this method must return the view corresponding to the data at the specified position. return view; } }
6. Create another java class called TcpClient.
import android.util.Log; import java.io.*; import java.net.InetAddress; import java.net.Socket; /** * Description * * @author Catalin Prata * Date: 2/12/13 */ public class TcpClient { public static final String SERVER_IP = "192.168.0.100"; //your computer IP address public static final int SERVER_PORT = 4444; // 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(String message) { if (mBufferOut != null && !mBufferOut.checkError()) { mBufferOut.println(message); mBufferOut.flush(); } } /** * Close the connection and release the members */ public void stopClient() { // send mesage that we are closing the connection sendMessage(Constants.CLOSED_CONNECTION+"Kazy"); 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.e("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())); // send login name sendMessage(Constants.LOGIN_NAME+"Kazy"); //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.e("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 MyActivity //class at on asynckTask doInBackground public interface OnMessageReceived { public void messageReceived(String message); } }
7. Be sure that you AndroidManifest.xml file contains the Internet permission. The code for AndroidManifest is below:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="YOUR_PACKAGE" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8"/> <uses-permission android:name="android.permission.INTERNET" /> <application android:label="@string/app_name"> <activity android:name="ClientActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
If you need more exaplanations about TCP connection you can read the old TCP Connection Tutorial. There are more details.
I hope this tutorial helped you :D