13-6-7 android Socket客户端client双向通信的编写
2013-06-09 16:08
387 查看
看了一些android scoket的实例,觉得大部分的socket编程只是实现了一个客户端发送数据到服务器,基本上可以说建立完成。可是实际我们在应用中常见的应该是双向通信,那么这里我主要说一些在做客户端的细节问题,尤其对readline和3.0系统以上建立连接进行介绍。。
源码:http://download.csdn.net/detail/feiyangxiaomi/5573915
1、关于安卓高版本访问网络出 现.NetworkOnMainThreadException异常的问题 ,我们可以采用三种方式:
自从Android 2.3之后,系统增加了一个类:StrictMode。这个类对网络的访问方式进行了一定的改变。Android的官方文档给出了这个类设置的目的:StrictMode是一个系统提供的开发工具,用以检测在开发过程中因为偶然的事故从而造成的系统潜在的问题,进而提示开发者对其进行修复。StrictMode通常用于捕获磁盘访问或者网络访问中与主进程之间交互产生的问题,因为在主进程中,UI操作和一些动作的执行是最经常用到的,它们之间会产生一定的冲突问题。将磁盘访问和网络访问从主线程中剥离可以使磁盘或者网络的访问更加流畅,提升响应度和用户体验。
显然,大多数初学者在进行网络开发时,会选择将访问网络的代码直接放到主进程中,由于和主进程的首要工作——UI交互——相矛盾,因此,必须设置一定的检测机制,以保证系统运行的流畅,所有的异常都可以被检测。
① 使用 AsyncTask 不做介绍可参考点击打开链接
② 开启 Worker Thread(接下来我要采用的)
③ 在 onCreate 方法中加以下代码:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
.build());
这里我主要讲的是第二种方法:
直接上源码,回来我在具体说明:
上面程序用了两个线程实现创建socket和实现socket接收。用了一个handle消息处理机制,按键监听功能这里不做讲解。
2、主要集中的两个问题:
(1)为什么程序中应用in.readline()会阻塞住线程,并且不能读取到正确数据,使用read()则可以
BufferedReader.read(buffer)从这个缓冲区中读取字符,并将它们存储在字符数组buffer,偏移0开始,如果数据读取完毕,返回实际读的字符数目或-1(无数据)。
buffer = BufferedReader.readLine():则是返回读者缓冲区中的下一行。A行开始是由零个或多个字符为'\ n','\
r',“\ R\ N”等作为起始字符。该字符串不包括换行符序列。
在过程中我是用readline()造成了程序的阻塞。
(2)对与BufferedReader和BufferedWriter进行讲解
BufferedReader继承了java.io.Reader包装了一个阅读器和一个缓冲器,用于做数据接收或是文件读取缓冲,默认情况下可缓冲8192个字节:
主要的Reader有
Known
Direct Subclasses
BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader
对于数据接收或是文件读取缓冲可通过下列方法,进行读出:
BufferedWriter和BufferedReader是一个原理,不做介绍。
源码:http://download.csdn.net/detail/feiyangxiaomi/5573915
1、关于安卓高版本访问网络出 现.NetworkOnMainThreadException异常的问题 ,我们可以采用三种方式:
自从Android 2.3之后,系统增加了一个类:StrictMode。这个类对网络的访问方式进行了一定的改变。Android的官方文档给出了这个类设置的目的:StrictMode是一个系统提供的开发工具,用以检测在开发过程中因为偶然的事故从而造成的系统潜在的问题,进而提示开发者对其进行修复。StrictMode通常用于捕获磁盘访问或者网络访问中与主进程之间交互产生的问题,因为在主进程中,UI操作和一些动作的执行是最经常用到的,它们之间会产生一定的冲突问题。将磁盘访问和网络访问从主线程中剥离可以使磁盘或者网络的访问更加流畅,提升响应度和用户体验。
显然,大多数初学者在进行网络开发时,会选择将访问网络的代码直接放到主进程中,由于和主进程的首要工作——UI交互——相矛盾,因此,必须设置一定的检测机制,以保证系统运行的流畅,所有的异常都可以被检测。
① 使用 AsyncTask 不做介绍可参考点击打开链接
② 开启 Worker Thread(接下来我要采用的)
③ 在 onCreate 方法中加以下代码:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
.build());
这里我主要讲的是第二种方法:
直接上源码,回来我在具体说明:
package com.example.client; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @SuppressLint("HandlerLeak") public class MainActivity extends Activity{ private static final String TAG = "MainActivity"; private Button mBtnRegister; private TextView mTxtId; private EditText mEtDevice; private TextView mTxtIp; private Button mBtnConnect; private Socket socket=null; //使用socket连接 private BufferedReader in=null; //缓冲数据 private BufferedWriter out =null; private ObjectInputStream socketin=null; //缓冲数据 private ObjectOutputStream socketout =null; private Thread socketThread; private Thread readlineThread; private boolean socketIsRunning = true; private boolean readIsRunning = false; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, "-------------this is activity_main-------------"); mBtnRegister = (Button)findViewById(R.id.register); mTxtId = (TextView)findViewById(R.id.id); mEtDevice = (EditText)findViewById(R.id.device); mTxtIp = (TextView)findViewById(R.id.ip); mBtnConnect = (Button)findViewById(R.id.connect); ClickListener c1 = new ClickListener(); mBtnConnect.setOnClickListener(c1); mBtnRegister.setOnClickListener(c1); /************************************************************************* * handler 事件处理 */ handler = new Handler(){ @Override public void handleMessage(Message msg){ switch(msg.what){ case 1://接收回来的数据 Log.i(TAG, msg.toString()); Toast.makeText(MainActivity.this, "Data:"+msg.obj, Toast.LENGTH_LONG).show(); mTxtId.setText((String)msg.obj); break; case 2: readIsRunning = true; socketIsRunning = false; readlineThread.start(); } } }; readlineThread = new Thread(new Runnable(){ public void run() { // TODO Auto-generated method stub while(readIsRunning){ try { Thread.sleep(200); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if(!socket.isInputShutdown()){ try { Log.i(TAG, "read……"); String formServerStr=null; char[] buffer = new char[10]; int count = 0; if((count = in.read(buffer))>0) { Log.i(TAG, count+""); Log.i(TAG, buffer[0]+""); formServerStr = getInfoBuff(buffer, count);//消息换行 Message msg = new Message(); msg.what = 1; msg.obj = formServerStr; handler.sendMessageDelayed(msg, 100); } /*********** * 这块不能接收是个极大的问题 看手册 看readline 和 read区别 * if((formServerStr = in.readLine())!=null){//通过直接读取,会造成阻塞 formServerStr+='\n'; Message msg = new Message(); msg.what = 1; msg.obj = formServerStr; Log.i(TAG, "success: "+formServerStr.toString()); handler.sendMessageDelayed(msg, 100); }*/ } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }); socketThread = new Thread(new Runnable(){ public void run(){ while(socketIsRunning){ if(socket == null){ try{ socket = new Socket("10.10.100.254", 8899); //创建 socket socket.setSoTimeout(3000); //防止阻塞 if(socket.isConnected()){ Log.i(TAG, "socket: is created "+socket.toString()); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); Message msg = new Message(); msg.what = 2; handler.sendMessageDelayed(msg, 120); } }catch(Exception e){ e.printStackTrace(); Log.i(TAG, "error: "+e.toString()); } } } } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } /************************************************************************* * 内部监听类,监听OnClickListener事件 */ class ClickListener implements OnClickListener{ public void onClick(View v) { // TODO Auto-generated method stub if(v == mBtnConnect){ Log.i(TAG, "connectButton is pressed"); if(socketIsRunning == true){ socketThread.start(); }else{ Toast.makeText(MainActivity.this, "socket已经连接", Toast.LENGTH_LONG).show(); } } /********************* * register device */ if(v == mBtnRegister){ Log.i(TAG, "register is pressed"); } } } private String getInfoBuff(char[] buff, int count) { char[] temp = new char[count]; for(int i=0; i<count; i++) { temp[i] = buff[i]; } return new String(temp); } }
上面程序用了两个线程实现创建socket和实现socket接收。用了一个handle消息处理机制,按键监听功能这里不做讲解。
2、主要集中的两个问题:
(1)为什么程序中应用in.readline()会阻塞住线程,并且不能读取到正确数据,使用read()则可以
BufferedReader.read(buffer)从这个缓冲区中读取字符,并将它们存储在字符数组buffer,偏移0开始,如果数据读取完毕,返回实际读的字符数目或-1(无数据)。
buffer = BufferedReader.readLine():则是返回读者缓冲区中的下一行。A行开始是由零个或多个字符为'\ n','\
r',“\ R\ N”等作为起始字符。该字符串不包括换行符序列。
在过程中我是用readline()造成了程序的阻塞。
(2)对与BufferedReader和BufferedWriter进行讲解
BufferedReader继承了java.io.Reader包装了一个阅读器和一个缓冲器,用于做数据接收或是文件读取缓冲,默认情况下可缓冲8192个字节:
BufferedReader buf = new BufferedReader(new FileReader("file.java"));
主要的Reader有
Known
Direct Subclasses
BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader
对于数据接收或是文件读取缓冲可通过下列方法,进行读出:
Public Methods | |
---|---|
void | close() Closes this reader. |
void | mark(int markLimit) Sets a mark position in this reader. |
boolean | markSupported() Indicates whether this reader supports the mark()and reset()methods. |
int | read() Reads a single character from this reader and returns it with the two higher-order bytes set to 0. |
int | , int, int)]read(char[] buffer, int offset, int length) Reads at most lengthcharacters from this reader and stores them at offsetin the character array buffer. |
String | readLine() Returns the next line of text available from this reader. |
boolean | ready() Indicates whether this reader is ready to be read without blocking. |
void | reset() Resets this reader's position to the last mark()location. |
long | skip(long byteCount) Skips byteCountbytes in this stream. |
相关文章推荐
- Android-socket-client客户端<2>
- Android-socket-client 客户端实现
- 编写一段Socket服务端程序,监听端口8888,接受到Client的消息“nihao”后,将“nihao”写回到客户端,关闭socket。
- Android 使用Socket实现服务器与手机客户端的长连接三:clientA 发送给clientB,定点发送
- Android 使用Socket实现服务器与手机客户端的长连接二:多Client对一Server聊天
- XMPP在android客户端上的应用 Androidpn的使用[找不到org.androidpn.client.PersistentConnectionListener]
- 编写和MQTT服务器通信的Android客户端程序(二)
- Android项目笔记四:Android端的socket客户端建立
- Android客户端与服务器端通过SOCKET连接进行读写(将JSON数据转化为字符串后传输)
- Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
- iOS用Socket编写客户端
- Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
- Android开发(13)-- 互联网访问图片,在android客户端显示
- Python网络通信之socket模块(四)基于Tcp/Ip的TCP交互通信serve/client的编写过程
- Android 使用Socket实现服务器与手机客户端的长连接五:使用队列封装请求
- Android客户端通过socket与服务器通信
- Java WebSocket客户端java WebSocketClient
- Android作为服务器通过USB使用Socket协议向PC客户端发送文件
- FTP服务器和客户端源代码编写问题(ftp server client source)
- Android Asynchronous Http Client-Android异步网络请求客户端接口