Android 聊天室的开发

刚开始接触Android的网络通信开发。
目前自己写了一个聊天室的小程序,记录一下。

本程序包括:

1.服务器:由java开发
2.客户端:由Android开发

首先贴上演示效果。先开启服务端程序以后,再打开客户端。
Android 聊天室的开发_第1张图片

服务器的console起到接受并且转发的目的:

Android 聊天室的开发_第2张图片

服务端代码:

package com.ustclin.talk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {
    //private static final String IP_ADDRESS = "192.168.0.200";
    private static final int PORT = 18888;
    private static int num = 0;

    public static ArrayList socketList = new ArrayList();
    /**
     * @param args
     */
    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        System.out.println("ServerSocket Begin........");
        try {
            serverSocket = new ServerSocket(PORT);
            // 使用循环方式一直等待客户端的连接
            while (true) {
                num++;
                Socket accept = serverSocket.accept();
                socketList.add(accept);
                System.out.println("arrayList num = "+socketList.size());
                // 启动一个新的线程,接管与当前客户端的交互会话
                new Thread(new ServerThread(accept , "Client "+num ), "Client " + num).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                serverSocket.close();
                System.out.println("---->  serverSocket closed.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * @author JCC 服务器处理客户端会话的线程
 */
class ServerThread implements Runnable {

    Socket socket = null;
    String clientName = null;
    public ServerThread(Socket socket , String clientName) {
        System.out.println("Create a new ServerThread...");
        this.socket = socket;
        this.clientName = clientName;
    }

    @Override
    public void run() {
        try {
            // 接收客户端消息
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));

            while (true) {
                String message = null;
                if (!socket.isClosed()) {
                    try {
                        message = in.readLine();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if(null == message){
                        // the socket is null , means that the client is disconnect
                        Server.socketList.remove(socket);
                        break;
                    }
                    System.out.println("server read Line from "+ clientName + " success! message = " + message);
                    for(Socket ss : Server.socketList){
                        // 发送消息,向客户端
                        PrintWriter out = new PrintWriter(new BufferedWriter(
                                new OutputStreamWriter(ss.getOutputStream())), true);
                        out.println(this.clientName +": "+ message);
                        System.out.println("Thread " + clientName + " socket send out");
                    }
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        } finally {
                System.out.println("out of while");
        }
    }

}

interface Constant {

    public static final String SERVER_IP = "192.168.0.200";
    public static final int PORT = 19999;
}

客户端主程序:

package com.ustc.linkun.chat;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;


public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private static final String TAG = "ConnectToServer";
    private static final String CONNECTED = "connected ! ";
    private static final String CONNECTINGSERVER = "connecting ...";

    private TextView tvForIpAddress;
    private TextView tvForPort;
    private EditText mIpAddress;
    private EditText mPort;
    private Button mConnect;
    private TextView mServerMsg;
    private EditText editText;
    private Button button1;

    private static final int SEND_DATA = 0;
    private static final int GET_DATA_FROM_SERVER = 1;
    private static final int CONNECT_TO_SERVER = 2;
    private static final int CONNECTING = 3;
    private MyHandler myHandler;
    private Socket socket = null;
    private Context mContext;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mContext = this;
        tvForIpAddress = (TextView) findViewById(R.id.tvForIpAddress);
        tvForPort = (TextView) findViewById(R.id.tvForPort);
        mIpAddress = (EditText)findViewById(R.id.ipAddress);
        mPort = (EditText) findViewById(R.id.port);
        mConnect = (Button) findViewById(R.id.connect);
        editText = (EditText) findViewById(R.id.editText1);
        mServerMsg = (TextView) findViewById(R.id.serverMsg);
        //mServerMsg.setEnabled(false);
        button1 = (Button) findViewById(R.id.button1);
        myHandler = new MyHandler();

        mConnect.setOnClickListener(this);
        button1.setOnClickListener(this);

    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){

            // connect server
            case R.id.connect:
                // connecting , avoid multi button click which can result sending multi-connect request
                Runnable r0 = new Runnable() {
                    @Override
                    public void run() {
                        Message msg = myHandler.obtainMessage();
                        msg.what = CONNECTING;
                        myHandler.sendMessage(msg);
                    }
                };
                new Thread(r0).start();
                // use for connection
                Runnable r1 = new Runnable() {
                    @Override
                    public void run() {
                        initSocket();
                        ClientThread ct = new ClientThread(socket , "Client");
                        new Thread(ct).start();
                        //connectToServer(mIpAddress.getText().toString(), Integer.parseInt(mPort.getText().toString()));
                        if(socket.isConnected()){
                            Message msg = myHandler.obtainMessage();
                            msg.what = CONNECT_TO_SERVER;
                            myHandler.sendMessage(msg);
                        }
                    }
                };
                new Thread(r1).start();
                break;
            // send data
            case R.id.button1:
                Runnable r2 = new Runnable() {
                    @Override
                    public void run() {
                        Message msg = myHandler.obtainMessage();
                        String str = editText.getText().toString();
                        System.out.println(">>>>editText: " +str);
                        Bundle bundle = new Bundle();
                        bundle.putString("content", str);
                        msg.what = SEND_DATA;
                        msg.setData(bundle);
                        myHandler.sendMessage(msg);
                    }
                };
                new Thread(r2).start();
                break;
            default:
                break;
        }
    }

    private void initSocket() {
        try{
            //socket = new Socket(ipAddress , port);
            socket = new Socket(mIpAddress.getText().toString(),Integer.parseInt(mPort.getText().toString()));
            socket.setKeepAlive(true);
            socket.setSoTimeout(10 * 60 * 1000);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    //private class

    private class MyHandler extends Handler {
        public MyHandler() {
        }

        public MyHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case SEND_DATA:
                    //Bundle bundle = new Bundle();

                    final String str = (String)msg.getData().get("content");
                    System.out.println(">>>>>content : " + str);
                    if(str.equals("")){
                        Toast.makeText(mContext,"不能发送空内容!",Toast.LENGTH_SHORT).show();
                    }
                    else {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                sendData(str);
                            }
                        }).start();
                        editText.setText("");
                        //mServerMsg.append(str);
                    }
                    break;
                case GET_DATA_FROM_SERVER:
                    String str1 = (String) msg.getData().get("content");
                    System.out.println("myHandler get str = " + str1);
                    mServerMsg.append("\n"+str1);
                case CONNECT_TO_SERVER:
                    mIpAddress.setEnabled(false);
                    mPort.setEnabled(false);
                    mConnect.setText(CONNECTED);
                    tvForIpAddress.setVisibility(View.GONE);
                    tvForPort.setVisibility(View.GONE);
                    mIpAddress.setVisibility(View.GONE);
                    mPort.setVisibility(View.GONE);
                    mConnect.setVisibility(View.GONE);
                    //mServerMsg.setText("The Server is connected!");
                case CONNECTING:
                    mConnect.setText(CONNECTINGSERVER);
                    mConnect.setEnabled(false);
                default:
                    break;
            }

        }
    }


    // send data
    private void sendData(String content) {
        // server is on
        try {
            //String content = editText.getText().toString();
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter
                    (socket.getOutputStream())), true);
            //发送数据
            out.println(content);
            System.out.println(">>>>>send out SUCCESSFUL!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //
    private void send_CONNECTION_CLOSE_DATA(){
        try {
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter
                    (socket.getOutputStream())), true);
            //发送数据
            out.println("closing-connection");
            System.out.println("closing-connection");
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    // close the connection to the server
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            if (null != socket) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        send_CONNECTION_CLOSE_DATA();
                    }
                });
                socket.close();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class ClientThread implements Runnable{
        private Socket socket = null;
        private String name;
        public ClientThread(Socket socket , String threadName){
            this.socket = socket;
            this.name = threadName;
        }
        @Override
        public void run() {

            try {
                // 接收客户端消息
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                while (true) {
                    String message = null;
                    try {
                        if (!socket.isClosed()) {
                            message = in.readLine();
                            System.out.println("Server:" + message);
                            Message msg = myHandler.obtainMessage();
                            Bundle b = new Bundle();
                            b.putString("content" , message);
                            msg.setData(b);
                            msg.what = GET_DATA_FROM_SERVER;
                            myHandler.sendMessage(msg);
                            System.out.println("read Line success! message = " + message);
                        }
                        Thread.sleep(1000);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //in = socket.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }



}

客户端界面布局:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tvForIpAddress"
        android:text="IP Address: " />

    <EditText
        android:id="@+id/ipAddress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="input the ip address here"
        android:text="192.168.0.200">
    EditText>
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tvForPort"
        android:text="port: " />

    <EditText
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="input the port number here"
        android:text="18888">
    EditText>

    <Button
        android:id="@+id/connect"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="connect">
    Button>


    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="----Talk----" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/serverMsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="This is for TALK History zone" />

    RelativeLayout>

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="">
    EditText>


    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="send">
    Button>

LinearLayout>
  1. 先运行Server.java , 保证服务器在客户端之前开启

  2. 客户端是用Android Studio开发的,可以直接导入。如果你的IDE是ADT,
    则可以选择性得添加里边的MainActivity.java 和 main.xml布局文件。需要
    注意的是,AndroidManifest.xml文件需要添加访问INTERNET的权限

  3. 运行多个客户端,配置好服务器的IP地址后,即可进行聊天。

具体的源码大家可以去看看:基于socket的Android聊天程序

你可能感兴趣的:(Android,从零开始)