Android Socket连接
注意点:注册访问的网络权限;android中UI线程不能有访问网络的操作,否则会报android.os.NetworkOnMainThreadException的异常
<uses-permission android:name="android.permission.INTERNET"/>
实例一
客户端
Java:
package com.android.xiong.simplesocket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketTimeoutException; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; 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 { Socket socket = null; String buffer = ""; TextView txt1; Button send; EditText ed1; String geted1; public Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0x11) { Bundle bundle = msg.getData(); txt1.append("server:"+bundle.getString("msg")+"\n"); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txt1 = (TextView) findViewById(R.id.txt1); send = (Button) findViewById(R.id.send); ed1 = (EditText) findViewById(R.id.ed1); send.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { geted1 = ed1.getText().toString(); txt1.append("client:"+geted1+"\n"); //启动线程 向服务器发送和接收信息 new MyThread(geted1).start(); } }); } class MyThread extends Thread { public String txt1; public MyThread(String str) { txt1 = str; } @Override public void run() { //定义消息 Message msg = new Message(); msg.what = 0x11; Bundle bundle = new Bundle(); bundle.clear(); try { //连接服务器 并设置连接超时为5秒 socket = new Socket(); socket.connect(new InetSocketAddress("1.1.9.30", 30000), 5000); //获取输入输出流 OutputStream ou = socket.getOutputStream(); BufferedReader bff = new BufferedReader(new InputStreamReader( socket.getInputStream())); //读取发来服务器信息 String line = null; buffer=""; while ((line = bff.readLine()) != null) { buffer = line + buffer; } //向服务器发送信息 ou.write("android 客户端".getBytes("gbk")); ou.flush(); bundle.putString("msg", buffer.toString()); msg.setData(bundle); //发送消息 修改UI线程中的组件 myHandler.sendMessage(msg); //关闭各种输入输出流 bff.close(); ou.close(); socket.close(); } catch (SocketTimeoutException aa) { //连接超时 在UI界面显示消息 bundle.putString("msg", "服务器连接失败!请检查网络是否打开"); msg.setData(bundle); //发送消息 修改UI线程中的组件 myHandler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } } @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; } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:id="@+id/ed1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="给服务器发送信息"/> <Button android:id="@+id/send" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/ed1" android:text="发送"/> <TextView android:id="@+id/txt1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/send"/> </RelativeLayout>
服务端
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 AndroidService { public static void main(String[] args) throws IOException { ServerSocket serivce = new ServerSocket(30000); while (true) { //等待客户端连接 Socket socket = serivce.accept(); new Thread(new AndroidRunable(socket)).start(); } } }
package com.android.net; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; public class AndroidRunable implements Runnable { Socket socket = null; public AndroidRunable(Socket socket) { this.socket = socket; } @Override public void run() { // 向android客户端输出hello worild String line = null; InputStream input; OutputStream output; String str = "hello world!"; try { //向客户端发送信息 output = socket.getOutputStream(); input = socket.getInputStream(); BufferedReader bff = new BufferedReader( new InputStreamReader(input)); output.write(str.getBytes("gbk")); output.flush(); //半关闭socket socket.shutdownOutput(); //获取客户端的信息 while ((line = bff.readLine()) != null) { System.out.print(line); } //关闭输入输出流 output.close(); bff.close(); input.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
实例二
客户端
Java
package com.android.xiong.sockettwotest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; 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) { getMenuInflater().inflate(R.menu.main, menu); return true; } }
package com.android.xiong.sockettwotest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; 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; public ClientThread(Handler handler) { this.handler = handler; } @Override public void run() { s = new Socket(); try { s.connect(new InetSocketAddress("1.1.9.30", 3000), 5000); br = new BufferedReader(new InputStreamReader(s.getInputStream())); os = s.getOutputStream(); // 启动一条子线程来读取服务器相应的数据 new Thread() { @Override public void run() { String content = null; // 不断的读取Socket输入流的内容 try { while ((content = br.readLine()) != null) { // 每当读取到来自服务器的数据之后,发送的消息通知程序 // 界面显示该数据 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 { os.write((msg.obj.toString() + "\r\n") .getBytes("gbk")); } 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(); } } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:id="@+id/input" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/input" /> <Button android:id="@+id/send" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/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"/> </RelativeLayout>
服务端
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 { ServerSocket server = new ServerSocket(3000); while(true){ Socket s=server.accept(); socketList.add(s); //每当客户端连接之后启动一条ServerThread线程为该客户端服务 new Thread(new ServiceThreada(s)).start(); } } }
package com.android.net; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; 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){ OutputStream os; try { os = s.getOutputStream(); os.write((content+"\n").getBytes("gbk")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } // 定义读取客户端的信息 public String readFromClient() { try { return br.readLine(); } catch (Exception e) { e.printStackTrace(); } return null; } }
附:
一些记录:
把socket写成一个服务:
public class SocketService extends Service{ Thread mServiceThread; Socket client; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); mServiceThread = new Thread(new SocketServerThread()); } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); mServiceThread.start(); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); } public class SocketServerThread extends Thread { private static final int PORT = 54321; private SocketServerThread(){ } @Override public void run() { try { ServerSocket server = new ServerSocket(PORT); while(true){ System.out.println("begin client connected"); client = server.accept(); System.out.println("client connected"); BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream())); System.out.println("read from client:"); String textLine = reader.readLine(); if(textLine.equalsIgnoreCase("EXIT")){ System.out.println("EXIT invoked, closing client"); break; } System.out.println(textLine); PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))); writer.println("ECHO from server: " + textLine); writer.flush(); writer.close(); reader.close(); } } catch (IOException e) { // TODO Auto-generated catch block System.err.println(e); } } } }
状态:
除了isClose方法,Socket类还有一个isConnected方法来判断Socket对象是否连接成功。 看到这个名字,也许读者会产生误解。 其实isConnected方法所判断的并不是Socket对象的当前连接状态, 而是Socket对象是否曾经连接成功过,如果成功连接过,即使现在isClose返回true, isConnected仍然返回true。因此,要判断当前的Socket对象是否处于连接状态, 必须同时使用isClose和isConnected方法, 即只有当isClose返回false,isConnected返回true的时候Socket对象才处于连接状态。 虽然在大多数的时候可以直接使用Socket类或输入输出流的close方法关闭网络连接,但有时我们只希望关闭OutputStream或InputStream,而在关闭输入输出流的同时,并不关闭网络连接。这就需要用到Socket类的另外两个方法:shutdownInput和shutdownOutput,这两个方法只关闭相应的输入、输出流,而它们并没有同时关闭网络连接的功能。和isClosed、isConnected方法一样,Socket类也提供了两个方法来判断Socket对象的输入、输出流是否被关闭,这两个方法是isInputShutdown()和isOutputShutdown()。 shutdownInput和shutdownOutput并不影响Socket对象的状态。