您的位置:首页 > 移动开发 > Android开发

Android客户端与服务器之间的通信

2015-10-24 14:21 666 查看
本文将介绍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");


把这一句的参数设置为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);
}
};
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: