内容摘要

1.程序架构

2.通信协议

3.服务器源代码

4.客户端源代码

5.运行效果

一、程序架构

在开发一个聊天室程序时,我们可以使用Socket、Remoting、WCF这些具有双向通信的协议或框架。而现在,我正要实现一个C#语言作为服务器 端、Android作为客户端的聊天室。由于服务器端和客户端不是同一语言(C#和java),所有我选择了Socket作为通信协议。

图1.1所示,我们可以看出:android手机客户端A向服务器端发送消息,服务器端收到消息后,又把消息推送到android手机客户端B。

图1.1

二、通信协议

我们知道,在C#语言中使用Socket技术需要“四部曲”,即“Bind”,“Listen”,“Accept”,“Receive”。然而 Socket编程不像WCF那样面向对象。而且对应每个请求都用同一种方式处理。作为习惯面向对象编程的我来说,编写一个传统的Socket程序很不爽。 绞尽脑汁,我们将数据传输的格式改为json(JavaScript Object Notation 是一种轻量级的数据交换格式),面对对象的问题就解决了。

假设程序的服务契约有两个方法:“登陆”和“发送消息”。调用登陆的方法,就传送方法名(Method Name)为“Logon”的json数据;调用发送消息的方法,就传送方法名为“Send”的json数据。返回的数据中也使用json格式,这样在 android客户端中也能知道是哪个方法的返回值了。

三、服务器源代码

首先需要编写一个处理客户端消息的接口:IResponseManager。

     public   interface  IResponseManager
    {
         void  Write(Socket sender, IList < Socket >  cliens, IDictionary < string ,  object >  param);
    }

其次,我们知道,换了是WCF编程的话,就需要在服务契约中写两个方法:“登陆”和“发送消息”。由于这里是Socket编程,我们实现之前写的IResponseManager接口,一个实现作为“登陆”的方法,另一个实现作为“发送消息”的方法。

public   class  LogonResponseManager : IResponseManager
    {
         public   void  Write(System.Net.Sockets.Socket sender, IList < System.Net.Sockets.Socket >  cliens, IDictionary < string ,  object >  param)
        {
            Console.WriteLine( " 客户端({0})登陆 " , sender.Handle);
            var response  =   new  SocketResponse
            {
                Method  =   " Logon " ,
                DateTime  =  DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ),
                Result  =   new  { UserName  =  param[ " UserName " ].ToString() }
            };

JavaScriptSerializer jss  =   new  JavaScriptSerializer();
             string  context  =  jss.Serialize(response);
            Console.WriteLine( " 登陆发送的数据为:{0} " , context);
            sender.Send(Encoding.UTF8.GetBytes(context  +   " \n " ));
        }
    }

public   class  SendResponseManager : IResponseManager
    {
         public   void  Write(System.Net.Sockets.Socket sender, IList < System.Net.Sockets.Socket >  cliens, IDictionary < string ,  object >  param)
        {
            Console.WriteLine( " 客户端({0})发送消息 " , sender.Handle);
            var msgList  =  param[ " Message " ]  as  IEnumerable < object > ;
             if  (msgList  ==   null )
            {
                 return ;
            }

var response  =   new  SocketResponse
            {
                Method  =   " Send " ,
                DateTime  =  DateTime.Now.ToString( " yyyy-MM-dd HH:mm:ss " ),
                Result  =   new
                { 
                    UserName  =  param[ " UserName " ].ToString(),
                    Message  =  msgList.Select(s  =>  s.ToString()).ToArray() 
                }
            };

JavaScriptSerializer jss  =   new  JavaScriptSerializer();
             string  context  =  jss.Serialize(response);
            Console.WriteLine( " 消息发送的数据为:{0} " , context);

Parallel.ForEach(cliens, (item)  =>
            {
                 try
                {
                    item.Send(Encoding.UTF8.GetBytes(context  +   " \n " ));
                }
                 catch  { };
            });
        }
    }

最后在Socket程序中使用反射加“策略模式”调用这两个接口实现类。

            var typeName  =   " SocketServer. "   +  request.Method  +   " ResponseManager, SocketServer " ;
            Console.WriteLine( " 反射类名为: "   +  typeName);

