C#服務端經過Socket推送數據到Android端App中

需求:

  描述:實時在客戶端上獲取到哪些款須要補貨.java

     要求: 後臺須要使用c#,而且哪些須要補貨的邏輯寫在公司框架內,客戶端採用PDA(Android客戶端 版本4.4) . 用戶打開了補貨通知頁面時不須要在通知欄推送 若是不在時須要通知欄推送消息.android

實現思路設計

思路圖解釋:正則表達式

想法是啓動服務時候建立TcpListener監聽指定的Ip端口建立接收鏈接的線程和接收數據的回調因爲 定義的存儲方式(Dictionary<string, ClientSocketManager> Clients = new Dictionary<string, ClientSocketManager>();)因此採用了先由客戶端創建鏈接而後服務端收到鏈接請求時當即發送一條數據給客戶端要求客戶端發送用戶簽名給服務端以便服務端能夠根據用戶Id之類的數據去發送給指定的用戶 設置的數據格式爲/*star|狀態,user標識|end*/真實數據c#

客戶端登陸時候和服務端創建鏈接在任意界面均可以接收到通知打開通知時候進入展現數據的頁面服務器

 

服務端關鍵性代碼

 1    protected override void OnStart(string[] args)
 2         {
 3             if (IsListened) return;
 4             //啓動監聽
 5             IPAddress ip = IPAddress.Parse(ServiceSetting._IPAddress);
 6             IPEndPoint point = new IPEndPoint(ip, ServiceSetting._IPEndPoint);
 7             listener = new TcpListener(point);
 8             try
 9             {
10                 listener.Start(100);
11             }
12             catch (Exception ex)
13             {
14                 LogHelper.Log(ex);
15                 return;
16             }
17             IsListened = true;
18             //接受鏈接請求的異步調用
19             AsyncCallback callback = new AsyncCallback(AcceptCallBack);
20             listener.BeginAcceptSocket(callback, listener);
21             LogHelper.Write("服務已啓動……", LogLev.Info);
22         }
OnStart
 1   private void AcceptCallBack(IAsyncResult ar)
 2         {
 3             try
 4             {
 5                 //完成異步接收鏈接請求的異步調用
 6                 Socket handle = listener.EndAcceptSocket(ar);
 7                 ClientSocketManager manager = new ClientSocketManager(handle);
 8 
 9                 AsyncCallback callback;
10                 //繼續調用異步方法接收鏈接請求
11                 if (IsListened)
12                 {
13                     callback = new AsyncCallback(AcceptCallBack);
14                     listener.BeginAcceptSocket(callback, listener);
15                 }
16                 //開始在鏈接上進行異步的數據接收
17                 manager.ClearBuffer();
18                 callback = new AsyncCallback(ReceiveCallback);
19                 manager.socket.BeginReceive(manager.Rcvbuffer, 0, manager.Rcvbuffer.Length, SocketFlags.None, callback, manager);
20             }
21             catch (Exception ex)
22             {
23                 //在調用EndAcceptSocket方法時可能引起異常
24                 //套接字Listener被關閉,則設置爲未啓動偵聽狀態
25                 IsListened = false;
26                 LogHelper.Log(ex);
27                 return;
28             }
29         }
接收鏈接回調
 1   private void ReceiveCallback(IAsyncResult ar)
 2         {
 3             ClientSocketManager manager = (ClientSocketManager)ar.AsyncState;
 4             try
 5             {
 6                 int i = manager.socket.EndReceive(ar);
 7                 if (i == 0)
 8                 {
 9                     RemoveOneClientbyManager(manager);
10                     return;
11                 }
12                 else
13                 {
14                     string data = Encoding.UTF8.GetString(manager.Rcvbuffer, 0, i);
15                     //manager.socket.RemoteEndPoint.ToString() 獲取客戶端IP
16                     manager.ClearBuffer();
17                     //根據傳入數據處理用戶數據 設置數據格式爲/*star|狀態,user標識|end*/真實數據
18                     //匹配中間的狀態正則表達式  ^(/[*]star\|).*(?=\|end[*]/)
19                     //首次傳入保存鏈接信息
20                     //打開通知時接收到回調
21                     string packgeHead = Regex.Match(data, @"^(/[*]star\|).*(?=\|end[*]/)").ToString().Replace("/*star|", "");
22                     if (string.IsNullOrEmpty(packgeHead))
23                     {
24                         LogHelper.Write("客戶端沒有發送指定的數據頭", LogLev.Warn);
25                         return;
26                     }
27                     string[] heads = packgeHead.Split(',');
28                     switch (heads[0])
29                     {
30                         case "first":// 首次傳入保存鏈接信息
31                             lock (lockObj)
32                             {
33                                 Clients.Add(heads[1], manager);
34                             }
35                             //ToRemove
36                             SendToClient(new List<string>() { "aaa" }, "您有一條新的通知");
37                             //endRemove
38                             break;
39                         case "data"://用戶打開了頁面能夠發送數據
40                             ReceiveThenSend(manager);
41                             break;
42                         default:
43                             LogHelper.Write("客戶端發送的數據頭有問題", LogLev.Warn);
44                             break;
45                     }
46                     AsyncCallback callback = new AsyncCallback(ReceiveCallback);
47                     manager.socket.BeginReceive(manager.Rcvbuffer, 0, manager.Rcvbuffer.Length, SocketFlags.None, callback, manager);
48                 }
49             }
50             catch (Exception ex)
51             {
52                 RemoveOneClientbyManager(manager);
53                 LogHelper.Log(ex);
54                 return;
55             }
56         }
接收數據回調
 1   private void SendData(ClientSocketManager manager, string data)
 2         {
 3             try
 4             {
 5                 byte[] msg = Encoding.UTF8.GetBytes(data);
 6                 AsyncCallback callback = new AsyncCallback(new Action<IAsyncResult>(ar =>
 7                 {
 8                     ClientSocketManager frd = (ClientSocketManager)ar.AsyncState;
 9                     try
10                     {
11                         frd.socket.EndSend(ar);
12                     }
13                     catch (Exception ex)
14                     {
15                         RemoveOneClientbyManager(manager);
16                         LogHelper.Log(ex);
17                         return;
18                     }
19                 }));
20                 manager.socket.BeginSend(msg, 0, msg.Length, SocketFlags.None, callback, manager);
21             }
22             catch (Exception ex)
23             {
24                 RemoveOneClientbyManager(manager);
25                 LogHelper.Log(ex);
26                 return;
27             }
28         }
發送數據到客戶端

