Android聊天室

来源:互联网 发布:wtaps15aw军裤数据 编辑:程序博客网 时间:2024/06/09 21:20

背景

最新在研究网络编程,感觉好好玩,然后玩得兴起就想做个聊天室来玩玩。这个聊天室叫 ChatRoom ,是一个基于 TCP 通信的聊天室,并且用到了一些 Material Design 的控件,之前一直都在赶项目都没时间学习 Material Design(其实不是没时间,是有些事情很烦,所以耽搁了),工作室的昭哥老说我,你基础工不扎实,嘿嘿。

基础

  • 我们来围观李俊师兄写的 TCP:java 网络编程 TCP协议

  • 李俊师兄写的很详细,我也来班门弄斧下(^0^):

TCP 是一种可靠、必须连接才能通信的协议。因为需要连接才能通信,所以 TCP 通信严格区分客户端和服务器端,只有客户端连接了服务器端才能实现通信,服务器端不能连接客户端并且需要事先启动,等待客户端的请求。

附图

ChatRoom

好了,扯了辣么多,我们来看看 ChatRoom 是怎么实现的吧!先看看效果:

服务器端

/** * Created by kn on 2016/5/24. * * 聊天室主线程服务 */public class MyServerSocket {    public static void main(String args[]){        new ServerListener().start();    }}/** * Created by kn on 2016/5/24. * * 聊天监听线程类 */public class ServerListener extends Thread {    @Override    public void run() {        try {            //端口号port:1~65535            ServerSocket serverSocket = new ServerSocket(30000);            while(true){                //该方法会阻塞当前线程                Socket socket = serverSocket.accept();                //建立连接                System.out.println("有客户端链接到本地的30000端口");                //将socket传递给新的线程                ChatSocket chatSocket = new ChatSocket(socket);                chatSocket.start();                ChatManager.getInstance().add(chatSocket);            }        } catch (IOException e) {            e.printStackTrace();        }    }}/** * Created by kn on 2016/5/24. * * 聊天线程类 */public class ChatSocket extends Thread {    Socket socket;    public ChatSocket(Socket socket) {        this.socket = socket;    }    @Override    public void run() {        try {            BufferedReader br = new BufferedReader(                    new InputStreamReader(socket.getInputStream(), "UTF-8"));            String line = null;            while ((line = br.readLine()) != null) {                ChatManager.getInstance().publish(this, line);            }            br.close();        } catch (IOException e) {            e.printStackTrace();        }    }    /**    * 输出服务器返回的信息    * @param message    */    public void showMessage(String message) {        try {            socket.getOutputStream().write((message + "\n").getBytes("UTF-8"));        } catch (IOException e) {            e.printStackTrace();        }    }    /**    * 判断socket是否关闭    * @return    */      public boolean isSocketClosed(){        return socket.isClosed();    }}/** * Created by kn on 2016/5/24. * * 聊天室线程管理类 */public class ChatManager {    private static ChatManager instance = new ChatManager();    //聊天线程列表    Vector<ChatSocket> vector = new Vector<>();    private ChatManager() {    }    /**     * 单例模式     * @return     */    public static ChatManager getInstance() {        if (instance == null) {            synchronized (ChatManager.class) {                if (instance == null) {                    instance = new ChatManager();                }            }        }        return instance;    }    /**     * 添加聊天线程     *     * @param chatSocket     */    public void add(ChatSocket chatSocket) {        vector.add(chatSocket);    }    /**     * 向聊天室的其他线程发布消息     * @param chatSocket     * @param message     */    public void publish(ChatSocket chatSocket, String message) {        //遍历线程列表        for (int i = 0; i < vector.size(); i++) {            ChatSocket mChatSocket = vector.get(i);            //判断是否是己线程            if (!chatSocket.equals(mChatSocket)) {                //判断该线程是否已经断开服务器的连接                if (mChatSocket.isSocketClosed()) {                    vector.remove(i);                } else {                    mChatSocket.showMessage(message);                }            }        }    }}

写完以上代码,服务器端基本上完成了,其实现在,我们就可以玩聊天室了。打开多个 cmd 并输入 telnet localhost 30000 就可以连接服务器,然后你就可以在黑框下聊天了。

客户端

主界面,输入服务器的 IP 和聊天中显示的名字

public class MainActivity extends AppCompatActivity {    MaterialEditText metName;//聊天的昵称    MaterialEditText metIP;//聊天室的IP    ImageView ivAvatar;//聊天的头像    ButtonFlat btnEnter;//进入聊天按钮    ProgressBar progressBar;//进度条    FrameLayout flProgressBar;    public static Socket socket = null;    final static int SUCCESS = 0x01;//进入聊天室成功    final static int FAILURE = 0x02;//进入聊天室失败    final static int TIMEOUT = 0x03;//连接超时    final static int UN_KNOWN_HOST = 0x04;//未知主机    private BufferedWriter writer;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    private void initView() {        metName = (MaterialEditText) findViewById(R.id.met_name);        metIP = (MaterialEditText) findViewById(R.id.met_ip);        ivAvatar = (ImageView) findViewById(R.id.iv_avatar);        btnEnter = (ButtonFlat) findViewById(R.id.btn_enter);        progressBar = (ProgressBar) findViewById(R.id.progress);        flProgressBar = (FrameLayout) findViewById(R.id.fl_progress);        metName.setText("kntryer");        metIP.setText("192.168.1.101");        btnEnter.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                enterChatRoom();            }        });    }    private void enterChatRoom() {        //获取ip        final String ipString = metIP.getText().toString().trim();        new Thread(new Runnable() {            @Override            public void run() {                try {                    socket = new Socket();                    socket.connect(new InetSocketAddress(ipString, 30000), 5000);                    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));                    handler.sendEmptyMessage(SUCCESS);                } catch (SocketTimeoutException e) {                    //连接超时 在UI界面显示消息                    handler.sendEmptyMessage(TIMEOUT);                    e.printStackTrace();                } catch (UnknownHostException e) {                    handler.sendEmptyMessage(UN_KNOWN_HOST);                    e.printStackTrace();                } catch (IOException e) {                    handler.sendEmptyMessage(FAILURE);                    e.printStackTrace();                }            }        }).start();    }    Handler handler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message msg) {            switch (msg.what) {                case SUCCESS:                    String name = metName.getText().toString();                    try {                        if (writer != null) {                            writer.write("system," + name + " enter ChatRoom\n");                            writer.flush();                        }                    } catch (IOException e) {                        e.printStackTrace();                    }                    Intent intent = new Intent(MainActivity.this, ChatActivity.class);                    intent.putExtra("name", name);                    startActivity(intent);                    break;                case FAILURE:                    showIsOpenWifi("Please check whether the network is open or not.");                    break;                case TIMEOUT:                    showIsOpenWifi("SocketTimeoutException");                    break;                case UN_KNOWN_HOST:                    showIsOpenWifi("UnknownHostException");                    break;            }            return false;        }    });    private void showIsOpenWifi(String message) {        new SnackBar(this, message, "Yes", new View.OnClickListener() {            @Override            public void onClick(View v) {                //跳到WiFi,这个还没做            }        }).show();    }}

聊天界面

/** * Created by kn on 2016/5/24. */public class ChatActivity extends AppCompatActivity {    ButtonFlat btnSent;//发送消息    MaterialEditText metMsg;//消息    ListView lvMsg;//显示消息    ArrayList<ChatMessage> msgList = new ArrayList<>();//消息列表    MessageAdapter adapter;    Socket socket;    String name;//聊天昵称    BufferedReader reader;//读取服务器返回的数据    BufferedWriter writer;//向服务器发送数据    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_chat);        initView();    }    private void initView() {        name = getIntent().getStringExtra("name");        socket = MainActivity.socket;        btnSent = (ButtonFlat) findViewById(R.id.btn_sent);        metMsg = (MaterialEditText) findViewById(R.id.met_msg);        lvMsg = (ListView) findViewById(R.id.lv_msg);        adapter = new MessageAdapter(this,msgList);        lvMsg.setAdapter(adapter);        //开启一个新的线程监听聊天室,并获取聊天室的消息        getMessage();        btnSent.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ChatMessage chatMessage = new ChatMessage();                chatMessage.setType(2);                chatMessage.setName(name);                chatMessage.setMessage(metMsg.getText().toString());                msgList.add(chatMessage);                adapter.notifyDataSetChanged();                String message = name + "," + metMsg.getText().toString();                metMsg.setText("");                setMessage(message);            }        });    }    /**     * 发送消息     * @param message     */    private void setMessage(String message) {        try {            if (writer != null) {                writer.write(message + "\n");                writer.flush();            } else {                Toast.makeText(ChatActivity.this, "你已经离开 YY 聊天室!", Toast.LENGTH_LONG).show();            }        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 获取聊天室的消息     */    private void getMessage() {        new Thread(new Runnable() {            @Override            public void run() {                try {                    writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));                    reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));                    String line = null;                    while ((line = reader.readLine()) != null) {                        ChatMessage chatMessage = new ChatMessage();                        String[] temp = line.split(",");                        System.out.print(temp[0]);                        if(temp[0].equals("system")){//如果temp[0]=system说明是系统消息                            chatMessage.setType(0);                            chatMessage.setMessage(temp[1]);                        }else{                            chatMessage.setType(1);                            chatMessage.setName(temp[0]);                            chatMessage.setMessage(temp[1]);                        }                        msgList.add(chatMessage);                        handler.sendEmptyMessage(0x00);                    }                    reader.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }).start();    }    Handler handler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message msg) {            adapter.notifyDataSetChanged();            return false;        }    });}

如何查看服务器 IP 呢?

打开 cmd ,输入 ipconfig ,就可以看到本机的 IP 设置,在无线局域网适配 wifi 这里的 IPv4地址 就是服务器的 IP 了。

模拟器可以连上服务器,手机却连不上怎么办?

网上说是手机是外网,访问不了内网的问题,手机和电脑连同一个 wifi 就行了。

0 0