Android客户端与服务器之间的通信
本文将介绍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());
但是我们一般不会这样做,毕竟android4.0以后对主线程的这个设定是有它的道理的,所以我们一般会新建一个线程。
新建线程有一般两个方法:
(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); } };}
2. 实现Runnable接口,让类实现Runnable接口,然后把run方法单独提出来
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); } };}
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(二)| 一文带你读懂Nginx的正向与反向代理
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- Android应用程序模型:应用程序,任务,进程,线程
- Android中ContentProvider的实现及定义自己的ContentProvider
- Android(安卓)ContentResolver使用说明
- ANDROID GridView 分页平滑滑动 效果的实现(基于android TV遥控器