Android小项目————聊天室(网络编程篇)

Android小项目————聊天室(网络编程篇)

一.前言

这是关于聊天室的第二篇博客,内容主要是聊天室的核心篇章,即网络编程,主要是客户端和电脑端的服务器的代码。

二.客户端

  1. 步骤
    • 创建一个ClientThread类
  2. 数据的流动
    1. 当按动发送键时,将数据从EditText中提取出来,通过Handler和Message传递给发送子线程。
    2. 发送子线程将数据(ip+昵称+输入语句)通过Socket和输出流发送给电脑端的服务器
    3. 服务器将数据通过Socket发送给所有连接服务器的手机客户端
    4. 手机的接受子线程接受来自客户端的数据
    5. 接受子线程通过Handler和Message传递给主线程
    6. 主线程将数据拆分,并赋值给msg对象,添加到Msg集合中,并更新UI
  3. 代码
public class ClientThread implements Runnable {
    private Socket mSocket;
    private BufferedReader mBufferedReader = null;
    private OutputStream mOutputStream = null;
    private Handler mHandler;

    public Handler revHandler;

    public ClientThread(Handler handler) {
        mHandler = handler;
    }

    @Override
    public void run() {
        try {
            mSocket = new Socket("139.199.60.129", 9733);
            Log.d("xjj","connect success");
            //输入流管道到客户端
            mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
            mOutputStream = mSocket.getOutputStream();//输出流,客户端到管道

            //接受子线程
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    try {
                        String content = null;
                        //接收消息
                        while ((content = mBufferedReader.readLine()) != null) {
                            Log.d("xjj",content);
                            //将接受到的数据传递给msg对象,并标记
                            Message handleMsg = new Message();
                            handleMsg.what = 0;
                            handleMsg.obj = content;
                            mHandler.sendMessage(handleMsg);
                        }
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }.start();//启动

            //Looper类用来为一个线程开启一个消息循环。
            // 默认情况下android中新诞生的线程是没有开启消息循环的。
            // (主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
            Looper.prepare();
            //绑定发送线程的Handler
            revHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 1) {
                        try {
                            //发送消息
                            String content;
                            content =Name.IP+"#$#" + Name.name+"#$#" + msg.obj.toString() + "\r\n";
                            mOutputStream.write(content.getBytes("utf-8"));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            //Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
            Looper.loop();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("xjj","");
        }
    }

}

三.服务器端

  1. 步骤
    • 创建一个MyServer类(java编程,用eclipse)
    • 创建一个ServerThread类
  2. 数据的流动
    1. 循环接受来自各个客户端的Socket链接
    2. 为每个链接创建一个子线程,并启动
    3. 子线程中循环接受来自该客户端的数据,并将该数据发送给所有客户端。
  3. 代码
    MyServer类中
public class MyServer {
    public static ArrayList<Socket> mSocketList = new ArrayList<>() ;
    public static void main(String[] args){
        try {
            //创建服务器Socket
            ServerSocket ss = new ServerSocket(9733);
            while (true){
                //监听链接
                Socket s = ss.accept();
                //打印信息
                System.out.println("ip:"+ s.getInetAddress().getHostAddress() +"加入聊天室");
                //将s加入到线程池中
                mSocketList.add(s);
                //启动子线程
                new Thread(new ServerThread(s)).start();
            }
        }catch (IOException e){
            e.printStackTrace();
            System.out.println("服务器已崩溃");
            e.printStackTrace();

        }
    }
}

ServerThread类中

public class ServerThread implements Runnable {
    private Socket mSocket = null;
    private BufferedReader mBufferedReader = null;
    //构造方法
    public ServerThread(Socket s)throws IOException{
        mSocket = s;
        //输入管道到服务器
        mBufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream(), "utf-8"));
    }
    public void run(){
        try {
            String content = null;
            //循环接受服务器消息,如果没有接收到,说明该客户端下线,将其从线程池中删除
            while ((content = mBufferedReader.readLine())!=null){
                System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress()+":"+content);

                //循环向其他线程发送消息
                 for (Iterator<Socket> it = MyServer.mSocketList.iterator();it.hasNext();) {
                Socket s = it.next();
                try {
                    OutputStream os = s.getOutputStream();
                    os.write((content + "\n").getBytes("utf-8"));
                } catch (SocketException e) {
                    e.printStackTrace();
                    it.remove();
                    }
                }
            }
        }catch (IOException e){
            System.out.println("接收出错");
            try {
                mSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            MyServer.mSocketList.remove(mSocket);
            System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress() +"退出聊天室");
        }
    }
}

四.其他

  • 注意,在客户端中,创建Socket时我使用的ip为自己电脑的ip,如果需要正常运行,将代码中的ip换为自己电脑ip地址
  • 源码百度云链接
  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值