android 通信机制 socket
socket 作为一种通信机制,可以实现单机或者跨网络之间的通信,要有明确的server端和client端。
android里面最简单的socket 通信的demo:
//1. IP 地址
InetAddress inetAddress = InetAddress.getByName("IP address");
// socket port
Socket client = new Socket(inetAddress,61203,true);
// get data stream
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
// deal with data
// close connection
out.close();
in.close();
client.close();
在一个完整的通行过程,包括2个socket,一个server段在用,另外一个是client段。整个架构的简介:
1)通常情况下,我们使用线程处理socket携带的信息。
2)clientThread, serverThread处理socket,好处是主线程可以继续其他的工作。
demo创建的流程:1. 在Eclipse里面安装Tomcat 作为server
2. 编写一个service project用来处理client 传递过来的数据,并且把处理过的数据返回到客户端
3. 编写一个简单的android应用,向service发送数据,并且接收service返回的数据
1. 如何在Eclipse里面配置Tomcat不是本文的重点,在网上搜索一堆。这里要说明的如果默认的8080端口被使用,要修改Tomcat配置文件里面的端口号,配置文件的地址是../conf/server.xml
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
这个只是Tomcat的端口,和socket里面的端口不一样。
2. Server的端代码:
1)ServerThread
public class SeverThread implements Runnable
{
private Socket socket=null; // 定义一个socket 给当前线程使用
private BufferedReader br=null; // 处理线程里面socket所对应的输入流
public ServerThread(Socket socket)
{
this.socket=socket;
// 初始化socket对应的流
br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
}
public void run()
{
String content="";
// 不停的loop, 读取client传过的数据
while((content = getContent())!= null){
// 读取socket里面的内容,然后回发, 这里是整个server的核心,也是功能扩展的核心
for(Socket s : MyServer.socketList){
OutputStream os = s.getOutputStream(); // outputStream 是用socket创建
os.write(("这个server段给你的消息").getBytes("utf-8"))
}
}
}
private String getContent()
{
try{
return br.readLine();
}catch(Exception ex){
MyServer.socketList.remove(socket);// 如果捕获到异常,表明要关闭这个client的连接, 删除该socket
}
return null;
}
}
定义好一个serverThread,我们就开始在编写service app,定义一个简单的控制台应用即可,host在tomcat上。
public class MyServer{
public List<Socket> socketList = new ArrayList<Socket>();
public static void main(){
ServerSocket ss = new ServerSocket(18070) ;// 这里的18070是端口号,这个是client 和server 公用的端口号
// 程序开始不停的loop,等待client的连接
while(true){
Socket s = ss.accept();
socketList.add(s);
// 有client的socket过来的时候启动线程处理
new Thread(new ServerThread(s)).start();
}
}
}
至此server段的代码已经编写完毕,启动Tomcat,启动server的application host在Tomcat上,一个完整的service已经好了。
3. 编写client段, client段的结构和server类似,一个clientThread,一个android application
public class ClientThread implements Runnable{
private Socket socket; //为这个线程定义一个socket
private BufferedReader br = null;// 处理该线程的socket流
private Handler handler;// 作用是发送message到UI,通知UI改变信息
public ClientThread(Socket socket, Handler handler) throw IOException
{
this.socket = socket;
this.handler=handler;
br=new BufferedReader(new InputStreamReader(sockt.getInputStream()));
}
public void run(){
try{
String content="";
// 和server相同,不停的循环读取socket里面的流
while((content=br.readLine())!=null){
// 读到数据之后,发送message,通知UI改变
Message msg = new Message();
msg.what=0X123; // 作为message的标识
msg.object= content;
handler.sendMessage(msg);
}
}catch(Exception ex){
e.printStackTrace();
}
}
}
public class MainActivity extends Activity implements Runnable {
private Button btnTest;
private TextView tv_msg;
private EditText etMessage;
private String content = "";
Handler handler;
// 需要BufferedReader
BufferedReader bufferedReader = null;
// 需要一个socket
Socket socket = null;
// 需要一个printWritter
PrintWriter out = null;
OutputStream os;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 如果是2.3以后的版本,这段必须加上
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork() /
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
.build());
handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// 如果消息来自于子线程
if (msg.what == 0x123)
{
// 将读取的内容追加显示在文本框中
tv_msg.append("\n" + msg.obj.toString());
}
}
};
initalView();
btnTest.setOnClickListener(myListener);
new Thread(MainActivity.this).start();
}
private void initalView() {
btnTest = (Button) findViewById(R.id.btnTest);
etMessage = (EditText) findViewById(R.id.messageET);
tv_msg = (TextView) findViewById(R.id.tv_msg);
initalSocket();
}
private void initalSocket() {
try {
socket = new Socket();
InetSocketAddress sd = new InetSocketAddress(HostPort.HOST,HostPort.PORT);
socket.connect(sd,5000);
new Thread(new ClientThread(socket, handler)).start(); // ①
os = socket.getOutputStream();
} catch (UnknownHostException e) {
// 由于会发生断网什么的异常处理
System.out.print("连接不上了");
e.printStackTrace();
} catch (IOException e) {
System.out.print(e.getMessage());
e.printStackTrace();
}
}
private View.OnClickListener myListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnTest:
testSocket();
break;
}
}
};
private void testSocket() {
// 将用户在文本框内输入的内容写入网络
try {
os.write((etMessage.getText().toString() + "\r\n")
.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 清空input文本框
etMessage.setText("");
}
@Override
public void run() {
}
@SuppressLint("HandlerLeak")
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.println(1, "test", msg.toString());
tv_msg.setText(tv_msg.getText().toString() + content);
}
};
}
同时在manifest.xml文件中添加权限<uses-permission android:name="android.permission.INTERNET" />
启动android application 即可用socket通行。
以上这种方式其实质就是TCP/IP协议的网络通信。 TCP/IP通信的运行机制是首先向对方发出询问,在等到对方的response后,就给对方发数据。还有一种是UDP的通信,将在下一篇文章详细介绍。 这种UDP的通信方式的缺陷是,不知道对方通不通,就给对方发送消息,结果就是有可能丢包。
如要转载,请注明出处