Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)

转自:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html

一、概述

关于Socket编程的基本方法在基础篇里已经讲过,今天把它给完善了。加入了多线程,这样UI线程就不会被阻塞;实现了客户端和服务器的双向通信,只要客户端发起了连接并成功连接后那么两者就可以随意进行通信了。

二、实现

在之前的工程基础上进行修改就可以了。

MyClient工程的main.xml文件不用修改,只需要修改MyClientActivity.java文件,主要是定义了一个继承自 Thread类的用于接收数据的类,覆写了其中的run()方法,在这个函数里面接收数据,接收到数据后就通过Handler发送消息,收到消息后在UI 线程里更新接收到的数据。完整的内容如下:

package com.nan.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MyClientActivity extends Activity
{
    private EditText mEditText = null;
    private Button connectButton = null;
    private Button sendButton = null;
    private TextView mTextView = null;

    private Socket clientSocket = null;
    private OutputStream outStream = null;

    private Handler mHandler = null;

    private ReceiveThread mReceiveThread = null;
    private boolean stop = true;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mEditText = (EditText)this.findViewById(R.id.edittext);
        mTextView = (TextView)this.findViewById(R.id.retextview);
        connectButton = (Button)this.findViewById(R.id.connectbutton);
        sendButton = (Button)this.findViewById(R.id.sendbutton);
        sendButton.setEnabled(false);      

        //连接按钮监听
        connectButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                try
                {
                    //实例化对象并连接到服务器
                    clientSocket = new Socket("113.114.170.246",8888);
                }
                catch (UnknownHostException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                displayToast("连接成功!");
                //连接按钮使能
                connectButton.setEnabled(false);
                //发送按钮使能
                sendButton.setEnabled(true);

                mReceiveThread = new ReceiveThread(clientSocket);
                stop = false;
                //开启线程
                mReceiveThread.start();
            }
        });

        //发送数据按钮监听
        sendButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                byte[] msgBuffer = null;
                //获得EditTex的内容
                String text = mEditText.getText().toString();
                try {
                    //字符编码转换
                    msgBuffer = text.getBytes("GB2312");
                } catch (UnsupportedEncodingException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                try {
                    //获得Socket的输出流
                    outStream = clientSocket.getOutputStream();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }                                                    

                try {
                    //发送数据
                    outStream.write(msgBuffer);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //清空内容
                mEditText.setText("");
                displayToast("发送成功!");
            }
        });

        //消息处理
        mHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)
            {
                //显示接收到的内容
                mTextView.setText((msg.obj).toString());
            }
        };

    }

    //显示Toast函数
    private void displayToast(String s)
    {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    }

    private class ReceiveThread extends Thread
    {
        private InputStream inStream = null;

        private byte[] buf;
        private String str = null;

        ReceiveThread(Socket s)
        {
            try {
                //获得输入流
                this.inStream = s.getInputStream();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }      

        @Override
        public void run()
        {
            while(!stop)
            {
                this.buf = new byte[512];

                try {
                    //读取输入数据(阻塞)
                    this.inStream.read(this.buf);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } 

                //字符编码转换
                try {
                    this.str = new String(this.buf, "GB2312").trim();
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                Message msg = new Message();
                msg.obj = this.str;
                //发送消息
                mHandler.sendMessage(msg);

            }
        }

    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if(mReceiveThread != null)
        {
            stop = true;
            mReceiveThread.interrupt();
        }
    }

}

对于MyServer工程,改动比较大,首先是main.xml文件,在里面添加了两个TextView,一个用于显示客户端的IP,一个用于显示接收到的内容,一个用于发送数据的Button,还有一个EditText,完整的main.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/iptextview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="20dip"
        android:gravity="center_horizontal"
        />

    <EditText
        android:id="@+id/sedittext"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="请输入要发送的内容"
        />

    <Button
        android:id="@+id/sendbutton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="发送"
        />

    <TextView
        android:id="@+id/textview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="15dip"

        />

</LinearLayout>

接着,修改MyServerActivity.java文件,定义了两个Thread子类,一个用于监听客户端的连接,一个用于接收数据,其他地方与MyClientActivity.java差不多。完整的内容如下:

package com.nan.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MyServerActivity extends Activity
{
    private TextView ipTextView = null;
    private EditText mEditText = null;
    private Button sendButton = null;
    private TextView mTextView = null;

    private OutputStream outStream = null;
    private Socket clientSocket = null;
    private ServerSocket mServerSocket = null;

    private Handler mHandler = null;

    private AcceptThread mAcceptThread = null;
    private ReceiveThread mReceiveThread = null;
    private boolean stop = true;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ipTextView = (TextView)this.findViewById(R.id.iptextview);
        mEditText = (EditText)this.findViewById(R.id.sedittext);
        sendButton = (Button)this.findViewById(R.id.sendbutton);
        sendButton.setEnabled(false);
        mTextView = (TextView)this.findViewById(R.id.textview);

        //发送数据按钮监听
        sendButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                byte[] msgBuffer = null;
                //获得EditTex的内容
                String text = mEditText.getText().toString();
                try {
                    //字符编码转换
                    msgBuffer = text.getBytes("GB2312");
                } catch (UnsupportedEncodingException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                try {
                    //获得Socket的输出流
                    outStream = clientSocket.getOutputStream();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }                                                    

                try {
                    //发送数据
                    outStream.write(msgBuffer);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //清空内容
                mEditText.setText("");
                displayToast("发送成功!");

            }
        });
        //消息处理
        mHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg)
            {
                switch(msg.what)
                {
                    case 0:
                    {
                        //显示客户端IP
                        ipTextView.setText((msg.obj).toString());
                        //使能发送按钮
                        sendButton.setEnabled(true);
                        break;
                    }
                    case 1:
                    {
                        //显示接收到的数据
                        mTextView.setText((msg.obj).toString());
                        break;
                    }
                }                                           

            }
        };

        mAcceptThread = new AcceptThread();
        //开启监听线程
        mAcceptThread.start();

    }

    //显示Toast函数
    private void displayToast(String s)
    {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    }

    private class AcceptThread extends Thread
    {
        @Override
        public void run()
        {
            try {
                //实例化ServerSocket对象并设置端口号为8888
                mServerSocket = new ServerSocket(8888);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            try {
                //等待客户端的连接(阻塞)
                clientSocket = mServerSocket.accept();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            mReceiveThread = new ReceiveThread(clientSocket);
            stop = false;
            //开启接收线程
            mReceiveThread.start();

            Message msg = new Message();
            msg.what = 0;
            //获取客户端IP
            msg.obj = clientSocket.getInetAddress().getHostAddress();
            //发送消息
            mHandler.sendMessage(msg);

        }

    }

    private class ReceiveThread extends Thread
    {
        private InputStream mInputStream = null;
        private byte[] buf ;
        private String str = null;

        ReceiveThread(Socket s)
        {
            try {
                //获得输入流
                this.mInputStream = s.getInputStream();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        @Override
        public void run()
        {
            while(!stop)
            {
                this.buf = new byte[512];

                //读取输入的数据(阻塞读)
                try {
                    this.mInputStream.read(buf);
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

                //字符编码转换
                try {
                    this.str = new String(this.buf, "GB2312").trim();
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                Message msg = new Message();
                msg.what = 1;
                msg.obj = this.str;
                //发送消息
                mHandler.sendMessage(msg);

            }
        }
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if(mReceiveThread != null)
        {
            stop = true;
            mReceiveThread.interrupt();
        }
    }

}

两个工程都修改好了,同样,在模拟器上运行客户端:

在真机上运行服务器端:

接着,点击客户端的“连接”按钮,看到“连接成功”提示后输入一些内容再点击“发送”按钮,此时客户端显示:

服务器端显示:

接下来两边都可以随意发送数据了。

时间: 2024-11-02 04:30:44

Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)的相关文章

Android应用开发提高篇(1)-----获取本地IP

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/21/2361802.html 一.概述 习惯了Linux下的网络编程,在还没用智能机之前就一直想知道怎么得到手机的IP地址(玩智能机之前我是不搞手机应用的).好了,得知Android是基于Linux内核的,那么不就可以利用之前学的Linux下的网络编程方法来获取IP了吗?呵呵,其实这是比较底层的方法,在Android上,完全可以利用Java的API来实现,而且实现的代码非常简单.下面的实现只可

Android JNI开发提高篇

有关JNI的开发技术,我们继续围绕Android平台进行,JNI可以支持C或C++,从目前为止我们写过的JNI代码均为C实现的,即文件名为.C而C++的和这些有什么不同呢? Android平台上的JNI一般使用C还是C++编写呢? Android平台在中间层和大部分的类库的底层使用了C++的开发方式,后缀为.cpp,比如Android Framework.OpenCore.Webkit.SQLite等等.使用C++好处就是可以使用很多库但目前Android不支持STL,我们知道C表示字符串都是字

Android应用开发提高篇(5)-----Camera使用

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/06/2382679.html 一.概述 Camera是手机的一个很重要的设备,可以说现在的每一部手机上都有.回想当时在Linux搞摄像头编程真的要捏一把汗.有人会说在Linux下装个opencv就可以通过它的函数来使用摄像头啦,但我并没有这么做,我还是用最原始的方法(V4L2)实现了.之前研究过Android关于摄像头这部分的源码,毫无疑问,Android关于摄像头底层的实现用的也是V4L2.

Android应用开发提高篇(6)-----FaceDetector(人脸检测)

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/10/2388776.html 一.概述 初次看到FaceDetector这个类时,心里想:Android真的很强大.但直到我实际应用它的时候,心情从高山跌倒了谷底(看实现中的结果就知道了),再仔细看看官方文档,才知道这个类是API LEVEL1的,我就晕了,这就说明这个类很早就有了,但为什么到现在还没有得到改善呢.写这篇文章的目的还有一个,就是想强调一下用SurfaceView来画图的时候,要

Android应用开发提高篇(2)-----文本朗读TTS(TextToSpeech)

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/26/2368696.html 一.概述 TextToSpeech,就是将文本内容转换成语音,在其他的一些应用中经常可以看到.这个功能还是挺强大的,但是用户利用它来编写应用却很简单. 二.要求 能够将文本内容转换成语音并朗读出来:可以一次全部朗读出来,也可以边写边读:可以将文本保存为语音文件. 三.实现 新建工程MySpeak,修改/res/layout/main.xml文件,在里面添加一个Ed

Android应用开发进阶篇-场景文字识别

由于研究生毕业项目需要完成一个基于移动终端的场景文字识别系统,虽然离毕业尚早,但出于兴趣的缘故,近一段抽时间完成了这样一套系统.基本的架构如下: 客户端:Android应用实现拍摄场景图片,大致划出感兴趣文字区域,通过socket通信上传服务器端识别; 服务器端:Python server进行socket通信监听,连通后调用文字识别引擎(exe可执行程序),将识别结果返回; 下面是系统运行示例图: 1. 客户端 包含两个Activity,: MainActivity主界面如上图左1,选择拍摄后调

Android应用开发基础篇(12)-----Socket通信(转载)

转自:http://www.devdiv.com/android_socket_-blog-258060-10594.html 一.概述 网络通信无论在手机还是其他设备上都应用得非常广泛,因此掌握网络编程是非常有必要的,而我觉得socket编程是网络编程的基础.在进入正题之前,先介 绍几点网络知识,一:socket编程有分TCP和UDP两种,TCP是基于连接的,而UDP是无连接的:二:一个TCP连接包括了输入和输出两条独立的 路径:三:服务器必须先运行然后客户端才能与它进行通信.四:客户端与服务

Android应用开发基础篇(12)-----Socket通信

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/03/2378669.html 一.概述 网络通信无论在手机还是其他设备上都应用得非常广泛,因此掌握网络编程是非常有必要的,而我觉得socket编程是网络编程的基础.在进入正题之前,先介绍几点网络知识,一:socket编程有分TCP和UDP两种,TCP是基于连接的,而UDP是无连接的:二:一个TCP连接包括了输入和输出两条独立的路径:三:服务器必须先运行然后客户端才能与它进行通信.四:客户端与服

简单服务器开发(三)Socket 编程

Socket 的英文原义是“孔”或“插座”.通常也称作"套接字",用于描述 IP 地址和端口,可以用来实现不同计算机之间的通信.在 Internet 上的主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个 Socket,并绑定到一个端口上,不同的端口对应于不同的服务. 根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认.第一步:服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,