Android学习之Socket多个客户端即时通信聊天

聊天室的原理是这样的,一个客户端与服务器建立通讯成功,即客户端socket连接到服务器的ServerSocket之后,服务器端程序将对应的socket加入到容器中,为每一个socket创建一条线程,服务器端读到客户端发来的信息之后,遍历该容器,给容器中的每个socket发送一次,就完成了所有客户端广播。当客户端离开时,向服务器发送一条断开连接信息,从服务器端断开socket,将容器中的对应socket移除掉。

图:

Android学习之Socket多个客户端即时通信聊天_第1张图片

服务器端Server,java:

accept通信后,为该socket建立一条线程,开启循环读写操作

/**
 * Created by konghao on 2017/11/8.
 */
public class Server {

    static List cons = new LinkedList();
    private static Socket socket = null;

    public static class ServerThread extends Thread{
        private Socket s;

        public ServerThread(Socket socket){
            this.s = socket;
            cons.add(s);
        }

        @Override
        public void run(){
            System.out.print("新用户加入\n");
            System.out.print("当前在线数量:"+cons.size()+"\n");
            try{
                while(true){

                    BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    String mess;// = br.readLine();
                    //保存信息
                    if((mess=br.readLine())!=null) {
                        if(mess.equals("-用户退出-")){
                            s.close();
                        }
                        System.out.print("客户端:" + mess + "\n");
                        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                        //为了证明是服务器返回的数据,我对mess修改在发送到客户端
                        //这里修改广播到所有客户端
                        for (Socket so : cons){
                            BufferedWriter buffw = new BufferedWriter(new OutputStreamWriter(so.getOutputStream()));
                            String str = "服务器>>"+mess+"\n";
                            buffw.write(str);
                            buffw.flush();
                        }
                        //
                        //单客户端通信
                        /*
                        String str = "服务器>>"+mess+"\n";
                        bw.write(str);
                        bw.flush();
                        */
                    }
                }
            }catch (IOException e){
                System.out.print("用户退出!\n");
                cons.remove(s);
                e.printStackTrace();
                this.interrupt();
                //e.printStackTrace();
            }catch (NullPointerException e) {
                System.out.print("NullPointerException");
            }finally {
                try {
                    s.close();
                }catch (IOException e){
                    System.out.print("IOException-2");
                    e.printStackTrace();
                }
            }
        }

    }

    public static void main(String[] args) throws IOException {

        ServerSocket ss = new ServerSocket(30001);
        while(true){
            Socket s = ss.accept();
            new Thread(new ServerThread(s)).start();
        }
    }
}

安卓客户端:

进入活动时候创建一条线程,完成socket连接,和循环监听接受服务器发来的消息。当发送按钮按下后,向服务器发送消息。退出活动时候,向服务器发送结束通信信息,服务器收到后关闭socket。

ChatRoomActivity.java

public class ChatRoomActivity extends Activity implements View.OnClickListener{
    private Socket socket = null;
    private EditText edit;
    private Button send,disconnect;
    private RecyclerView msg_recyclerView;
    private MsgAdapter adapter;
    private List msgs = new ArrayList();//存储消息容器
    private String name = "";
    private static final int UPDATE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat_room);

        Intent intent = getIntent();
        name = intent.getStringExtra("name");
        Log.d("孔昊",name);

        //从服务器读数进程
        new Thread(new Runnable() {
            private String msg_get="";
            @Override
            public void run() {
                try {
                    socket = new Socket();
                    socket.connect(new InetSocketAddress("公网IP", 30001), 5000);

                    //input
                    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                    while((msg_get=br.readLine())!=null){
                        Message message = new Message();
                        Bundle bundle = new Bundle();
                        Log.d("孔昊",msg_get);
                        bundle.putString("msg",msg_get);
                        message.setData(bundle);
                        message.what = UPDATE;
                        handler.sendMessage(message);
                    }

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

        edit = (EditText) findViewById(R.id.edit);
        send = (Button) findViewById(R.id.send);
        send.setOnClickListener(this);
        disconnect = (Button) findViewById(R.id.disconnect);
        disconnect.setOnClickListener(this);

        msg_recyclerView = (RecyclerView) findViewById(R.id.msg_view);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        msg_recyclerView.setLayoutManager(linearLayoutManager);
        adapter = new MsgAdapter(msgs);
        msg_recyclerView.setAdapter(adapter);
    }

    Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            switch (msg.what){
                //更新消息列表
                case UPDATE:{
                    Bundle bundle = msg.getData();
                    String msg_get = bundle.getString("msg");
                    Msg msg1 = new Msg(msg_get);
                    msgs.add(msg1);
                    adapter.notifyDataSetChanged();
                }
                break;
            }
        }
    };

    //向服务器发数据进程
    class SocketThread extends Thread{
        private String msg;
        //Socket socket;

        public SocketThread(String m){
            msg = m;
        }

        @Override
        public void run(){
            try {

                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                bw.write(msg);
                bw.newLine();
                bw.flush();

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

    }

    @Override
    public void onClick(View v) {
        switch(v.getId()){
            case R.id.send:{
                String s = name +":"+ edit.getText().toString();
                edit.setText("");
                new Thread(new SocketThread(s)).start();
            }
            break;
            case R.id.disconnect:{
                try {
                    //socket.shutdownOutput();
                    //socket.shutdownInput();
                    //socket.close();
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                    bw.write("-用户退出-");
                    bw.newLine();
                    bw.flush();
                    //发送message,更新UI
                    Message message = new Message();
                    Bundle bundle = new Bundle();
                    bundle.putString("msg","你已经退出聊天!");
                    message.setData(bundle);
                    message.what = UPDATE;
                    handler.sendMessage(message);

                }catch (IOException e){
                    //Log.d("孔昊","断开连接");
                    e.printStackTrace();
                }
            }
            break;
        }
    }

    //back事件

    @Override
    public void onBackPressed(){
        try {
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("-用户退出-");
            bw.newLine();
            bw.flush();

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

}
Android学习之Socket多个客户端即时通信聊天_第2张图片

Android学习之Socket多个客户端即时通信聊天_第3张图片


服务器端收到的信息:

Android学习之Socket多个客户端即时通信聊天_第4张图片

另附java控制台作为客户端代码:

/**
 * Created by konghao on 2017/11/8.
 */
public class Client {
    private static String name;
    private static Socket socket;
    public static void main(String[] args) {
        try {
            name = "孔昊";
            Socket s = new Socket("112.74.92.125",30001);
            socket = s;
            System.out.println("客户端IP:"+s.getLocalAddress()+"端口"+s.getPort());
            //构建IO流
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

            //建立键盘输入:
            Scanner scanner = new Scanner(System.in);
            while(true){
                System.out.println("请输入发送消息内容:");
                bw.write(name+":"+scanner.nextLine()+"\n");
                bw.newLine();
                bw.flush();
                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                //读取服务器返回的消息数据
                System.out.println(s.getInetAddress().getLocalHost()+":"+s.getPort()+">>"+br.readLine());
            }

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                socket.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }

    }
}



你可能感兴趣的:(Android)