客戶端關鍵性代碼

先受權app

1   <uses-permission android:name="android.permission.INTERNET" />
2 <uses-permission android:name="android.permission.GET_TASKS" />  
AndroidManifest.xml

在Application中插入代碼 (ps:文件名因爲開始打算建的是父級的Activity後來實驗不行就沒有更換名稱)框架

  1 package com.example.sockettestclient;
  2 
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.io.OutputStream;
  6 import java.io.UnsupportedEncodingException;
  7 import java.net.Socket;
  8 import java.net.UnknownHostException;
  9 
 10 import android.app.ActivityManager;
 11 import android.app.Application;
 12 import android.app.NotificationManager;
 13 import android.app.PendingIntent;
 14 import android.content.Context;
 15 import android.content.Intent;
 16 import android.net.NetworkInfo.State;
 17 import android.os.Bundle;
 18 import android.os.Handler;
 19 import android.os.Message;
 20 import android.support.v4.app.NotificationCompat;
 21 import android.widget.EditText;
 22 import android.widget.TextView;
 23 
 24 public class BaseActivity extends Application{
 25      @Override  
 26         public void onCreate(){  
 27             super.onCreate();
 28         }  
 29      //NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 30      //發送通知
 31      protected void InitNotificationManager(String Title,String Content) { 
 32          NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
 33             Intent intent = new Intent(this, TestGetSocketRes.class);//將要跳轉的界面
 34             builder.setAutoCancel(true);//點擊後消失
 35             builder.setSmallIcon(R.drawable.info);//設置通知欄消息標題的頭像
 36             builder.setDefaults(NotificationCompat.DEFAULT_SOUND);//設置通知鈴聲
 37             builder.setTicker(Title);
 38             builder.setContentText(Content);//通知內容
 39             builder.setContentTitle(Title);
 40             //添加參數
 41             Bundle bundle = new Bundle();  
 42             bundle.putString("title", Title);  
 43             bundle.putString("Content", Content);  
 44             intent.putExtras(bundle);
 45             //利用PendingIntent來包裝咱們的intent對象,使其延遲跳轉
 46             PendingIntent intentPend = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 47             builder.setContentIntent(intentPend);
 48             NotificationManager manager = (NotificationManager) this.getSystemService(this.NOTIFICATION_SERVICE);
 49             manager.notify(0, builder.build());
 50     }
 51     protected boolean isConnect = false;
 52     protected static final String ServerIP = "192.168.47.102";
 53     protected static final int ServerPort = 4567;
 54     protected Socket socket = null;
 55     protected ReceiveThread receiveThread = null;
 56     protected boolean isReceive = false;
 57     protected Handler SocketUIHandler = null;
 58     protected OutputStream outStream;
 59     protected String strMessage;
 60     protected TextView textReceive = null;
 61     protected EditText textSend = null;
 62     private boolean IsInPage=false;
 63     private String UserID="aaa";
 64     public enum PostState {  
 65           first, data 
 66         }  
 67     public void SetUserInfo() {
 68         UserID="aaa";
 69     }
 70     public String GetSocketPostDataHeadInfo(PostState state) {
 71         return "/*star|"+state.toString()+","+UserID+"|end*/";
 72     }
 73 Runnable connectThread = new Runnable() {
 74         
 75         @Override
 76         public void run() {
 77             // TODO Auto-generated method stub
 78             try {
 79                 //初始化Scoket,鏈接到服務器
 80                 socket = new Socket(ServerIP, ServerPort);
 81                 isConnect = true;
 82                 //啓動接收線程
 83                 isReceive = true;
 84                 receiveThread = new ReceiveThread(socket);
 85                 receiveThread.start();
 86                 strMessage = GetSocketPostDataHeadInfo(PostState.first);    
 87                 new Thread(sendThread).start();
 88                 System.out.println("----connected success----");
 89             } catch (UnknownHostException e) {
 90                 // TODO Auto-generated catch block
 91                 e.printStackTrace();
 92                 System.out.println("UnknownHostException-->" + e.toString());
 93             } catch (IOException e) {
 94                 // TODO Auto-generated catch block
 95                 e.printStackTrace();
 96                 System.out.println("IOException" + e.toString());
 97             }
 98         }
 99     };
100     //接收線程
101     protected class ReceiveThread extends Thread{
102             private InputStream inStream = null;
103             
104             private byte[] buffer;
105             private String str = null;
106             
107             ReceiveThread(Socket socket){
108                 try {
109                     inStream = socket.getInputStream();
110                 } catch (IOException e) {
111                     // TODO Auto-generated catch block
112                     e.printStackTrace();
113                 }
114             }
115             @Override
116             public void run(){
117                 while(isReceive){
118                     buffer = new byte[512];
119                     try {
120                         inStream.read(buffer);
121                     } catch (IOException e) {
122                         // TODO Auto-generated catch block
123                         e.printStackTrace();
124                     }
125                     try {
126                         str = new String(buffer,"UTF-8").trim();
127                     } catch (UnsupportedEncodingException e) {
128                         // TODO Auto-generated catch block
129                         e.printStackTrace();
130                     }
131                     if(str!=""||str!=null){
132                         if(getRunningActivityName().equals("com.example.sockettestclient.TestGetSocketRes")){
133                             IsInPage=true;
134                         }
135                         if(IsInPage){
136                             Message msg = new Message();
137                             msg.obj = "/*star|data,aaa|end*/"+str;
138                             SocketUIHandler.sendMessage(msg);
139                         }else {
140                             InitNotificationManager("通知",str);
141                         }
142                         if(str.indexOf("_pageend")>=0){
143                             IsInPage=false;
144                         }
145                     }
146                 }
147             }
148         }
149     private String getRunningActivityName(){          
150         ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  
151         String runningActivity=activityManager.getRunningTasks(1).get(0).topActivity.getClassName();  
152         return runningActivity;                 
153 }
154         //發送消息的接口
155         Runnable sendThread = new Runnable() {
156             
157             @Override
158             public void run() {
159                 // TODO Auto-generated method stub
160                 byte[] sendBuffer = null;
161                 try {
162                     sendBuffer = strMessage.getBytes("UTF-8");
163                 } catch (UnsupportedEncodingException e1) {
164                     // TODO Auto-generated catch block
165                     e1.printStackTrace();
166                 }
167                 try {
168                     outStream = socket.getOutputStream();
169                 } catch (IOException e) {
170                     // TODO Auto-generated catch block
171                     e.printStackTrace();
172                 }
173                 try {
174                     outStream.write(sendBuffer);
175                 } catch (IOException e) {
176                     // TODO Auto-generated catch block
177                     e.printStackTrace();
178                 }
179             }
180         };
181         
182         
183 }
BaseApplication
 1 protected void onCreate(Bundle savedInstanceState) {
 2         final BaseActivity app = (BaseActivity)getApplication();  
 3         super.onCreate(savedInstanceState);
 4         setContentView(R.layout.activity_test_login);
 5         Button btnConnect = (Button)findViewById(R.id.button1);
 6         //鏈接
 7                 btnConnect.setOnClickListener(new View.OnClickListener() {
 8                     
 9                     @Override
10                     public void onClick(View v) {
11                         // TODO Auto-generated method stub
12                         if (!app.isConnect){
13                             new Thread(app.connectThread).start(); 
14                         }
15                         Intent intent = new Intent();  
16                            intent.setClass(TestLogin.this, UserLookPage.class);  
17                             startActivity(intent);  
18                     }
19                 });
20                 
21     }
登陸頁
 1 protected void onCreate(Bundle savedInstanceState) {
 2         super.onCreate(savedInstanceState);
 3         setContentView(R.layout.activity_test_get_socket_res);
 4          app = (BaseActivity)getApplication();  
 5         TextView textReceive = (TextView)findViewById(R.id.textView1);
 6         textReceive.setMovementMethod(ScrollingMovementMethod.getInstance());
 7         textReceive.setText("");
 8         Intent intent=getIntent();
 9         String title=intent.getStringExtra("title");
10         String Content=intent.getStringExtra("Content");
11         if(app.isConnect){
12             app.strMessage = app.GetSocketPostDataHeadInfo(PostState.data)+Content;
13             new Thread(app.sendThread).start();
14         }
15         final TextView resval=(TextView)findViewById(R.id.textView1);
16          app.SocketUIHandler= new Handler(){
17             @Override
18             public void handleMessage(Message msg){
19                 String removestr=app.GetSocketPostDataHeadInfo(PostState.data);
20                 resval.append((msg.obj).toString().replace(removestr, ""));
21             }
22         };
23         //new Thread(app.sendThread).start();
24     }
接收數據頁

 開發中遇到的問題

