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客户端与服务器之间的通信_第1张图片


然后,开始进行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就可以了,用其他编码格式的也是这样设置。

Android客户端与服务器之间的通信_第2张图片


开头说到,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);
        }
    };
}






你可能感兴趣的:(android,线程,通信,网络,服务器)