本文将介绍Android客户端与服务器端的通信的简单实现方法。
要两点需要注意的地方:
1.Android 端记得在AndroidManifest.xml里记得获取一下网络权限,否则无法进行网络通信,如果有需要还要获取一下SD卡读写权限。
获取方法是在AndroidManifest.xml里添加获取权限的两句话:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>前一句是获取网络权限,后一句是获取SD卡读写权限。
2.在Android 4.0以后,是不允许直接在主线程里直接进行网络连接操作的,因为主线程要把菊花献给UI,所以需要建立一个新的线程来进行网络操作。
当然,如果是在写测试demo,可以强行在主线程中进行网络操作,只要在代码中加入这样一句话即可:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads() .detectDiskWrites().detectNetwork().penaltyLog().build());
新建线程有一般两个方法:
(1)通过拓展Thread类来拓展多线程
(2)通过Runnable接口来创建多线程
在传输协议方面,这里一般有两种传输协议可选,即我们所熟知的TCP和UDP协议,一个是面向连接的协议,一个是面向无连接的协议。
因为做测试demo的时候要传输的东西很少,只有实现能连上服务器并进行传输就可以了,所以我们先选用UDP来做,一边发出去另一边接收,这边发完那边能收到就算是成功了。
好,开始动手写代码。
首先,我们在eclipse用Java写一个简单的服务器程序,用来接收android端发来的信息。
package com.cky; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class Server2_1 { public static void main(String[] args) throws IOException { /* * 接收客户端发送的数据 */ //1.创建服务器端DatagramSocket,指定端口 DatagramSocket socket=new DatagramSocket(8800); //2.创建数据报,用于接收客户端发送的数据 byte[] data =new byte[1024];//创建字节数组,指定接收的数据包的大小 DatagramPacket packet=new DatagramPacket(data, data.length); //3.接收客户端发送的数据 System.out.println("****我是服务器,客户端到我碗里来!****"); socket.receive(packet);//此方法在接收到数据报之前会一直阻塞 //4.读取数据 String info=new String(data, 0, packet.getLength()); System.out.println("客户端说:"+info); /* * 向客户端响应数据 */ //1.定义客户端的地址、端口号、数据 InetAddress address=packet.getAddress(); int port=packet.getPort(); byte[] data2="客户端你好,我是服务器".getBytes(); //2.创建数据报,包含响应的数据信息 DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, port); //3.响应客户端 socket.send(packet2); //4.关闭资源 socket.close(); } }
启动程序,在控制台输出这样一句话,等待Android端发信息过来:
然后,开始进行android端的代码编写。
这里我们先写一个测试demo,就不新建线程了,直接强行获取在主线程里进行网络操作的权限
MainActivity.java
package com.example.pc.client2; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.pc.client2.Tool.toolSend1; import java.io.IOException; public class Client2_MainActivity extends AppCompatActivity { private Button btnSend; private EditText etGetText; private TextView tvRecevied; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client2__main); intLayout(); } private void intLayout() { btnSend = (Button) findViewById(R.id.btnSend); btnSend.setOnClickListener(new Click()); etGetText = (EditText) findViewById(R.id.etGetText); tvRecevied = (TextView) findViewById(R.id.tvReceviedStr); } private class Click implements View.OnClickListener { @Override public void onClick(View v) { //通过一个工具来实现发送信息 String sendStr = String.valueOf(etGetText.getText()); String receivedStr = null; try { receivedStr=toolSend1.send(sendStr); } catch (IOException e) { e.printStackTrace(); } tvRecevied.setText("received:" + receivedStr); System.out.println("received:" + receivedStr); } } }
工具类部分代码:
package com.example.pc.client2.Tool; import android.os.StrictMode; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; /** * Created by pc on 2015/10/24. */ public class toolSend1 { public static String send(String sendStr) throws IOException { /* * 向服务器端发送数据 */ //1.定义服务器的地址、端口号、数据 //(cmd: arp -a) byte[] bs = new byte[] { (byte) 192, (byte) 168, (byte)191, (byte)1 }; InetAddress address= null; try { address = InetAddress.getByAddress(bs); } catch (UnknownHostException e) { e.printStackTrace(); } int port=8800; byte[] data=sendStr.getBytes(); //2.创建数据报,包含发送的数据信息 DatagramPacket packet=new DatagramPacket(data, data.length, address, port); //3.创建DatagramSocket对象 DatagramSocket socket= null; try { socket = new DatagramSocket(); } catch (SocketException e) { e.printStackTrace(); } StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads() .detectDiskWrites().detectNetwork().penaltyLog().build()); //4.向服务器端发送数据报 try { socket.send(packet); } catch (IOException e) { e.printStackTrace(); } /* * 接收服务器端响应的数据 */ //1.创建数据报,用于接收服务器端响应的数据 byte[] data2=new byte[1024]; DatagramPacket packet2=new DatagramPacket(data2, data2.length); //2.接收服务器响应的数据 socket.receive(packet2); //3.读取数据 String reply=new String(data2, 0, packet2.getLength()); //4.关闭资源 socket.close(); return reply; } }
服务器端收到信息后进行相应:
客户端收到服务器端返回的信息:
很明显,这里返回的信息出现了乱码。这由于中文编码格式的原因造成的,我们需要对编码格式进行设定,这里我们统一使用utf-8。
byte[] data2="客户端你好,我是服务器".getBytes("UTF-8");
开头说到,Android4.0以后是不允许在主线程里进行网络链接操作的,上面我们是强行在主线程里进行网络操作,但是只能撑一时不能撑一时。比如,此时手机网络开关没有打开或者服务器关闭没有响应的情况下,线程就会卡在那然后程序强退掉,显然,这是很危险的,所以我们必须新建线程进行网络操作,
下面介绍两种新建线程的方法。
在此之前,我们先把强行在主线程进行网络操作的一句代码注释掉
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads() .detectDiskWrites().detectNetwork().penaltyLog().build());
1.扩展java.lang.Thread类,也就是把run()方法写到线程里面。
这里我们一般用handle机制实现activity和Runnable之间的交互
贴代码:
package com.example.pc.client2; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.pc.client2.Tool.toolSend1; import java.io.IOException; public class Client2_MainActivity extends AppCompatActivity { private Button btnSend; private EditText etGetText; private TextView tvRecevied; private String sendStr = null; private String receivedStr = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client2__main); intLayout(); } private void intLayout() { btnSend = (Button) findViewById(R.id.btnSend); btnSend.setOnClickListener(new Click()); etGetText = (EditText) findViewById(R.id.etGetText); tvRecevied = (TextView) findViewById(R.id.tvReceviedStr); } private class Click implements View.OnClickListener { @Override public void onClick(View v) { //通过一个工具来实现发送信息 sendStr = String.valueOf(etGetText.getText()); Thread thread = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { receivedStr = toolSend1.send(sendStr); } catch (IOException e) { e.printStackTrace(); } Message message = new Message(); message.what = 1; mHandler.sendMessage(message); } }); thread.start(); } } public Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1: tvRecevied.setText("received:" + receivedStr); System.out.println("received:" + receivedStr); break; default: break; } super.handleMessage(msg); } }; }
package com.example.pc.client2; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import com.example.pc.client2.Tool.toolSend1; import java.io.IOException; public class Client2_MainActivity extends AppCompatActivity implements Runnable { private Button btnSend; private EditText etGetText; private TextView tvRecevied; private String sendStr = null; private String receivedStr = null; private Thread thread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client2__main); intLayout(); thread=new Thread(this); } private void intLayout() { btnSend = (Button) findViewById(R.id.btnSend); btnSend.setOnClickListener(new Click()); etGetText = (EditText) findViewById(R.id.etGetText); tvRecevied = (TextView) findViewById(R.id.tvReceviedStr); } private class Click implements View.OnClickListener { @Override public void onClick(View v) { //通过一个工具来实现发送信息 sendStr = String.valueOf(etGetText.getText()); thread.start(); } } public void run() { // TODO Auto-generated method stub try { receivedStr = toolSend1.send(sendStr); } catch (IOException e) { e.printStackTrace(); } Message message = new Message(); message.what = 1; mHandler.sendMessage(message); } public Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1: tvRecevied.setText("received:" + receivedStr); System.out.println("received:" + receivedStr); break; default: break; } super.handleMessage(msg); } }; }