Android应用socket即时通讯的实现

一、服务器

思路:

首先创建服务器,用一个死循环等候若干个客户端的连接。一旦有客户端连接,就把客户端添加到集合当中,并且启动一个新的线程来保持长连接,监控客户端发来的信息。一旦接收到有客户端发来的信息,就进行包装后遍历集合,把包装好的信息发送给每一个客户端。

代码如下:

/**
 * Tcp通信服务器
 * @author Devin Chen
 *
 */
public class CSServer {
	private static final int PORT = 8888;
	private List<Socket> mClientList = new ArrayList<Socket>();
	private ServerSocket server = null;
	private ExecutorService mExecutors = null; // 线程池对象

	public static void main(String[] args) {
		new CSServer();
	}

	/**
	 * 构造方法:任务是启动服务器,等待客户端连接
	 */
	public CSServer() {
		try {
			server = new ServerSocket(PORT);
			mExecutors = Executors.newCachedThreadPool(); // 创建线程池
			System.out.println("服务器已启动,等待客户端连接...");
			Socket client = null;
			/*
			 * 用死循环等待多个客户端的连接,连接一个就启动一个线程进行管理
			 */
			while (true) {
				client = server.accept();
				// 把客户端放入集合中
				mClientList.add(client);
				mExecutors.execute(new Service(client)); // 启动一个线程,用以守候从客户端发来的消息
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	class Service implements Runnable {
		private Socket socket;
		private BufferedReader in = null;
		private String message = "";

		public Service(Socket socket) {
			this.socket = socket;
			try {
				in = new BufferedReader(new InputStreamReader(
						socket.getInputStream()));// 获得输入流对象
				// 客户端只要一连到服务器,便发送连接成功的信息
				message = "服务器地址:" + this.socket.getInetAddress();
				this.sendMessage(message);
				message = "当前连接总数:" + mClientList.size();
				this.sendMessage(message);
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		@Override
		public void run() {
			try {
				while (true) {
					if ((message = in.readLine()) != null) {
						// 当客户端发送的信息为:exit时,关闭连接
						if (message.equals("exit")) {
							closeSocket();
							break;
						} else {
							// 接收客户端发过来的信息message,然后转发给客户端。
							message = socket.getInetAddress() + ":" + message;
							this.sendMessage(message);
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		/**
		 * 关闭客户端
		 * 
		 * @throws IOException
		 */
		public void closeSocket() throws IOException {
			mClientList.remove(socket);
			in.close();
			message = "主机:" + socket.getInetAddress() + "关闭连接\n目前在线:"
					+ mClientList.size();
			socket.close();
			this.sendMessage(message);
		}

		/**
		 * 将接收的消息转发给每一个客户端
		 * 
		 * @param msg
		 */

		public void sendMessage(String msg) {
			System.out.println(msg);// 先在控制台输出
			int count = mClientList.size();
			// 遍历客户端集合
			for (int i = 0; i < count; i++) {
				Socket mSocket = mClientList.get(i);
				PrintWriter out = null;
				try {
					out = new PrintWriter(new BufferedWriter(
							new OutputStreamWriter(mSocket.getOutputStream())),
							true);// 创建输出流对象
					out.println(msg);// 转发
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

二、Android客户端

思路:

设置权限。

首先开辟线程,在线程中连接服务器,并获取输入流和输出流,并用一个死循环接收来自服务器的消息,输入流收到消息进行处理,用handler通知给UI线程更新文本框。

编辑框填好消息,直接点击发送。用获得的输出流发送消息。

代码:

/**
 * Android Tcp即时通讯客户端
 */
public class MainActivity extends Activity implements Runnable{
    private TextView tv_msg = null;
    private EditText ed_msg = null;
    private Button btn_send = null;
    private static final String HOST = "192.168.0.100";//服务器地址
    private static final int PORT = 8888;//连接端口号
    private Socket socket = null;
    private BufferedReader in = null;
    private PrintWriter out = null;

    //接收线程发送过来信息,并用TextView追加显示
    public Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tv_msg.append((CharSequence) msg.obj);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv_msg = (TextView) findViewById(R.id.txt_1);
        ed_msg = (EditText) findViewById(R.id.et_talk);
        btn_send = (Button) findViewById(R.id.btn_send);

        btn_send.setOnClickListener(new Button.OnClickListener() {

            @Override
            public void onClick(View v) {
                String msg = ed_msg.getText().toString();
                if (socket.isConnected()) {//如果服务器连接
                    if (!socket.isOutputShutdown()) {//如果输出流没有断开
                        out.println(msg);//点击按钮发送消息
                        ed_msg.setText("");//清空编辑框
                    }
                }
            }
        });
        //启动线程,连接服务器,并用死循环守候,接收服务器发送过来的数据
        new Thread(this).start();
    }

    /**
     * 连接服务器
     */
    private void connection() {
        try {
            socket = new Socket(HOST, PORT);//连接服务器
            in = new BufferedReader(new InputStreamReader(socket
                    .getInputStream()));//接收消息的流对象
            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                    socket.getOutputStream())), true);//发送消息的流对象
        } catch (IOException ex) {
            ex.printStackTrace();
            ShowDialog("连接服务器失败:" + ex.getMessage());
        }
    }

    /**
     * 如果连接出现异常,弹出AlertDialog!
     */
    public void ShowDialog(String msg) {
        new AlertDialog.Builder(this).setTitle("通知").setMessage(msg)
                .setPositiveButton("ok", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                }).show();
    }

    /**
     * 读取服务器发来的信息,并通过Handler发给UI线程
     */
    public void run() {
        connection();// 连接到服务器
        try {
            while (true) {//死循环守护,监控服务器发来的消息
                if (!socket.isClosed()) {//如果服务器没有关闭
                    if (socket.isConnected()) {//连接正常
                        if (!socket.isInputShutdown()) {//如果输入流没有断开
                            String getLine;
                            if ((getLine = in.readLine()) != null) {//读取接收的信息
                                getLine += "\n";
                                Message message=new Message();
                                message.obj=getLine;
                                mHandler.sendMessage(message);//通知UI更新
                            } else {

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

}


运行效果:




如果要扩展优化成一个有模有样的即时通讯工具。考虑发发送的消息用json进行格式化,包含用户昵称和图片地址等等,服务器收到后解析,在添加上时间等进行重新包装。客户端收到消息,同样进行解析,装载到美化好的listview当中。

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值