Type type  =  Type.GetType(typeName);
             if  (type  ==   null )
            {
                 return ;
            }

var manager  =  Activator.CreateInstance(type)  as  IResponseManager;
            manager.Write(sender,  this .socketClientSesson.Select(s  =>  s.Key).ToList(),
                request.Param  as  IDictionary < string ,  object > );

完整的Socket服务器代码如下:

public   class  SocketHost
    {
         private  IDictionary < Socket,  byte [] >  socketClientSesson  =   new  Dictionary < Socket,  byte [] > ();

public   int  Port {  get ;  set ; }

public   void  Start()
        {
            var socketThread  =   new  Thread(()  =>
            {
                Socket socket  =   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint iep  =   new  IPEndPoint(IPAddress.Any,  this .Port);

// 绑定到通道上
                socket.Bind(iep);

// 侦听
                socket.Listen( 6 );

// 通过异步来处理
                socket.BeginAccept( new  AsyncCallback(Accept), socket);

});

socketThread.Start();

Console.WriteLine( " 服务器已启动 " );
        }

private   void  Accept(IAsyncResult ia)
        {
            Socket socket  =  ia.AsyncState  as  Socket;
            var client  =  socket.EndAccept(ia);

socket.BeginAccept( new  AsyncCallback(Accept), socket);

byte [] buf  =   new   byte [ 1024 ];
             this .socketClientSesson.Add(client, buf);

try
            {
                client.BeginReceive(buf,  0 , buf.Length, SocketFlags.None,  new  AsyncCallback(Receive), client);
                 string  sessionId  =  client.Handle.ToString();
                Console.WriteLine( " 客户端({0})已连接 " , sessionId);
            }
             catch  (Exception ex)
            {
                Console.WriteLine( " 监听请求时出错:\r\n "   +  ex.ToString());
            }
        }

private   void  Receive(IAsyncResult ia)
        {
            var client  =  ia.AsyncState  as  Socket;

if  (client  ==   null   ||   ! this .socketClientSesson.ContainsKey(client))
            {
                 return ;
            }

int  count  =  client.EndReceive(ia);

byte [] buf  =   this .socketClientSesson[client];

if  (count  >   0 )
            {
                 try
                {
                    client.BeginReceive(buf,  0 , buf.Length, SocketFlags.None,  new  AsyncCallback(Receive), client);
                     string  context  =  Encoding.UTF8.GetString(buf,  0 , count);
                    Console.WriteLine( " 接收的数据为: " , context);

this .Response(client, context);
                }
                 catch  (Exception ex)
                {
                    Console.WriteLine( " 接收的数据出错:\r\n{0} " , ex.ToString());
                }
            }
             else
            {
                 try
                {
                     string  sessionId  =  client.Handle.ToString();
                    client.Disconnect( true );
                     this .socketClientSesson.Remove(client);
                    Console.WriteLine( " 客户端({0})已断开 " , sessionId);
                }
                 catch  (Exception ex)
                {
                    Console.WriteLine( " 客户端已断开出错 "   +  ex.ToString());
                }
            }
        }

private   void  Response(Socket sender,  string  context)
        {
            SocketRequest request  =   null ;
            JavaScriptSerializer jss  =   new  JavaScriptSerializer();
            request  =  jss.Deserialize(context,  typeof (SocketRequest))  as  SocketRequest;

if  (request  ==   null )
            {
                 return ;
            }

var typeName  =   " SocketServer. "   +  request.Method  +   " ResponseManager, SocketServer " ;
            Console.WriteLine( " 反射类名为: "   +  typeName);

Type type  =  Type.GetType(typeName);
             if  (type  ==   null )
            {
                 return ;
            }

var manager  =  Activator.CreateInstance(type)  as  IResponseManager;
            manager.Write(sender,  this .socketClientSesson.Select(s  =>  s.Key).ToList(),
                request.Param  as  IDictionary < string ,  object > );
        }
    }

