zoukankan      html  css  js  c++  java
  • Android应用开发提高篇(4)Socket编程(多线程、双向通信)

    一、概述

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


    二、实现

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

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

      1 package com.nan.client;
    2
    3 import java.io.IOException;
    4 import java.io.InputStream;
    5 import java.io.OutputStream;
    6 import java.io.UnsupportedEncodingException;
    7 import java.net.Socket;
    8 import java.net.UnknownHostException;
    9
    10 import android.app.Activity;
    11 import android.os.Bundle;
    12 import android.os.Handler;
    13 import android.os.Message;
    14 import android.view.View;
    15 import android.widget.Button;
    16 import android.widget.EditText;
    17 import android.widget.TextView;
    18 import android.widget.Toast;
    19
    20
    21 public class MyClientActivity extends Activity
    22 {
    23 private EditText mEditText = null;
    24 private Button connectButton = null;
    25 private Button sendButton = null;
    26 private TextView mTextView = null;
    27
    28 private Socket clientSocket = null;
    29 private OutputStream outStream = null;
    30
    31 private Handler mHandler = null;
    32
    33 private ReceiveThread mReceiveThread = null;
    34 private boolean stop = true;
    35
    36 /** Called when the activity is first created. */
    37 @Override
    38 public void onCreate(Bundle savedInstanceState)
    39 {
    40 super.onCreate(savedInstanceState);
    41 setContentView(R.layout.main);
    42
    43 mEditText = (EditText)this.findViewById(R.id.edittext);
    44 mTextView = (TextView)this.findViewById(R.id.retextview);
    45 connectButton = (Button)this.findViewById(R.id.connectbutton);
    46 sendButton = (Button)this.findViewById(R.id.sendbutton);
    47 sendButton.setEnabled(false);
    48
    49 //连接按钮监听
    50 connectButton.setOnClickListener(new View.OnClickListener()
    51 {
    52
    53 @Override
    54 public void onClick(View v)
    55 {
    56 // TODO Auto-generated method stub
    57 try
    58 {
    59 //实例化对象并连接到服务器
    60 clientSocket = new Socket("113.114.170.246",8888);
    61 }
    62 catch (UnknownHostException e)
    63 {
    64 // TODO Auto-generated catch block
    65 e.printStackTrace();
    66 }
    67 catch (IOException e)
    68 {
    69 // TODO Auto-generated catch block
    70 e.printStackTrace();
    71 }
    72
    73 displayToast("连接成功!");
    74 //连接按钮使能
    75 connectButton.setEnabled(false);
    76 //发送按钮使能
    77 sendButton.setEnabled(true);
    78
    79 mReceiveThread = new ReceiveThread(clientSocket);
    80 stop = false;
    81 //开启线程
    82 mReceiveThread.start();
    83 }
    84 });
    85
    86 //发送数据按钮监听
    87 sendButton.setOnClickListener(new View.OnClickListener()
    88 {
    89
    90 @Override
    91 public void onClick(View v)
    92 {
    93 // TODO Auto-generated method stub
    94 byte[] msgBuffer = null;
    95 //获得EditTex的内容
    96 String text = mEditText.getText().toString();
    97 try {
    98 //字符编码转换
    99 msgBuffer = text.getBytes("GB2312");
    100 } catch (UnsupportedEncodingException e1) {
    101 // TODO Auto-generated catch block
    102 e1.printStackTrace();
    103 }
    104
    105
    106 try {
    107 //获得Socket的输出流
    108 outStream = clientSocket.getOutputStream();
    109 } catch (IOException e) {
    110 // TODO Auto-generated catch block
    111 e.printStackTrace();
    112 }
    113
    114
    115 try {
    116 //发送数据
    117 outStream.write(msgBuffer);
    118 } catch (IOException e) {
    119 // TODO Auto-generated catch block
    120 e.printStackTrace();
    121 }
    122 //清空内容
    123 mEditText.setText("");
    124 displayToast("发送成功!");
    125 }
    126 });
    127
    128 //消息处理
    129 mHandler = new Handler()
    130 {
    131 @Override
    132 public void handleMessage(Message msg)
    133 {
    134 //显示接收到的内容
    135 mTextView.setText((msg.obj).toString());
    136 }
    137 };
    138
    139 }
    140
    141 //显示Toast函数
    142 private void displayToast(String s)
    143 {
    144 Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    145 }
    146
    147
    148 private class ReceiveThread extends Thread
    149 {
    150 private InputStream inStream = null;
    151
    152 private byte[] buf;
    153 private String str = null;
    154
    155 ReceiveThread(Socket s)
    156 {
    157 try {
    158 //获得输入流
    159 this.inStream = s.getInputStream();
    160 } catch (IOException e) {
    161 // TODO Auto-generated catch block
    162 e.printStackTrace();
    163 }
    164 }
    165
    166 @Override
    167 public void run()
    168 {
    169 while(!stop)
    170 {
    171 this.buf = new byte[512];
    172
    173 try {
    174 //读取输入数据(阻塞)
    175 this.inStream.read(this.buf);
    176 } catch (IOException e) {
    177 // TODO Auto-generated catch block
    178 e.printStackTrace();
    179 }
    180
    181 //字符编码转换
    182 try {
    183 this.str = new String(this.buf, "GB2312").trim();
    184 } catch (UnsupportedEncodingException e) {
    185 // TODO Auto-generated catch block
    186 e.printStackTrace();
    187 }
    188
    189 Message msg = new Message();
    190 msg.obj = this.str;
    191 //发送消息
    192 mHandler.sendMessage(msg);
    193
    194 }
    195 }
    196
    197
    198 }
    199
    200 @Override
    201 public void onDestroy()
    202 {
    203 super.onDestroy();
    204
    205 if(mReceiveThread != null)
    206 {
    207 stop = true;
    208 mReceiveThread.interrupt();
    209 }
    210 }
    211
    212 }

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

     1 <?xml version="1.0" encoding="utf-8"?>
    2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3 android:layout_width="fill_parent"
    4 android:layout_height="fill_parent"
    5 android:orientation="vertical" >
    6
    7 <TextView
    8 android:id="@+id/iptextview"
    9 android:layout_width="fill_parent"
    10 android:layout_height="wrap_content"
    11 android:textSize="20dip"
    12 android:gravity="center_horizontal"
    13 />
    14
    15 <EditText
    16 android:id="@+id/sedittext"
    17 android:layout_width="fill_parent"
    18 android:layout_height="wrap_content"
    19 android:hint="请输入要发送的内容"
    20 />
    21
    22 <Button
    23 android:id="@+id/sendbutton"
    24 android:layout_width="fill_parent"
    25 android:layout_height="wrap_content"
    26 android:text="发送"
    27 />
    28
    29 <TextView
    30 android:id="@+id/textview"
    31 android:layout_width="fill_parent"
    32 android:layout_height="wrap_content"
    33 android:textSize="15dip"
    34
    35 />
    36
    37 </LinearLayout>

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

      1 package com.nan.server;
    2
    3 import java.io.IOException;
    4 import java.io.InputStream;
    5 import java.io.OutputStream;
    6 import java.io.UnsupportedEncodingException;
    7 import java.net.ServerSocket;
    8 import java.net.Socket;
    9
    10 import android.app.Activity;
    11 import android.os.Bundle;
    12 import android.os.Handler;
    13 import android.os.Message;
    14 import android.view.View;
    15 import android.widget.Button;
    16 import android.widget.EditText;
    17 import android.widget.TextView;
    18 import android.widget.Toast;
    19
    20
    21 public class MyServerActivity extends Activity
    22 {
    23 private TextView ipTextView = null;
    24 private EditText mEditText = null;
    25 private Button sendButton = null;
    26 private TextView mTextView = null;
    27
    28 private OutputStream outStream = null;
    29 private Socket clientSocket = null;
    30 private ServerSocket mServerSocket = null;
    31
    32 private Handler mHandler = null;
    33
    34 private AcceptThread mAcceptThread = null;
    35 private ReceiveThread mReceiveThread = null;
    36 private boolean stop = true;
    37
    38 /** Called when the activity is first created. */
    39 @Override
    40 public void onCreate(Bundle savedInstanceState)
    41 {
    42 super.onCreate(savedInstanceState);
    43 setContentView(R.layout.main);
    44
    45 ipTextView = (TextView)this.findViewById(R.id.iptextview);
    46 mEditText = (EditText)this.findViewById(R.id.sedittext);
    47 sendButton = (Button)this.findViewById(R.id.sendbutton);
    48 sendButton.setEnabled(false);
    49 mTextView = (TextView)this.findViewById(R.id.textview);
    50
    51 //发送数据按钮监听
    52 sendButton.setOnClickListener(new View.OnClickListener()
    53 {
    54
    55 @Override
    56 public void onClick(View v)
    57 {
    58 // TODO Auto-generated method stub
    59 byte[] msgBuffer = null;
    60 //获得EditTex的内容
    61 String text = mEditText.getText().toString();
    62 try {
    63 //字符编码转换
    64 msgBuffer = text.getBytes("GB2312");
    65 } catch (UnsupportedEncodingException e1) {
    66 // TODO Auto-generated catch block
    67 e1.printStackTrace();
    68 }
    69
    70
    71 try {
    72 //获得Socket的输出流
    73 outStream = clientSocket.getOutputStream();
    74 } catch (IOException e) {
    75 // TODO Auto-generated catch block
    76 e.printStackTrace();
    77 }
    78
    79
    80 try {
    81 //发送数据
    82 outStream.write(msgBuffer);
    83 } catch (IOException e) {
    84 // TODO Auto-generated catch block
    85 e.printStackTrace();
    86 }
    87 //清空内容
    88 mEditText.setText("");
    89 displayToast("发送成功!");
    90
    91 }
    92 });
    93 //消息处理
    94 mHandler = new Handler()
    95 {
    96 @Override
    97 public void handleMessage(Message msg)
    98 {
    99 switch(msg.what)
    100 {
    101 case 0:
    102 {
    103 //显示客户端IP
    104 ipTextView.setText((msg.obj).toString());
    105 //使能发送按钮
    106 sendButton.setEnabled(true);
    107 break;
    108 }
    109 case 1:
    110 {
    111 //显示接收到的数据
    112 mTextView.setText((msg.obj).toString());
    113 break;
    114 }
    115 }
    116
    117 }
    118 };
    119
    120
    121 mAcceptThread = new AcceptThread();
    122 //开启监听线程
    123 mAcceptThread.start();
    124
    125 }
    126
    127 //显示Toast函数
    128 private void displayToast(String s)
    129 {
    130 Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    131 }
    132
    133
    134 private class AcceptThread extends Thread
    135 {
    136 @Override
    137 public void run()
    138 {
    139 try {
    140 //实例化ServerSocket对象并设置端口号为8888
    141 mServerSocket = new ServerSocket(8888);
    142 } catch (IOException e) {
    143 // TODO Auto-generated catch block
    144 e.printStackTrace();
    145 }
    146
    147 try {
    148 //等待客户端的连接(阻塞)
    149 clientSocket = mServerSocket.accept();
    150 } catch (IOException e) {
    151 // TODO Auto-generated catch block
    152 e.printStackTrace();
    153 }
    154
    155 mReceiveThread = new ReceiveThread(clientSocket);
    156 stop = false;
    157 //开启接收线程
    158 mReceiveThread.start();
    159
    160 Message msg = new Message();
    161 msg.what = 0;
    162 //获取客户端IP
    163 msg.obj = clientSocket.getInetAddress().getHostAddress();
    164 //发送消息
    165 mHandler.sendMessage(msg);
    166
    167 }
    168
    169 }
    170
    171
    172 private class ReceiveThread extends Thread
    173 {
    174 private InputStream mInputStream = null;
    175 private byte[] buf ;
    176 private String str = null;
    177
    178 ReceiveThread(Socket s)
    179 {
    180 try {
    181 //获得输入流
    182 this.mInputStream = s.getInputStream();
    183 } catch (IOException e) {
    184 // TODO Auto-generated catch block
    185 e.printStackTrace();
    186 }
    187 }
    188
    189 @Override
    190 public void run()
    191 {
    192 while(!stop)
    193 {
    194 this.buf = new byte[512];
    195
    196 //读取输入的数据(阻塞读)
    197 try {
    198 this.mInputStream.read(buf);
    199 } catch (IOException e1) {
    200 // TODO Auto-generated catch block
    201 e1.printStackTrace();
    202 }
    203
    204 //字符编码转换
    205 try {
    206 this.str = new String(this.buf, "GB2312").trim();
    207 } catch (UnsupportedEncodingException e) {
    208 // TODO Auto-generated catch block
    209 e.printStackTrace();
    210 }
    211
    212 Message msg = new Message();
    213 msg.what = 1;
    214 msg.obj = this.str;
    215 //发送消息
    216 mHandler.sendMessage(msg);
    217
    218 }
    219 }
    220 }
    221
    222
    223 @Override
    224 public void onDestroy()
    225 {
    226 super.onDestroy();
    227
    228 if(mReceiveThread != null)
    229 {
    230 stop = true;
    231 mReceiveThread.interrupt();
    232 }
    233 }
    234
    235
    236 }

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

    在真机上运行服务器端:

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

    服务器端显示:

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





  • 相关阅读:
    初窥语义搜索
    爬取菜谱网站
    paramiko简介
    软件项目结构规范
    paramiko 远程执行多个命令
    python 中in 的 用法
    spring依赖(部分)
    ModelAndView的部分回顾
    SringMVC 国际化
    spring事物配置,声明式事务管理和基于@Transactional注解的使用
  • 原文地址:https://www.cnblogs.com/lknlfy/p/2379628.html
Copyright © 2011-2022 走看看