链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html

一、概述

关于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 }

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

在真机上运行服务器端:

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

服务器端显示:

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

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

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

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/21/2361802.html 一.概述 习惯了Linux下的网络编程,在还没用智能机之前就一直想 ...

  2. Android JNI开发提高篇

    有关JNI的开发技术,我们继续围绕Android平台进行,JNI可以支持C或C++,从目前为止我们写过的JNI代码均为C实现的,即文件名为.C而C++的和这些有什么不同呢? Android平台上的JN ...

  3. Android应用开发提高篇(3)-----传感器(Sensor)编程

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/29/2373420.html 一.概述 Android支持的传感器种类越来越多了,这确实是一件可 ...

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

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/10/2388776.html 一.概述 初次看到FaceDetector这个类时,心里想:And ...

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

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/06/2382679.html 一.概述 Camera是手机的一个很重要的设备,可以说现在的每一部 ...

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

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/26/2368696.html 一.概述 TextToSpeech,就是将文本内容转换成语音,在其 ...

  7. Android应用开发基础篇(1)-----Button

    Android应用开发基础篇(1)-----Button   一.概述        Button,顾名思义就是按钮的意思,它主要的功能是响应用户按下按钮时的动作. 二.应用      新建一个工程, ...

  8. android 串口开发第二篇:利用jni实现android和串口通信

    一:串口通信简介 由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以 ...

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

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/03/2378669.html 一.概述 网络通信无论在手机还是其他设备上都应用得非常广泛,因此掌 ...

随机推荐

  1. Android之Service与IntentService的比较

    Android之Service与IntentService的比较  不知道大家有没有和我一样,以前做项目或者练习的时候一直都是用Service来处理后台耗时操作,却很少注意到还有个IntentServ ...

  2. poj1565---(数论)skew binary

    /*将数字存储在数组中 #math.h strlen(a)=len sum=0 for(i=0;i<len;i++) sum+=a[i]*(pow(2,len-i)-1)*/ #include ...

  3. 布线问题(prime)

    布线问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:1.把所有 ...

  4. uva 639 Don't Get Rooked 变形N皇后问题 暴力回溯

    题目:跟N皇后问题一样,不考虑对角冲突,但考虑墙的存在,只要中间有墙就不会冲突. N皇后一行只能放一个,而这题不行,所以用全图暴力放棋,回溯dfs即可,题目最多就到4*4,范围很小. 刚开始考虑放一个 ...

  5. 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4

    在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...

  6. 多个Activity之间的切换与数据交互

    总结 两个activity之间切换我概括的分为两步: 1. 代码实现切换操作.2.配置中声明另外一个acitivity! 1. 代码实现切换操作 显示定义一个intent 对象,Intent 这个类的 ...

  7. SendMessage用法实例

    转: http://blog.csdn.net/coolszy/article/details/5523700 SendMessage用法 windowsbuttonmenucommandlistc# ...

  8. Css攻克Selectors 一

    Selectors (选择器) ---------------参考MDN中css学习. 首先css选择器有很多,但总体概括起来的话有两种: 标签选择器(*是特殊情况),可但标签,也可上下文多标签: 属 ...

  9. SQL学习之汇总数据之聚集函数

    一. 1.我们经常需要汇总数据而不用把他们实际检索出来,为此SQL提供了专门的函数,以便于分析数据和报表生成,这些函数的功能有: (1)确定表中行数(或者满足单个条件或多个条件或包含某个特定值的行数) ...

  10. 从零开始nodejs系列文章

    http://blog.fens.me/series-nodejs/ 从基础的node安装到npm配置,从express到jade,还有mongoDB.是一个很好的node教程