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 }
复制代码

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

 

在真机上运行服务器端:

 

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

 

服务器端显示:

 

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值