Android应用socket即时通讯的实现

原创 2016年12月21日 15:51:40

一、服务器

思路:

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

代码如下:

/**
 * 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当中。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

socket即时通信

写这些程序不要太过于着急

Android即时通讯--仿QQ即时聊天:(一)初识Socket

1、即时通讯简介 即时通讯(Instant Messaging,简称IM)是一个终端服务,允许两人或者多人通过网络即时传递文字讯息、档案、语音等。简单的概括就是发送消息时,只要对方在线,就能立即接收到...

见证Android消息推送时刻--笔记---Socket即时通讯机制

前几天在"慕课网"看到了郭霖大神的视频----点击打开链接  "见证Android消息推送时刻",由于自己这段时间也在做即时通讯,作为初级码农,顿时感到与大神如此的接近,所以决定追随大神的步伐...

即时通讯实现方式(采用openfire和asmack方式)

XMPP协议简介 XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提...

android即时通讯研究(逐渐完善中,还很简单)

在android实现了移动通话的项目,使用tcp传送数据。主要是为了学习android基础知识,所以做的比较简单,语音通话的降噪和回音消除都没有做, 有兴趣的朋友可以继续做下去,建议用rtp实现语音传...

【Android即时通讯】Android 高仿微信的即时聊天DEMO

很久没写博客,在此写一篇高仿微信的即时聊天的DEMO,大家一起学习下。 这里微信界面仿照的是微信5.2版本,个人偏爱这版,并且网上也有较多的高仿界面可以学习,本人以极光IM做辅助,实现了即时聊天。 ...

Android即时通讯--仿QQ即时聊天:(五)聊天模块

1、复杂ListView的展示 聊天模块其实就是一个复杂的ListView,在数据适配器中,从application中获取到当前登录的用户,与聊天消息中的from参数进行比较,如果两者相同则说明是自己...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)