Android Socket多个客户端即时通信聊天
Frank Kong 人气:0聊天室的原理是这样的,一个客户端与服务器建立通讯成功,即客户端socket连接到服务器的ServerSocket之后,服务器端程序将对应的socket加入到容器中,为每一个socket创建一条线程,服务器端读到客户端发来的信息之后,遍历该容器,给容器中的每个socket发送一次,就完成了所有客户端广播。当客户端离开时,向服务器发送一条断开连接信息,从服务器端断开socket,将容器中的对应socket移除掉。
图:
服务器端Server,java:
accept通信后,为该socket建立一条线程,开启循环读写操作
/** * Created by konghao on 2017/11/8. */ public class Server { static List<Socket> cons = new LinkedList<Socket>(); 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<Msg> msgs = new ArrayList<Msg>();//存储消息容器 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(); } }
服务器端收到的信息:
另附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(); } } } }
加载全部内容