最后,json数据传输的实体对象为:

   [Serializable]
     public   class  SocketRequest
    {
         public   string  Method {  get ;  set ; }

public   string  DateTime {  get ;  set ; }

public   object  Param {  get ;  set ; }
    }

    [Serializable]
     public   class  SocketResponse
    {
         public   string  Method {  get ;  set ; }

public   string  DateTime {  get ;  set ; }

public   object  Result {  get ;  set ; }
    }

四、客户端源代码

1.布局文件

logon.xml:

<? xml version="1.0" encoding="utf-8" ?>
< LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"
    android:orientation ="vertical"  android:layout_width ="fill_parent"
    android:layout_height ="fill_parent"  android:background ="@drawable/background" >

< LinearLayout  android:orientation ="vertical"
        android:layout_width ="fill_parent"  android:layout_height ="60dip"
        android:background ="@drawable/logon"   />

< LinearLayout  android:orientation ="vertical"
        android:layout_width ="fill_parent"  android:layout_height ="fill_parent"
        android:paddingLeft ="10dp"  android:paddingRight ="10dp" >

< View  android:layout_width ="fill_parent"  android:layout_height ="20dip"   />

< TextView  android:id ="@+id/feedback_title"  android:textColor ="#FFFFFF"
            android:layout_width ="fill_parent"  android:layout_height ="wrap_content"
            android:text ="用户名:"   />
         < EditText  android:id ="@+id/edtUserName"  android:layout_width ="fill_parent"
            android:layout_height ="wrap_content"   />

< View  android:layout_width ="fill_parent"  android:layout_height ="2dip"
            android:background ="#FF909090"   />

< TextView  android:layout_width ="fill_parent"
            android:textColor ="#FFFFFF"  android:layout_height ="wrap_content"
            android:text ="IP地址:"   />
         < EditText  android:id ="@+id/edtIp"  android:layout_width ="fill_parent"
            android:layout_height ="wrap_content"  android:digits ="1234567890."  
            android:text ="192.168.1.101" />

< View  android:layout_width ="fill_parent"  android:layout_height ="2dip"
            android:background ="#FF909090"   />

< TextView  android:layout_width ="fill_parent"
            android:textColor ="#FFFFFF"  android:layout_height ="wrap_content"
            android:text ="端口号:"   />
         < EditText  android:id ="@+id/edtPort"  android:layout_width ="fill_parent"
            android:layout_height ="wrap_content"  android:inputType ="number"
            android:numeric ="integer"  android:text ="1234" />

< LinearLayout  android:orientation ="horizontal"
            android:layout_width ="fill_parent"  android:layout_height ="wrap_content"
            android:layout_marginTop ="10dp" >
         </ LinearLayout >
         < RelativeLayout  android:layout_width ="fill_parent"
            android:layout_height ="fill_parent" >
             < View  android:id ="@+id/feedback_content"  android:layout_width ="fill_parent"
                android:layout_height ="fill_parent"  android:maxEms ="10"
                android:minEms ="10"  android:gravity ="top"
                android:layout_marginBottom ="50dip"   />
             < Button  android:id ="@+id/btnLogon"  android:layout_width ="fill_parent"
                android:layout_height ="50dp"  android:text ="登陆"  android:textSize ="19dp"
                android:layout_gravity ="center_horizontal"
                android:layout_alignParentBottom ="true"   />
         </ RelativeLayout >
     </ LinearLayout >
</ LinearLayout >

main.xml:

<? xml version="1.0" encoding="utf-8" ?>
< LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"
    android:orientation ="vertical"  android:layout_width ="fill_parent"
    android:layout_height ="fill_parent"  android:background ="@drawable/background" >

< ListView  android:layout_width ="fill_parent"
        android:layout_height ="wrap_content"  android:id ="@+id/ltvMessage" >
     </ ListView >

< RelativeLayout  android:layout_width ="fill_parent"
        android:layout_height ="wrap_content" >

< EditText  android:layout_width ="fill_parent"
            android:layout_height ="wrap_content"  android:id ="@+id/edtMessage"
            android:hint ="请输入消息"  android:layout_alignTop ="@+id/btnSend"
            android:layout_toLeftOf ="@+id/btnSend"   />

