Android Socket 聊天工具(一个服务端实现多个客户端间通信)

tuyi456com

贡献于2014-04-14

字数:20678 关键词: Android开发 移动开发

Android Socket 聊天工具(一个服务端实现多个客户端间通信) 看看新闻网>看引擎>开源产品 摘要: 程序开源,共同学习。最近在学Android,做了一个由Socket实现的基于TCP协议的聊天工具,用一个服务端支持多个客户端之间的交流 通信。虽然本人之前做过蓝牙控制小车的软件,但这次做起来也花了不少时间。没办法,谁叫本人还是只菜鸟,所以下面有哪些说得不当的地方,还请各位多多包涵哦!! 如果某位朋友也打算做这个Socket聊天工具,本人有个小小的建议,你可以不必太着急些代码,先想清楚自己最终要做到怎样效果,然后把自己的思路都写下来,有一个基本的实现方法。在写代码时就按照自己的思路一步一步地写下去,这样可以很好地避免写代码时由于思路不清左删右改。 以下是本人程序的设计思路 客户端设计思路: 一 用户登录界面 1 用一个EditText作为用户名输入口,用一个按键确定。 2 注册一个广播接收器,专门接收由后来的聊天界面发过来的消息广播(包括发信人,收信人,消息体)。 3 创建一个客户端连接服务端的方法(要在线程中启动该方法),连接成功并获取输入输出流以后,再在里面启动一个输入流管理线程(接受并处理由服务端发送过来的消息)。并通过intent启动下一个好友列表界面(同时把自身用户名发给下一界面)。 4 对于输入流管理线程,要先判断接收到的是好友名单还是聊天消息发送两种广播,(服务端发送两种信息时可以加个标签以便线程区分)。然后分发出两种广播,一种广播后面的好友列表界面接受的在线好友名单,另一种广播出聊天界面接收的聊天信息。 5 在菜单下做一个退出Activity按键,方便用户退出程序。 6 当一切准备好以后,用户在输入用户名并点击确定,就可以实现以上操作,同时进入了好友列表界面(前提是能正确连接上服务端)。 二 好友列表界面 1 注册一个广播接收器,专门接收由登录界面的输入流管理线程发送过来的好友名单广播 2 用listView逐个显示好友名单。 3 获取用户登录界面发过来的自身用户名。 4 给listView绑定一个监听器,当用户点击listView上的某一好友时,通过intent启动下一个聊天界面,并把所点击到的好友用户名以及自身用户名发给下一个界面。 三 聊天界面 1 获取好友列表界面发送过来的聊天好友用户名以及自身用户名,并在Title上显示。 2 用一个EditText作为聊天消息输入口,用一个按键确定输出。 3 当用户点击确定以后,发送一个消息广播(包含发信人,收信人,消息体),让用户登录界面的消息广播接收器接收。 4 注册一个广播接收器接受用户登录界面的输入流管理线程发送过来的消息。 服务端设计思路: 消息处理界面(只有一个界面) 1 创建一个监听连接请求方法 (监听客户端发送连接请求,需要在线程中启动)。 A 当用户发送连接请求时,生成socket对象。由该socket对象生成输出流和输入流,从输入流中提取出客户端发送过来的用户名,把用户名放到sickName数组上,把输出流放在ArrayOut数组中。 B 发送新客户端XXX连接成功广播。 C 预先用sickName数组和ArrayOut数组创建发送好友列表方法(给各已连接客户端发送好友名单),在这里调用方法。 D 新生成并启动输入流管理线程(接受并处理客户端发送过来的消息,由于有一个新用户生成,就新生一个输入流管理线程,所以客户端发送的消息不会混乱)。 2 创建发送好友列表方法。 3 注册两个广播接收器,一个接收新客户端XXX连接成功广播;另一个接收输入流管理线程发送过来的聊天消息,识别出目标对象,并向目标对象分别发送消息。 4 在onResume方法中启动监听线程。 5 在菜单下做一个退出Activity按键和刷新按钮(再次发送已连接用户名单给各客户端)。 可完善地方: 可考虑好友退出时显示离线。 非正在聊天好友发送信息时提醒。 只要登录了,未接信息可以一直保存,当进入聊天界面时可以再度显示。 可考虑添加LQ头像与聊天表情。 。。。。。。 客户端代码: 1 用户登录界面 package cn.text2; import java.io.BufferedWriter; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; public class Text2Activity extends Activity { Button buttonSure; Button buttonDump; EditText editTextName; PrintWriter output ; Text2Helper text2helper; int k = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); buttonSure = (Button)findViewById(R.id.buttonSure); editTextName = (EditText)findViewById(R.id.editTextName); } /*****确定按键*******/ public void buttonsure(View v) { new Thread(){ public void run(){ Connect(); System.out.println("注册Text2ClientActivity的发送信息广播"); } }.start(); System.out.println("注册Text2ClientActivity的发送信息广播"); OpenBroadcastReceiver(); } /****注册广播方法*******/ public void OpenBroadcastReceiver(){ //生成BroadcastReceiver对象 Text2ClientActivityReceiver Receiver = new Text2ClientActivityReceiver(); //生成过滤器IntentFilter对象 IntentFilter filter = new IntentFilter(); //为过滤器添加识别标签 filter.addAction("android.intent.action.VOICE_COMMAND");//读取Text2ClientActivity的发送信息广播 //接收广播状态 Text2Activity.this.registerReceiver(Receiver, filter); System.out.println("注册广播完成!"); } /********广播接收器类***********///专门读取Text2ClientActivity的发送信息广播 public class Text2ClientActivityReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String yourself = intent.getStringExtra("SendYourself");//接收要发送的对象名称以及信息 String target = intent.getStringExtra("SendTarget"); String message = intent.getStringExtra("SendMessage"); if(k>0){ output.println(yourself); //yourself output.flush(); output.println(target); //target output.flush(); output.println(message); //内容 output.flush(); System.out.println("接收器接收到Text2ClientActivity的广播,并发送到服务端"); } } } /*********启动客户端方法***********/ public void Connect(){ try { InetAddress addr = InetAddress.getByName("192.168.22.10");//服务端手机网络IP地址,连一下wifi就可以知道 System.out.println("客户端发出请求"); //客户端向服务端发出连接请求 Socket socket = new Socket(addr,6666); System.out.println("连接成功,socket=" + socket); //通过该条socket通道得到输出流 output = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); System.out.println("输出流获取成功"); output.println(editTextName.getEditableText().toString()); output.flush(); k++; //启动getMessage线程 text2helper = new Text2Helper(socket,this); //生成新的CGetMessage对象即调用一次CGetMessage Thread gt = new Thread(text2helper); gt.start(); /**跳转到下一个FriendListActivity**/ Intent intentdump =new Intent(); intentdump.putExtra("ClientName",editTextName.getText().toString()); intentdump.setClass(Text2Activity.this, Text2FriendActivity.class); Text2Activity.this.startActivity(intentdump); } catch (Exception e) { e.printStackTrace(); } } /********菜单功能**********/ @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,1,1,"退出"); menu.add(0,2,2,"连接"); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if(item.getItemId() == 1){ finish(); } if(item.getItemId() == 2){ new Thread(){ public void run() { Connect(); } }.start(); } return super.onMenuItemSelected(featureId, item); } } 2 好友列表界面 package cn.text2; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class Text2FriendActivity extends Activity { TextView textViewfriendlist; ListView listViewfriendlist; static Toast tt = null; int i = 1; String Clients[] = {"","","","","","","","","","","","","","","","","","","","","","","","",""}; String YourName; SimpleAdapter simpleAdapter; ArrayList> listItem; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.friend); Intent intentdump = getIntent(); YourName = intentdump.getStringExtra("ClientName"); listViewfriendlist = (ListView)findViewById(R.id.listViewfriendlist); textViewfriendlist = (TextView)findViewById(R.id.textViewfriendlist); /**********listView数据数组与适配器的定义*************/ listItem = new ArrayList>();//定义列表数组 HashMap map = new HashMap(); map.put("LvMessage","好友:"); listItem.add(map); simpleAdapter = new SimpleAdapter(this,listItem, R.layout.text2user,new String[] {"LvMessage"},new int[] {R.id.LvTextViewMessage}); //定义适配器 listViewfriendlist.setAdapter(simpleAdapter); listViewfriendlist.setOnItemClickListener(new ListViewListener()); OpenBroadcastReceiver();//注册接收UpLoadActivity发送过来的好友名单广播 Clients[0]= "Jack"; } /*******listView的监听器**********/ class ListViewListener implements OnItemClickListener{ @Override public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setTitle("你点击了第"+arg2+"行");//设置标题栏显示点击的行 (从0开始) // if(arg2>0){ /**跳转到下一个Text2ClientActivity**/ Intent intentdump2 =new Intent(); intentdump2.putExtra("Target",Clients[arg2]);//目标联系人 intentdump2.putExtra("Yourself", YourName);//自身用户名 intentdump2.setClass(Text2FriendActivity.this, Text2TalkActivity.class); Text2FriendActivity.this.startActivity(intentdump2); // } } } /****注册广播方法*******/ public void OpenBroadcastReceiver(){ //生成BroadcastReceiver对象 FriendListReceiver Receiver = new FriendListReceiver(); //生成过滤器IntentFilter对象 IntentFilter filter = new IntentFilter(); //为过滤器添加识别标签 filter.addAction("android.intent.action.DIAL"); //接收广播状态 Text2FriendActivity.this.registerReceiver(Receiver, filter); System.out.println("注册广播完成!"); } /********广播接收器类***********///接收UpLoadActivity发送过来的好友名单 public class FriendListReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String msg = intent.getStringExtra("FriendListmessage"); //给列表添加数据 Clients[i] = msg; HashMap map = new HashMap(); map.put("LvMessage",msg); listItem.add(map); listViewfriendlist.setAdapter(simpleAdapter); System.out.println("接收器接收到广播--->"+msg+",并显示在listView上"); i++; } } /********菜单功能**********/ @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,1,1,"退出"); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if(item.getItemId() == 1){ finish(); } return super.onMenuItemSelected(featureId, item); } } 3 聊天界面 package cn.text2; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Message; import android.os.Vibrator; import android.text.Editable; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class Text2TalkActivity extends Activity { TextView textViewMessage; Button buttonSend; EditText editText; ListView listView; Vibrator vibrator; static Toast tt = null; SimpleAdapter simpleAdapter; ArrayList> listItem; String Yourself; String Target; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.talk); Intent intent2 = getIntent(); Yourself = intent2.getStringExtra("Yourself"); Target = intent2.getStringExtra("Target"); setTitle("I am "+Yourself+" --->"+Target); textViewMessage = (TextView)findViewById(R.id.textViewMessage); buttonSend = (Button)findViewById(R.id.buttonSend); editText = (EditText)findViewById(R.id.editText); listView = (ListView)findViewById(R.id.listView); tt = Toast.makeText(Text2TalkActivity.this, "有消息", Toast.LENGTH_SHORT); /**********listView数据数组与适配器的定义*************/ listItem = new ArrayList>();//定义列表数组 HashMap map = new HashMap(); map.put("LvMessage","聊天内容:"); listItem.add(map); simpleAdapter = new SimpleAdapter(this,listItem, R.layout.text2user,new String[] {"LvMessage"},new int[] {R.id.LvTextViewMessage}); //定义适配器 listView.setAdapter(simpleAdapter); Text2TalkBroadcastReceiver(); } /******发送信息按钮监听器********/ public void buttonsend(View v) { HashMap map = new HashMap(); map.put("LvMessage", Yourself +":"+editText.getEditableText()); listItem.add(map); listView.setAdapter(simpleAdapter); Intent intent = new Intent(); intent.setAction(intent.ACTION_VOICE_COMMAND);//给UploadActivity发送广播yourself intent.putExtra("SendYourself",Yourself); intent.putExtra("SendTarget",Target); intent.putExtra("SendMessage",editText.getEditableText().toString()); Text2TalkActivity.this.sendBroadcast(intent); System.out.println("向服务端发送信息:"+editText.getEditableText()); } /****注册广播方法*******/ public void Text2TalkBroadcastReceiver(){ //生成BroadcastReceiver对象 Text2TalkbroadcastReceiver Receiver = new Text2TalkbroadcastReceiver(); //生成过滤器IntentFilter对象 IntentFilter filter = new IntentFilter(); //为过滤器添加识别标签 filter.addAction("android.intent.action.PICK"); //接收由Text2FriendActivity发送过来的信息 //接收广播状态 Text2TalkActivity.this.registerReceiver(Receiver, filter); System.out.println("注册广播完成!"); } /********广播接收器类***********///接收由Text2FriendActivity发送过来的信息 public class Text2TalkbroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String msg = intent.getStringExtra("TextMessage"); //给列表添加数据 HashMap map = new HashMap(); map.put("LvMessage", msg); listItem.add(map); listView.setAdapter(simpleAdapter); System.out.println("Text2Talk接收器接收到广播--->"+msg+",并显示在listView上"); vibrator();//震动 } } /******震动30ms方法******/ public void vibrator(){ vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(30); System.out.println("震动30ms"); } /*************菜单*******************/ @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,0,0,"清除"); menu.add(0,1,1,"退出"); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if(item.getItemId() == 0){ ArrayList> listItem1 = new ArrayList>();/*在数组中存放数据*/ HashMap map = new HashMap(); map.put("ItemText","聊天内容:"); listItem1.add(map); SimpleAdapter simpleAdapter1 = new SimpleAdapter(this,listItem1, R.layout.text2user,new String[] {"ItemText"},new int[] {R.id.LvTextViewMessage}); listView.setAdapter(simpleAdapter1); } if(item.getItemId() == 1){ finish(); } return super.onMenuItemSelected(featureId, item); } } 服务端代码: package cn.Text2Server; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class Text2ServerActivity extends Activity { TextView textViewHead = null; TextView textViewMessage; Button buttonStart; Button buttonSend; EditText editText; ListView listView; static Toast toast = null; PrintWriter out,o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11,o12,o13,o14,o15,o16,o17,o18,o19,o20; PrintWriter ArrayOut[] = {o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11,o12,o13,o14,o15,o16,o17,o18,o19,o20}; //直接写(PrintWriter[] ArrayOut)不成功 int k = 0; //记录已连接的客户端数 int m = 0; // 区分显示在服务端的目标对象与body String ReceiveMessage = "客户端:\n"; String nickName[] = {"","","","","","","","","","","","","","","","","","","","","","","","",""}; String from,to,body; String packet[] = {from,to,body}; SimpleAdapter simpleAdapter; ArrayList> listItem; HashMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textViewHead = (TextView)findViewById(R.id.textView); textViewMessage = (TextView)findViewById(R.id.textViewMessage); buttonSend = (Button)findViewById(R.id.buttonSend); editText = (EditText)findViewById(R.id.editText); listView = (ListView)findViewById(R.id.listView); toast = Toast.makeText(Text2ServerActivity.this, "连接成功", Toast.LENGTH_SHORT); /**********listView数据数组与适配器的定义*************/ listItem = new ArrayList>();//定义列表数组 map = new HashMap(); map.put("LvMessage","聊天内容:"); listItem.add(map); simpleAdapter = new SimpleAdapter(this,listItem, R.layout.user,new String[] {"LvMessage"},new int[] {R.id.LvTextViewMessage}); //定义适配器 listView.setAdapter(simpleAdapter); } /********发送信息按钮监听器*******/ //这个可以不要 public void buttonsend(View v){ HashMap map = new HashMap(); map.put("LvMessage", "服务端:"+editText.getEditableText()); listItem.add(map); listView.setAdapter(simpleAdapter); out.println(editText.getEditableText());//发送出该字符串 out.flush(); System.out.println("向客户端发送信息:"+editText.getEditableText()); } /****注册接收信息广播方法*******/ public void OpenBroadcastReceiver(){ //生成BroadcastReceiver对象 broadcastReceiver Receiver = new broadcastReceiver(); //生成过滤器IntentFilter对象 IntentFilter filterMessage = new IntentFilter(); //为过滤器添加识别标签 filterMessage.addAction("android.intent.action.EDIT"); //接收广播状态 Text2ServerActivity.this.registerReceiver(Receiver, filterMessage); System.out.println("注册广播完成!"); } /********信息广播接收器类***********/ public class broadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //给列表添加数据 String msg = intent.getStringExtra("message"); packet[m] = msg; m++; if(msg.equals("监听中")||msg.equals("已连接")){ textViewHead.setText("服务端: 状态:"+msg); System.out.println("接收器已接收到连接状态msg并显示在TextView上"); m = 0; } if(m>=3){ m = 0; String ReceiveMessage = "From 客户端-"+packet[0]+ "To 客户端-"+packet[1] + " :"+packet[2]; HashMap map = new HashMap(); map.put("LvMessage", ReceiveMessage); listItem.add(map); listView.setAdapter(simpleAdapter); System.out.println("接收器已接收到消息并显示在ListView上"); for(int i=0;i> listItem1 = new ArrayList>();/*在数组中存放数据*/ HashMap map = new HashMap(); map.put("ItemText", "聊天内容:"); listItem.add(map); SimpleAdapter simpleAdapter1 = new SimpleAdapter(this,listItem1, R.layout.user,new String[] {"ItemText"},new int[] {R.id.LvTextViewMessage} ); listView.setAdapter(simpleAdapter1); } if(item.getItemId() == 1){ finish(); } if(item.getItemId() == 2){ for(int m=0;m

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 6 金币 [ 分享文档获得金币 ]
1 人已下载

下载文档

相关文档