前提概要
笔者很久之前其实就已经学习过了socket,当然也是用socket做过了聊天室,但是觉得此知识点比较一般,并无特别难的技术点,于是也并未深究。
然而近期一个项目中对socket的使用却让笔者感觉socket强大无比,可以实现诸多功能。
个人Socket体验
项目主要有关智能家居,需要实现多台手机同时对灯进行 *** 作(开或者关),主要需要实现以下几点:
1、进入界面时获取所有灯的状态。
2、一台手机改变了灯的状态,其他的手机上可以有所显示。
3、硬件上改变了灯的状态(手动开关灯),所有手机上要有所显示。
此功能如果使用http读取的方式实现就不太合适了。一方面客户端与服务器读取文件的同步性难以保证,即使保证了,也需要浪费大量性能;另一方面,类似笔者的这种项目功能服务器和客户端交互比较频繁,对“即时性”要求也比较高,用http不仅性能消耗太大,而且难以保证“即时性”。
但是使用Socket就很容易实现了,主要逻辑如下:
1、每次进入界面与服务器建立Socket连接,并得到此时灯的状态
2、每次需要对灯进行 *** 作的时候建立一个线程把灯的状态传递给服务器,服务器接收到之后,把该状态传递给每一个此时与服务器建立连接的客户端。
此次体验也是让笔者想起了学长之前做的一道笔试题,题目大概如下:
将淘宝网页和手机版同时打开账户,手机停留在购物车界面,此时网页上将某一物品加入购物车,如何设计才能让手机自动刷新购物车。
如果使用socket,相信是一个不错的思路。
好了,接下来进入正题,展示socket聊天室demo。
效果(源码在文章结尾)
主要思路
AndroID
1、进入界面客户端与服务器建立socket,同时此时开启一个线程一直接收服务器发送来的消息。
2、每次点击button获取EditText中的字符串,调用子线程把字符串发送给服务器。
服务器
1、创建一个ArrayList存储Socket。
2、循环接收请求访问该端口的客户端,接收到之后,把该socket存储到ArrayList中,并且为每一个socket开启一个线程用于通信。
3、每个socket的线程的逻辑如下:循环接收客户端发来的消息,接收到之后,利用之前的ArrayList,发送到每一个客户端。如果某个客户端返回空值或者无法发送过去,那么表示该客户端已经断开,就从ArrayList中移除。
代码
(借鉴《AndroID疯狂讲义》)
AndroID
不要忘记在AndroIDManifest里面加上访问网络的权限
MainActivity:
package com.example.double2.sockettesttwo;import androID.os.Bundle;import androID.os.Handler;import androID.os.Message;import androID.support.v7.app.AppCompatActivity;import androID.vIEw.VIEw;import androID.Widget.button;import androID.Widget.EditText;import androID.Widget.TextVIEw;public class MainActivity extends AppCompatActivity { private EditText etMain; private button btnMain; private TextVIEw tvMain; private ClIEntThread mClIEntThread; //在主线程中定义Handler传入子线程用于更新TextVIEw private Handler mHandler; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); etMain = (EditText) findVIEwByID(R.ID.et_main); btnMain = (button) findVIEwByID(R.ID.btn_main); tvMain = (TextVIEw) findVIEwByID(R.ID.tv_main); mHandler=new Handler() { @OverrIDe public voID handleMessage(Message msg) { if (msg.what == 0) { tvMain.append("\n" + msg.obj.toString()); } } }; //点击button时,获取EditText中string并且调用子线程的Handler发送到服务器 btnMain.setonClickListener(new VIEw.OnClickListener() { @OverrIDe public voID onClick(VIEw v) { try { Message msg = new Message(); msg.what = 1; msg.obj = etMain.getText().toString(); mClIEntThread.revHandler.sendMessage(msg); etMain.setText(""); } catch (Exception e) { e.printstacktrace(); } } }); mClIEntThread = new ClIEntThread(mHandler); new Thread(mClIEntThread).start(); }}
ClIEntThread
package com.example.double2.sockettesttwo;import androID.os.Handler;import androID.os.Looper;import androID.os.Message;import androID.util.Log;import java.io.BufferedReader;import java.io.IOException;import java.io.inputStreamReader;import java.io.OutputStream;import java.net.socket;/** * 项目名称:SocketTestTwo * 创建人:Double2号 * 创建时间:2016.11.20 9:16 * 修改备注: */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("10.3.20.159",30003); 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); Message msg = new Message(); msg.what = 0; msg.obj = content; mHandler.sendMessage(msg); } }catch (IOException e){ e.printstacktrace(); } } }.start(); //由于子线程中没有默认初始化Looper,要在子线程中创建Handler,需要自己写 Looper.prepare(); revHandler = new Handler() { @OverrIDe public voID handleMessage(Message msg) { if (msg.what == 1) { try { mOutputStream.write((msg.obj.toString() + "\r\n").getBytes("utf-8")); } catch (IOException e) { e.printstacktrace(); } } } }; Looper.loop(); } catch (IOException e) { e.printstacktrace(); Log.d("xjj",""); } }}
activity_main
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:ID="@+ID/activity_main" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:padding="@dimen/activity_vertical_margin" androID:orIEntation="vertical" > <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="wrap_content" androID:orIEntation="horizontal"> <EditText androID:ID="@+ID/et_main" androID:layout_wIDth="0dp" androID:layout_height="wrap_content" androID:layout_weight="1"/> <button androID:ID="@+ID/btn_main" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:text="@string/send"/> </linearLayout> <TextVIEw androID:ID="@+ID/tv_main" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" /></linearLayout>
服务器:
MySever
import java.io.IOException;import java.net.ServerSocket;import java.net.socket;import java.util.ArrayList;public class MySever { public static ArrayList<Socket> socketList = new ArrayList<Socket>(); public static String content=""; public static voID main(String[] args) throws IOException { //建立ServerSocket ServerSocket ss = new ServerSocket(30003); //不断接收此端口的socket,并存储到socketList中 //并且为每一个socket开启一个线程,用于接收信息 while (true) { Socket s = ss.accept(); System.out.println("connect success!"); socketList.add(s); new Thread(new ServerThread(s)).start(); } }}
SeverThread
import java.io.BufferedReader;import java.io.IOException;import java.io.inputStreamReader;import java.io.OutputStream;import java.io.UnsupportedEnCodingException;import java.net.socket;import java.net.socketException;import java.util.Iterator;public class ServerThread implements Runnable { private Socket mSocket = null; private BufferedReader mBufferedReader = null; // 构造函数中接收socket并且初始化BufferedReader public ServerThread(Socket socket) throws UnsupportedEnCodingException,IOException { mSocket = socket; mBufferedReader = new BufferedReader( new inputStreamReader(mSocket.getinputStream(),"utf-8")); } @OverrIDe public voID run() { // Todo auto-generated method stub try { String content = null; //循环接收来自此客户端的消息 //如果接收不到了,表面已经断开,就将此客户端从socketList中移除 while ((content = mBufferedReader.readline()) != null) { System.out.println(content); //向连接中的每个客户端发送数据 //如果异常,说明断开,就将该条目从socketList中移除 for (Iterator<Socket> it = MySever.socketList.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) { e.printstacktrace(); MySever.socketList.remove(mSocket); } }}
源码地址:android socket聊天室
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的android socket聊天室功能实现全部内容,希望文章能够帮你解决android socket聊天室功能实现所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)