1.最初設計思路是直接後臺將數據返回而後直接顯示在通知欄用戶打開通知欄將存在客戶端的數據顯示到頁面上結果折騰了5個小時的問題就是後臺返回的文本太多前臺一次性收不完而後形成了頁面顯示數據不全並且通知欄有一大段的文本提示異步

最後解決方案就是提示時候只提示有一條消息而後打開時服務端繼續推送到客戶端 客戶端採用追加的形式添加進去(能夠優化爲服務端分屢次返回數據當前是服務端一次性取完數據)socket

2.使用log4net時配置正確顯示不出的問題 解決方案ide

生成選項中選擇若是較新則複製

運行效果

服務端運行

效果

點擊登陸

收到通知

跳轉到顯示數據界面並傳入數據

測試環境:VS2015,Neon.3 Release (4.6.3),Android4.4,逍遙安卓模擬器4.4版本

本例運行須要更改的內容

中的

中的

 中的

本例demo下載

未加wcf版本demo

連接: http://pan.baidu.com/s/1pKOoMld 密碼: e5pg

補充:demo中聯入WCF

添加WCF服務工廠

 1  public class AndroidServiceFactory : IAndroidServiceFactory
 2     {
 3         private readonly string serviceUri = Common.Constants.WCFAndroidBindAddressUrl;
 4         
 5         public IAndroidService CreateService()
 6         {
 7             return this.CreateService<IAndroidService>(serviceUri);
 8         }
 9 
10         private T CreateService<T>(string uri)
11         {
12             var key = string.Format("{0} - {1}", typeof(T), uri);
13 
14             if (Caching.Get(key) == null)
15             {
16                 var binding = new WSHttpBinding();
17                 binding.MaxReceivedMessageSize = maxReceivedMessageSize;
18                 binding.SendTimeout = new TimeSpan(0, 10, 0);
19                 binding.CloseTimeout = new TimeSpan(0, 10, 0);
20                 binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
21                 binding.OpenTimeout = new TimeSpan(0, 10, 0);
22                 binding.ReaderQuotas = new XmlDictionaryReaderQuotas();
23                 binding.ReaderQuotas.MaxStringContentLength = maxReceivedMessageSize;
24                 binding.ReaderQuotas.MaxArrayLength = maxReceivedMessageSize;
25                 binding.ReaderQuotas.MaxBytesPerRead = maxReceivedMessageSize;
26 
27                 ChannelFactory<T> chan = new ChannelFactory<T>(binding, new EndpointAddress(uri));
28                 chan.Open();
29                 var service = chan.CreateChannel();
30                 Caching.Set(key, service);
31                 return service;
32             }
33             else
34             {
35                 return (T)Caching.Get(key);
36             }
37         }
38 
39         private const int maxReceivedMessageSize = int.MaxValue;
40     }
AndroidServiceFactory
 1   /// <summary>
 2         /// 輪詢庫存
 3         /// </summary>
 4         /// <param name="users"></param>
 5         /// <param name="AlertTitle"></param>
 6         private void WcfGetInventory()
 7         {
 8             try
 9             {
10                 while (true)
11                 {
12                     string str = wcf.AndroidService.Replenishmentnotice();
13                     //記錄缺貨的庫存信息
14                     if (!string.IsNullOrEmpty(str))
15                     {
16                         lock (lockObj)
17                         {
18                             SendClientData = str;
19                         }
20                     }
21                     //發送客戶端通知
22                     SendToAllClient(ServiceSetting.AlertTitle);
23                     //等待30分鐘後從新查詢1800000
24                     Thread.Sleep(10000);//10秒
25                     if (Thread.CurrentThread.IsAlive)
26                     {
27                         WcfReTry = 0;
28                     }
29                     else {
30                         if (WcfReTry <= ServiceSetting.WcfReTryCount)
31                         {
32                             //重啓線程
33                             Thread th = new Thread(WcfGetInventory);
34                             th.Start();
35                             WcfReTry++;
36                         }
37                         LogHelper.Write("WcfGetInventory方法線程死掉而且沒法重啓", LogLev.Error);
38                     }
39                 }
40             }
41             catch (Exception ex)
42             {
43                 if (WcfReTry <= ServiceSetting.WcfReTryCount) {
44                     //重啓線程
45                     Thread th = new Thread(WcfGetInventory);
46                     th.Start();
47                     WcfReTry++;
48                 }
49                 LogHelper.Log(ex);
50             }
51         }
加入輪詢wcf方法

而後在服務啓動函數內啓動線程

相關文章
相關標籤/搜索