< Button  android:text ="SEND"  android:id ="@+id/btnSend"
            android:layout_height ="wrap_content"  android:layout_width ="wrap_content"
            android:layout_alignParentRight ="true"   />
     </ RelativeLayout >

</ LinearLayout >

listview_item.xml:

<? xml version="1.0" encoding="utf-8" ?>
< LinearLayout  xmlns:android ="http://schemas.android.com/apk/res/android"
    android:layout_width ="fill_parent"  android:layout_height ="wrap_content"
    android:orientation ="vertical"  android:paddingBottom ="3dip"
    android:paddingLeft ="10dip" >

< TextView  android:layout_height ="wrap_content"
        android:layout_width ="fill_parent"  android:id ="@+id/itmMessage"
        android:textSize ="20dip" >
     </ TextView >

< LinearLayout  android:layout_width ="fill_parent"
        android:orientation ="horizontal"  android:layout_height ="20dip" >
         < TextView  android:layout_height ="fill_parent"
            android:layout_width ="100dip"  android:id ="@+id/itmUserName"   >
         </ TextView >

< TextView  android:layout_height ="fill_parent"
            android:layout_width ="200dip"  android:id ="@+id/itmTime"   >
         </ TextView >

</ LinearLayout >

</ LinearLayout >

SocketClient:

package  ld.socket;

import  java.io.BufferedReader;
import  java.io.BufferedWriter;
import  java.io.IOException;
import  java.io.InputStreamReader;
import  java.io.OutputStreamWriter;
import  java.net.Socket;
import  java.net.UnknownHostException;
import  java.text.SimpleDateFormat;
import  java.util.Date;
import  java.util.HashMap;
import  java.util.Map;

import  org.json.JSONArray;
import  org.json.JSONException;
import  org.json.JSONObject;

import  android.os.Handler;
import  android.os.Message;
import  android.util.Log;

public   class  SocketClient {

private   static  Socket client;

private   static  SocketClient instance  =   null ;

public   static  SocketClient getInstance() {
         if  (instance  ==   null ) {

synchronized  (ChartInfo. class ) {
                 if  (instance  ==   null ) {
                     try  {
                        ChartInfo chartInfo  =  ChartInfo.getInstance();
                        client  =   new  Socket(chartInfo.getIp(), chartInfo
                                .getPort());
                        instance  =   new  SocketClient();
                    }  catch  (UnknownHostException e) {
                         //  TODO Auto-generated catch block
                    }  catch  (IOException e) {
                         //  TODO Auto-generated catch block
                    }
                }
            }
        }
         return  instance;
    }

private  SocketClient() {
         this .initMap();
         this .startThread();
    }

private   void  initMap() {
         this .handlerMap  =   new  HashMap < String, Handler > ();
    }

public   void  close() {
         try  {
            client.close();
        }  catch  (IOException e) {
             //  TODO Auto-generated catch block
             // e.printStackTrace();
        }
        instance  =   null ;
    }
    
