http://blog.csdn.net/zfyseu1/article/details/48831219?ref=myread
最近一段时间在断断续续地学习Android应用开发的一些知识,许多APP运行时都要服务器进行通信,socket可以很好完成这样一个功能。我在网上找到了一些手机和服务器通过socket通信的例子,然后挑了其中两个进行整合,供给像我一样的Android socket初学者进行参考。
两个例子的链接:
例子一:http://blog.csdn.net/wuchuanpingstone/article/details/6617276
例子二:http://blog.csdn.net/x605940745/article/details/17001641
我把两个例子整合成以下内容:
一、Android socket使用时要注意的地方
1、在Android主线程中不能有访问socket的操作,否则会报异常。
2、在Android工程配置文件中要进行网络权限声明: <uses-permission android:name="android.permission.INTERNET"/>
3、对数据进行发送接收操作时,首先获取socket流,然后可以封装成BufferedWriter和BufferedReader:
- br = new BufferedReader(new InputStreamReader(s.getInputStream()));//把socket输入流封装成BufferedReader
- os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);//把socket输出流封装成PrintWriter
- <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">4、对socket进行读写之前还要判断,连接是否还存在:</span>
- if(!s.isClosed()&&s.isConnected()){
- //进行socket读写操作<span style="white-space:pre">
- }
5、由于在主线程中不能访问网络的操作,所以socket通信还涉及到多线程的知识点;同样,UI控件的更新只能在主线程中进行,所以还涉及到Android消息处理机制相关知识点。
二、实例代码
Android客户端代码:
AndroidManifest.xml配置文件:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.client"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-permission
- android:name="android.permission.INTERNET"/>
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="21" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
activity_main:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- >
- <EditText
- android:id="@+id/input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="to send to the server" />
- <Button
- android:id="@+id/send"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="send"
- android:layout_below="@id/input"/>
- <TextView
- android:id="@+id/show"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/send"/>
- </LinearLayout>
MainActivity.java:
- package com.example.client;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- // 定义界面上的两个文本框
- EditText input;
- TextView show;
- // 定义界面上的一个按钮
- Button send;
- Handler handler;
- // 定义与服务器通信的子线程
- ClientThread clientThread;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- input = (EditText) findViewById(R.id.input);
- show = (TextView) findViewById(R.id.show);
- send = (Button) findViewById(R.id.send);
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // 如果消息来自子线程
- if (msg.what == 0x123) {
- // 将读取的内容追加显示在文本框中
- show.append("\n" + msg.obj.toString());
- }
- }
- };
- clientThread = new ClientThread(handler);
- // 客户端启动ClientThread线程创建网络连接、读取来自服务器的数据
- new Thread(clientThread).start();
- send.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- // 当用户按下按钮之后,将用户输入的数据封装成Message
- // 然后发送给子线程Handler
- Message msg = new Message();
- msg.what = 0x345;
- msg.obj = input.getText().toString();
- clientThread.revHandler.sendMessage(msg);
- input.setText("");
- } catch (Exception e) {
- }
- }
- });
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- }
ClientThread.java:
- package com.example.client;
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.net.InetSocketAddress;
- import java.net.Socket;
- import java.net.SocketTimeoutException;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- public class ClientThread implements Runnable {
- private Socket s;
- // 定义向UI线程发送消息的Handler对象
- Handler handler;
- // 定义接收UI线程的Handler对象
- Handler revHandler;
- // 该线程处理Socket所对用的输入输出流
- BufferedReader br = null;
- //OutputStream os = null;
- PrintWriter os = null;
- public ClientThread(Handler handler) {
- this.handler = handler;
- }
- @Override
- public void run() { //接收数据线程是发送数据线程的子线程
- s = new Socket();
- try {
- s.connect(new InetSocketAddress("121.248.52.236", 3000), 5000);
- br = new BufferedReader(new InputStreamReader(s.getInputStream()));
- // os = s.getOutputStream();
- os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
- // 启动一条子线程来读取服务器相应的数据
- new Thread(new Runnable() {
- @Override
- public void run() {
- String content = null;
- // 不断的读取Socket输入流的内容
- try {
- while ((content = br.readLine()) != null) {
- // 每当读取到来自服务器的数据之后,发送的消息通知程序
- // 界面显示该数据
- if(!s.isClosed()&&s.isConnected()){
- Message msg = new Message();
- msg.what = 0x123;
- msg.obj = content;
- handler.sendMessage(msg);
- }
- }
- } catch (IOException io) {
- io.printStackTrace();
- }
- }
- }).start();
- // 为当前线程初始化Looper
- Looper.prepare();
- // 创建revHandler对象
- revHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // 接收到UI线程的中用户输入的数据
- if (msg.what == 0x345) {
- // 将用户在文本框输入的内容写入网络
- try {
- if(!s.isClosed()&&s.isConnected()){
- //os.write((msg.obj.toString() + "\r\n").getBytes("gbk"));
- os.println(msg.obj.toString());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- };
- // 启动Looper
- Looper.loop();
- } catch (SocketTimeoutException e) {
- Message msg = new Message();
- msg.what = 0x123;
- msg.obj = "网络连接超时!";
- handler.sendMessage(msg);
- } catch (IOException io) {
- io.printStackTrace();
- }
- }
- }
Java服务端代码:
MyService.java:
- package com.android.net;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.List;
- public class MyService {
- // 定义保存所有的Socket
- public static List<Socket> socketList = new ArrayList<Socket>();
- public static void main(String[] args) throws IOException {
- System.out.println("Server start...");
- ServerSocket server = new ServerSocket(3000);
- while(true){
- Socket s=server.accept();
- socketList.add(s);
- //每当客户端连接之后启动一条ServerThread线程为该客户端服务
- new Thread(new ServiceThreada(s)).start();
- }
- }
- }
ServiceThreada.java:
- package com.android.net;
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.net.Socket;
- public class ServiceThreada implements Runnable {
- // 定义当前线程处理的Socket
- Socket s = null;
- // 该线程所处理的Socket所对应的输入流
- BufferedReader br = null;
- public ServiceThreada(Socket s) {
- this.s = s;
- try {
- br = new BufferedReader(new InputStreamReader(s.getInputStream()));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void run() {
- String content = null;
- //采用循环不断的从Socket中读取客户端发送过来的数据
- while((content=readFromClient())!=null){
- //遍历socketList中的每个Socket
- //将读取到的内容每个向Socket发送一次
- // for(Socket s:MyService.socketList)
- if(!s.isClosed()&&s.isConnected()){
- //OutputStream os;
- PrintWriter os=null;
- try {
- //os = s.getOutputStream();
- os=new PrintWriter(new BufferedWriter(new OutputStreamWriter(
- s.getOutputStream())), true);
- if(content.equals("quit")){
- System.out.println("user"+s.getInetAddress()+"offline");
- //os.write(("From server:"+"user"+s.getInetAddress()+"offline"+"\n").getBytes("gbk"));
- os.println("From server:user:"+s.getInetAddress()+"offline");
- s.close();
- }else{
- System.out.println("From client:"+content);
- //os.write(("From server:"+content+"\n").getBytes("gbk"));
- os.println("From server:"+content);
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
- // 定义读取客户端的信息
- public String readFromClient() {
- try {
- if(!s.isClosed()&&s.isConnected()){
- return br.readLine();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- }