     private   void  startThread() {
        Thread thread  =   new  Thread() {
            @Override
             public   void  run() {

while  ( true ) {
                     if  (client  ==   null   ||   ! client.isConnected()) {
                         continue ;
                    }

BufferedReader reader;
                     try  {
                        reader  =   new  BufferedReader( new  InputStreamReader(
                                client.getInputStream()));
                        String line  =  reader.readLine();
                        Log.d( " initSocket " ,  " line: "   +  line);
                         if  (line.equals( "" )) {
                             continue ;
                        }

JSONObject json  =   new  JSONObject(line);
                        String method  =  json.getString( " Method " );
                        Log.d( " initSocket " ,  " method: "   +  method);
                         if  (method.equals( "" )
                                 ||   ! handlerMap.containsKey(method)) {
                            Log.d( " initSocket " ,  " handlerMap not method " );
                             continue ;
                        }

Handler handler  =  handlerMap.get(method);
                         if  (handler  ==   null ) {
                            Log.d( " initSocket " ,  " handler is null " );
                             continue ;
                        }
                        Log.d( " initSocket " ,  " handler: "   +  method);
                        Object obj  =  json.getJSONObject( " Result " );
                        Log.d( " initSocket " ,  " Result: "   +  obj);
                        Message msg  =   new  Message();
                        msg.obj  =  obj;
                        handler.sendMessage(msg);

}  catch  (IOException e) {

}  catch  (JSONException e) {

}
                }
            }
        };
        thread.start();
    }

private  Map < String, Handler >  handlerMap;

public   void  putHandler(String methodnName, Handler handler) {
         this .removeHandler(methodnName);
         this .handlerMap.put(methodnName, handler);
    }

public   void  removeHandler(String methodnName) {
         if  ( this .handlerMap.containsKey(methodnName)) {
             this .handlerMap.remove(methodnName);
        }
    }

public   void  logon(String userName) {
        Log.d( " initSocket " ,  " logon " );
         try  {
            OutputStreamWriter osw  =   new  OutputStreamWriter(client
                    .getOutputStream());

BufferedWriter writer  =   new  BufferedWriter(osw);

JSONObject param  =   new  JSONObject();
            param.put( " UserName " , userName.replace( " \n " ,  "   " ));

JSONObject json  =   this .getJSONData( " Logon " , param);

writer.write(json.toString());
            writer.flush();
        }  catch  (IOException e) {
             //  TODO Auto-generated catch block
            e.printStackTrace();
        }  catch  (JSONException e) {
             //  TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

public   void  sendMessage(String message) {
        Log.d( " initSocket " ,  " Send " );
         try  {
            OutputStreamWriter osw  =   new  OutputStreamWriter(client
                    .getOutputStream());

BufferedWriter writer  =   new  BufferedWriter(osw);

JSONArray array  =   new  JSONArray();
             for  (String item : message.split( " \n " )) {
                array.put(item);
            }

JSONObject param  =   new  JSONObject();
            param.put( " Message " , array);

param.put( " UserName " , ChartInfo.getInstance().getUserName());

JSONObject json  =   this .getJSONData( " Send " , param);

writer.write(json.toString());
            writer.flush();
        }  catch  (IOException e) {
             //  TODO Auto-generated catch block
            e.printStackTrace();
        }  catch  (JSONException e) {
             //  TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

private  JSONObject getJSONData(String methodName, JSONObject param) {
        JSONObject json  =   new  JSONObject();
         try  {
            json.put( " Method " , methodName);
            SimpleDateFormat format  =   new  SimpleDateFormat(
                     " yyyy-MM-dd HH:mm:ss " );
            json.put( " DateTime " , format.format( new  Date()));
            json.put( " Param " , param);
             return  json;
        }  catch  (JSONException e) {
             return   null ;
        }
    }
}

LogonActivity:

package  ld.socket;

import  org.json.JSONException;
import  org.json.JSONObject;

import  android.app.Activity;
import  android.app.AlertDialog;
import  android.content.ComponentName;
import  android.content.DialogInterface;
import  android.content.Intent;
import  android.os.Bundle;
import  android.os.Handler;
import  android.os.Message;
import  android.util.Log;
import  android.view.KeyEvent;
import  android.view.View;
import  android.view.View.OnClickListener;
import  android.widget.Button;
import  android.widget.EditText;

public   class  LogonActivity  extends  Activity {

private  EditText edtUserName;
     private  EditText edtIp;
     private  EditText edtPort;

private  Button btnLogon;

@Override
     protected   void  onCreate(Bundle savedInstanceState) {
         //  TODO Auto-generated method stub
         super .onCreate(savedInstanceState);

setContentView(R.layout.logon);

this .initViews();
    }

private   void  initViews() {
         this .edtUserName  =  (EditText)  this .findViewById(R.id.edtUserName);
         this .edtIp  =  (EditText)  this .findViewById(R.id.edtIp);
         this .edtPort  =  (EditText)  this .findViewById(R.id.edtPort);

this .btnLogon  =  (Button)  this .findViewById(R.id.btnLogon);
         this .btnLogon.setOnClickListener( new  OnClickListener() {

@Override
             public   void  onClick(View v) {
                 //  TODO Auto-generated method stub

//  showAlert(edtUserName.getText().toString());
                 if  (edtUserName.getText().toString().equals( "" )) {
                    showDialog( " 请输入用户名 " );
                     return ;
                }

if  (edtIp.getText().toString().equals( "" )) {
                    showDialog( " 请输入IP地址 " );
                     return ;
                }

if  (edtPort.getText().toString().equals( "" )) {
                    showDialog( " 请输入端口号 " );
                     return ;
                }

int  port  =  Integer.parseInt(edtPort.getText().toString());
                ChartInfo chartInfo  =  ChartInfo.getInstance();
                chartInfo.setIp(edtIp.getText().toString());
                chartInfo.setPort(port);
                SocketClient proxy  =  SocketClient.getInstance();

if  (proxy  ==   null ) {
                    showDialog( " 未接入互联网 " );
                    setWireless();
                     return ;
                }

proxy.putHandler( " Logon " ,  new  Handler() {
                    @Override
                     public   void  handleMessage(Message msg) {

SocketClient proxy  =  SocketClient.getInstance();
                        proxy.removeHandler( " Logon " );
                        Log.d( " initSocket " ,  " handleMessage " );
                         if  (msg  ==   null   ||  msg.obj  ==   null ) {
                             return ;
                        }

JSONObject json  =  (JSONObject) msg.obj;
                         try  {
                            String userName  =  json.getString( " UserName " );
                            Log.d( " initSocket " ,  " userName: "   +  userName);
                            ChartInfo.getInstance().setUserName(userName);
                            Intent itt  =   new  Intent();
                            itt
                                    .setClass(LogonActivity. this ,
                                            MainActivity. class );
                            LogonActivity. this .startActivity(itt);
                        }  catch  (JSONException e) {
                             //  TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                });
                proxy.logon(edtUserName.getText().toString());
            }
        });
    }

private   void  setWireless() {
        Intent mIntent  =   new  Intent( " / " );
        ComponentName comp  =   new  ComponentName( " com.android.settings " ,
                 " com.android.settings.WirelessSettings " );
        mIntent.setComponent(comp);
        mIntent.setAction( " android.intent.action.VIEW " );
        startActivityForResult(mIntent,  0 );
    }

private   void  showDialog(String mess) {
         new  AlertDialog.Builder( this ).setTitle( " 信息 " ).setMessage(mess)
                .setNegativeButton( " 确定 " ,  new  DialogInterface.OnClickListener() {
                     public   void  onClick(DialogInterface dialog,  int  which) {
                    }
                }).show();
    }

@Override
     public   boolean  onKeyDown( int  keyCode, KeyEvent event) {

if  (keyCode  ==  KeyEvent.KEYCODE_BACK  &&  event.getRepeatCount()  ==   0 ) {

AlertDialog alertDialog  =   new  AlertDialog.Builder(
                    LogonActivity. this ).setTitle( " 退出程序 " ).setMessage( " 是否退出程序 " )
                    .setPositiveButton( " 确定 " ,
                             new  DialogInterface.OnClickListener() {

public   void  onClick(DialogInterface dialog,
                                         int  which) {
                                    LogonActivity. this .finish();
                                }

}).setNegativeButton( " 取消 " ,

new  DialogInterface.OnClickListener() {
                         public   void  onClick(DialogInterface dialog,  int  which) {
                             return ;
                        }
                    }).create();  //  创建对话框

alertDialog.show();  //  显示对话框

return   false ;

}

return   false ;
    }

@Override
     protected   void  onDestroy() {
         //  TODO Auto-generated method stub
         super .onDestroy();
        SocketClient proxy  =  SocketClient.getInstance();
         if  (proxy  !=   null ) {
            proxy.close();
        }
    }

}

MainActivity:

package  ld.socket;

import  org.json.JSONException;
import  org.json.JSONObject;

import  android.app.Activity;
import  android.app.AlertDialog;
import  android.content.DialogInterface;
import  android.os.Bundle;
import  android.os.Handler;
import  android.os.Message;
import  android.util.Log;
import  android.view.KeyEvent;
import  android.view.View;
import  android.view.WindowManager;
import  android.view.View.OnClickListener;
import  android.widget.Button;
import  android.widget.EditText;
import  android.widget.ListView;

public   class  MainActivity  extends  Activity {

private  EditText edtMessage;

private  Button btnSend;

private  ListView ltvMessage;

private  MessageAdapter adapter;

/**  Called when the activity is first created.  */
    @Override
     public   void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
        setContentView(R.layout.main);

//  隐藏键盘
         this .getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

Log.d( " initSocket " ,  " MessageAdapter " );
         this .adapter  =   new  MessageAdapter( this );
        Log.d( " initSocket " ,  " adapter is ok " );

this .findThisViews();
         this .initHandler();

this .serOnClick();

Log.d( " initSocket " ,  " onCreate " );
    }

private   void  findThisViews() {
         this .edtMessage  =  (EditText)  this .findViewById(R.id.edtMessage);
         this .btnSend  =  (Button)  this .findViewById(R.id.btnSend);

this .ltvMessage  =  (ListView)  this .findViewById(R.id.ltvMessage);
         //  this.ltvMessage.setEnabled(false);
         this .ltvMessage.setAdapter( this .adapter);
    }

private   void  initHandler() {

Handler handler  =   new  Handler() {
            @Override
             public   void  handleMessage(Message msg) {
                 if  (msg.obj  ==   null ) {
                    Log.d( " initSocket " ,  " handleMessage is null " );
                     return ;
                }

Log.d( " initSocket " ,  " handleMessage " );
                 try  {
                    JSONObject json  =  (JSONObject) msg.obj;
                    String userName  =  json.getString( " UserName " );

StringBuilder sb  =   new  StringBuilder();
                     int  length  =  json.getJSONArray( " Message " ).length();
                     for  ( int  i  =   0 ; i  <  length; i ++ ) {
                        String item  =  json.getJSONArray( " Message " ).getString(i);
                         if  (item.equals( "" )) {
                             continue ;
                        }
                         if  (length  >  i  +   1 ) {
                            Log.d( " initSocket " ,  " length: "   +  length);
                            Log.d( " initSocket " ,  " i: "   +  i);
                            Log.d( " initSocket " ,  " item: "   +  item);
                            item  +=   " \n " ;
                        }
                        sb.append(item);
                    }

MessageRecord record  =   new  MessageRecord();
                    record.setUserName(userName);
                    record.setMessage(sb.toString());

MainActivity. this .adapter.add(record);
                    adapter.notifyDataSetChanged();
                }  catch  (JSONException e) {
                     //  TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };
        SocketClient proxy  =  SocketClient.getInstance();
        proxy.putHandler( " Send " , handler);
    }

private   void  serOnClick() {
         this .btnSend.setOnClickListener( new  OnClickListener() {

@Override
             public   void  onClick(View v) {
                 //  TODO Auto-generated method stub
                btnSend.setEnabled( false );
                String txt  =  edtMessage.getText().toString();
                 if  (txt.equals( "" )) {
                    btnSend.setEnabled( true );
                     return ;
                }
                SocketClient proxy  =  SocketClient.getInstance();
                proxy.sendMessage(txt);
                edtMessage.setText( "" );
                btnSend.setEnabled( true );
            }
        });
    }

@Override
     public   boolean  onKeyDown( int  keyCode, KeyEvent event) {

if  (keyCode  ==  KeyEvent.KEYCODE_BACK  &&  event.getRepeatCount()  ==   0 ) {

AlertDialog alertDialog  =   new  AlertDialog.Builder(
                    MainActivity. this ).setTitle( " 询问 " ).setMessage( " 是否注销登录? " )
                    .setPositiveButton( " 确定 " ,
                             new  DialogInterface.OnClickListener() {

public   void  onClick(DialogInterface dialog,
                                         int  which) {
                                    MainActivity. this .finish();
                                }

}).setNegativeButton( " 取消 " ,

new  DialogInterface.OnClickListener() {
                         public   void  onClick(DialogInterface dialog,  int  which) {
                             return ;
                        }
                    }).create();  //  创建对话框

alertDialog.show();  //  显示对话框

return   false ;

}

return   false ;
    }
}

五、运行效果

代码下载

以C#编写的Socket服务器的Android手机聊天室Demo的更多相关文章

  1. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  2. 采用PHP实现”服务器推”技术的聊天室

      传统的B/S结构的应用程序,都是采用”客户端拉”结束来实现客户端和服务器端的数据交换. 本文将通过结合Ticks(可以参看我的另外一篇文章:关于PHP你可能不知道的-PHP的事件驱动化设计),来实 ...

  3. Android之聊天室设计与开发

    我们要设计和实现一个有聊天室功能的APP,需要服务器不断读取来自客户端的信息,并即时地将信息发送给每个连接到本服务器上的客户端,每个客户端可以向服务器发送消息,并不断地接收来自服务器的消息,并将消息显 ...

  4. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...

  5. 基于Node.js+socket.IO创建的Web聊天室

    这段时间进了一个新的项目组,项目是用Appcan来做一个跨平台的移动运维系统,其中前台和后台之间本来是打算用WebSocket来实现的,但写好了示例后发现android不支持WebSocket,大为受 ...

  6. Swift - 使用socket进行通信(附聊天室样例)

    在Swift开发中,如果我们需要保持客服端和服务器的长连接进行双向的数据通信,使用socket是一种很好的解决方案. 下面通过一个聊天室的样例来演示socket通信,这里我们使用了一个封装好的sock ...

  7. vue + socket.io实现一个简易聊天室

    vue + vuex + elementUi + socket.io实现一个简易的在线聊天室,提高自己在对vue系列在项目中应用的深度.因为学会一个库或者框架容易,但要结合项目使用一个库或框架就不是那 ...

  8. Socket之简单的Unity3D聊天室__TCP协议

    服务器端程序 using System; using System.Collections.Generic; using System.Linq; using System.Net; using Sy ...

  9. html5的新通讯技术socket.io,实现一个聊天室

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Storm的本地运行模式示例

    以word count为例,本地化运行模式(不需要安装zookeeper.storm集群),maven工程, pom.xml文件如下: <project xmlns="http://m ...

  2. 使ViewFlipper中的WebView实现手势效果

    使ViewFlipper中的WebView实现手势效果   今天写Blog阅读器的时候遇到了这个问题,把它分享给大家,让同样是新手们少走冤枉路始初写这个功能的时候,用过了好多方法,也耗了不少时间去研究 ...

  3. zoj3822-Domination (概率dp)

    题意: 给你n*m的棋盘,每天选择的一个空的方格放一个棋子,求使棋盘的每行每列都至少有一个棋子的天数期望. 分析: 先想状态,要使每行每列都至少一个,考虑前i行j列,能放得就是i行j列里面的或第i+1 ...

  4. bjfu1252 贪心

    题目意思是给出一些开区间,这些区间有的相交,有的不相交,问你能否选出一些区间,使这些区间之间都不相交,并且选出的区间数最大. 这是个典型的贪心问题了.按区间的结束位置排序,然后顺序地选取区间,只要当前 ...

  5. 【转载】【内存对齐(二)】__declspec( align(#) )的用法和大小计算

    转自:http://www.cppblog.com/deercoder/archive/2011/03/13/141747.html 感谢作者! 在上面讲到了关于pack的内存对齐和计算方法,这里继续 ...

  6. 【原】Storm Local模式和生产环境中Topology运行配置

    Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...

  7. jsViews validates(验证)

          概述:jsViews使得前端开发过程将js代码与html分离,通过模板实现数据与html元素关联,通过绑定方法用数据填充模板,达到渲染html要素的目的.采用该方法后js文件中再也不会出现 ...

  8. java中的==和equals的区别

    关于JAVA中的==和equals函数的区别 今天在研读Thinking in java 时注意到==和equals的区别,于是就通过查看JDK_API才读懂了他们的区别,于是将心得分享一下,望批评指 ...

  9. 你真的了解一段Java程序的生命史吗

    作为一名程序猿 ,我们每天都在写Code,但你真的了解它的生命周期么?今天就来简单聊下它的生命历程,说起一段Java Code,从出生到game over大体分这么几步:编译.类加载.运行.GC. 编 ...

  10. Delphi使用FindClass实现动态建立对像(有点像反射)

    相关资料:http://www.blogjava.net/nokiaguy/archive/2008/05/10/199739.html { http://www.blogjava.net/nokia ...