Android 之 Socket通信

来源:互联网 发布:域名申请的步骤包括 编辑:程序博客网 时间:2024/05/29 17:21

Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄。应用程序通常通过“套接字”向网络发送请求或者应答网络请求

一个客户端要发起一次通信,首先必须知道运行服务器端的主机IP地址和通信端口。然后由网络基础设施利用目标地址,将客户端发送的信息传递到正确的主机上,在Java中,地址可以由字符串来定义,字符串可以使数字型的地址(比如192.168.1.108),也可以是主机名,端口为6000

下面实现一个例子,手机为客户端,PC机(linux系统)为服务器,手机和服务器约定一个端口号6000.手机通过socket向服务器发送命令,服务器监听约定的端口号6000,接收来自客户端的socket套接字,执行命令,并将命令返回给手机客户端。手机客户端接收服务器返回的消息,并将消息显示出来。从而实现从手机端发送服务器发送命令,并显示服务器端执行命令后的结果。采用这种方法,可以使用手机控制服务器的运行,譬如重启,关机,查看文件等。

实例:

服务器端

[java] view plaincopyprint?
  1. package com.android.server;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.BufferedWriter;  
  5. import java.io.IOException;  
  6. import java.io.InputStreamReader;  
  7. import java.io.OutputStreamWriter;  
  8. import java.net.ServerSocket;  
  9. import java.net.Socket;  
  10. import java.io.LineNumberReader;  
  11.   
  12. public class Server extends Thread {  
  13.   
  14.     private ServerSocket server = null;  
  15.     private static final int PORT = 6000;  
  16.     private BufferedWriter writer;  
  17.     private BufferedReader reader;  
  18.   
  19.     private Server() throws IOException {  
  20.         // 创建Socket服务器  
  21.         CreateSocket();  
  22.     }  
  23.   
  24.     public void run() {  
  25.         Socket client;  
  26.         String txt;  
  27.         try {  
  28.             // 线程无限循环,实时监听socket端口  
  29.             while (true){  
  30.                 client = ResponseSocket();  
  31.                   
  32.                 // 响应客户端链接请求。。  
  33.                 while (true) {  
  34.                     txt = ReceiveMsg(client);  
  35.                     // 链接获得客户端发来的命令  
  36.                     System.out.println(txt);  
  37.                     if (txt != null) {  
  38.                         // 执行命令  
  39.                         txt = exceCommand(txt);  
  40.                     }  
  41.                     // 向客户端返回消息  
  42.                     SendMsg(client, txt);  
  43.                     // 中断,关闭此次连接  
  44.                     break;  
  45.                 }  
  46.                 CloseSocket(client);  
  47.             }  
  48.         } catch (IOException e) {  
  49.             System.out.println(e);  
  50.         }  
  51.   
  52.     }  
  53.   
  54.     //创建一个ServerSocket实例,绑定到一个特定的端口。一个服务器端口最多可以支持50个链接,超出了则拒绝链接。  
  55.     //所以,最多只能有50个客户端同时使用这个指定的端口向服务器发送消息  
  56.     private void CreateSocket() throws IOException {  
  57.         server = new ServerSocket(PORT);  
  58.         System.out.println("Server starting..");  
  59.     }  
  60.   
  61.     /* 
  62.     ServerSocket:这个类是实现了一个服务器端的Socket,利用这个类可以监听来自网络的请求。 
  63.     1、创建ServerSocket的方法: 
  64.         ServerSocket(Int localPort) 
  65.         ServerSocket(int localport,int queueLimit) 
  66.         ServerSocket(int localport,int queueLimit,InetAddress localAddr) 
  67.         创建一个ServerSocket必须指定一个端口,以便客户端能够向该端口号发送连接请求。端口的有效范围是0-65535 
  68.   2、ServerSocket操作 
  69.         Socket accept() 
  70.         void close 
  71.         accept()方法为下一个传入的连接请求创建Socket实例,并将已成功连接的Socket实例返回给服务器套接字,如果没有连接请求, 
  72.         accept()方法将阻塞等待; 
  73.         close方法用于关闭套接字 
  74.      */  
  75.     private Socket ResponseSocket() throws IOException {  
  76.         Socket client = server.accept();  
  77.         System.out.println("client connected..");  
  78.         return client;  
  79.     }  
  80.   
  81.     //关闭socket  
  82.     private void CloseSocket(Socket socket) throws IOException {  
  83.         reader.close();  
  84.         writer.close();  
  85.         socket.close();  
  86.         System.out.println("client closed..");  
  87.     }  
  88.   
  89.     //向客户端发送消息  
  90.     private void SendMsg(Socket socket, String Msg) throws IOException {  
  91.         writer = new BufferedWriter(new OutputStreamWriter(  
  92.                 socket.getOutputStream()));  
  93.         writer.write(Msg + "\n");  
  94.         writer.flush();  
  95.     }  
  96.   
  97.     //接收来自客户端的消息。服务器通过server.accept();接收来自客户端的套接字,采用I/O方式  
  98.     //将套接字的消息取出来  
  99.     private String ReceiveMsg(Socket socket) throws IOException {  
  100.         reader = new BufferedReader(new InputStreamReader(  
  101.                 socket.getInputStream()));  
  102.         System.out.println("server get input from client socket..");  
  103.         String line = null;  
  104.         while ((line = reader.readLine()) != null) {  
  105.             System.out.println(line);  
  106.             return line;  
  107.         }  
  108.         return line;  
  109.     }  
  110.   
  111.     //执行客户端发送来的命令。服务器将在本机执行客户端发送过来的消息(命令)。  
  112.     //并返回执行命令后,服务器返回的结果。譬如,在linux下执行“ls”命令,返回的是当前目录  
  113.     //下面的所有文件的名称  
  114.     private String exceCommand(String command) {  
  115.         String msg = "";  
  116.         try {  
  117.             //Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()  
  118.             //方法指示Java虚拟机创建一个子进程执行指定的可执行程序(命令),并返回与该子进程对应的Process对象实例。  
  119.             //通过Process可以控制该子进程的执行或获取该子进程的信息  
  120.               
  121.             Process process = Runtime.getRuntime().exec(command);  
  122.             InputStreamReader ir = new InputStreamReader(  
  123.                     process.getInputStream());  
  124.             LineNumberReader input = new LineNumberReader(ir);  
  125.             String line;  
  126.             while ((line = input.readLine()) != null) {  
  127.                 System.out.println(line);  
  128.                 msg += line + "\n";  
  129.             }  
  130.   
  131.         } catch (java.io.IOException e) {  
  132.             System.err.println("IOException " + e.getMessage());  
  133.         }  
  134.    
  135.         return msg;  
  136.     }  
  137.   
  138.     public static void main(final String args[]) throws IOException {  
  139.           
  140.         Server commandServer = new Server();  
  141.         if (commandServer != null) {  
  142. //          commandServer.stop();  
  143.             commandServer.start();  
  144.         }  
  145.     }  
  146.   
  147. }  

手机客户端:

[java] view plaincopyprint?
  1. package com.control;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.BufferedWriter;  
  5. import java.io.IOException;  
  6. import java.io.InputStreamReader;  
  7. import java.io.OutputStreamWriter;  
  8. import java.net.InetSocketAddress;  
  9. import java.net.Socket;  
  10. import java.net.UnknownHostException;  
  11.   
  12. import android.app.Activity;  
  13. import android.app.AlertDialog;  
  14. import android.content.Context;  
  15. import android.content.DialogInterface;  
  16. import android.content.SharedPreferences;  
  17. import android.os.Bundle;  
  18. import android.os.Handler;  
  19. import android.os.Message;  
  20. import android.text.TextUtils;  
  21. import android.text.method.ScrollingMovementMethod;  
  22. import android.util.Log;  
  23. import android.view.KeyEvent;  
  24. import android.view.Menu;  
  25. import android.view.MenuItem;  
  26. import android.view.View;  
  27. import android.widget.Button;  
  28. import android.widget.EditText;  
  29. import android.widget.TextView;  
  30.   
  31. public class ControlActivity extends Activity {  
  32.     //服务器ip地址  
  33.     public static final String DEFULT_PRES = "192.168.1.108";  
  34.     public static final String PREFS_NAME = "PreferencesFile";  
  35.     public static final int CONNENTED = 0;  
  36.     public static final int UPDATALOG = 1;  
  37.       
  38.     private static final int PORT = 6000;  
  39.       
  40.     private EditText command;  
  41.     private EditText ipEdit;  
  42.     private TextView log;  
  43.     private Button send;  
  44.     private Button clean;  
  45.     private String ip;  
  46.     private String logMsg;  
  47.     private Socket socket;  
  48.     private BufferedWriter writer;  
  49.     private InetSocketAddress isa = null;  
  50.     Context mContext;  
  51.   
  52.     public void onCreate(Bundle savedInstanceState) {  
  53.         super.onCreate(savedInstanceState);  
  54.         setContentView(R.layout.main);  
  55.         mContext = this;  
  56.         findviews();  
  57.         setonclick();  
  58.         init();  
  59.     }  
  60.   
  61.     public void findviews() {  
  62.         command = (EditText) this.findViewById(R.id.command);  
  63.         log = (TextView) this.findViewById(R.id.log);  
  64.         send = (Button) this.findViewById(R.id.send);  
  65.         ipEdit = (EditText) this.findViewById(R.id.ipEdit);  
  66.         clean = (Button) this.findViewById(R.id.clean);  
  67.     }  
  68.   
  69.     private void init() {  
  70.         log.setMovementMethod(ScrollingMovementMethod.getInstance());  
  71.         logMsg = log.getText().toString();  
  72.         //创建一个socket实例  
  73.         socket = new Socket();  
  74.         ip = onLoad();  
  75.         if (ip != null) {  
  76.             ipEdit.setText(ip);  
  77.         }  
  78.     }  
  79.   
  80.     private void setonclick() {  
  81.         send.setOnClickListener(new View.OnClickListener() {  
  82.             public void onClick(View v) {  
  83.                 ip = ipEdit.getText().toString();  
  84.                 //当点击发送按钮时,开启一个tcpClient线程,向服务器发送消息  
  85.                 tcpClient tcp = new tcpClient(command.getText().toString());  
  86.                 tcp.start();  
  87.             }  
  88.         });  
  89.   
  90.         clean.setOnClickListener(new Button.OnClickListener() {  
  91.             public void onClick(View v) {  
  92.                 // TODO Auto-generated method stub  
  93.                 logMsg = "";  
  94.                 log.setText(logMsg);  
  95.             }  
  96.         });  
  97.     }  
  98.   
  99.     //在向服务器发送消息之前,必须先链接到服务器。  
  100.     public void connecttoserver() throws UnknownHostException, IOException {  
  101.         socket = RequestSocket(ip, PORT);  
  102.         //判断是否链接成功  
  103.         if (socket.isConnected()) {  
  104.             Message msg = new Message();  
  105.             msg.what = CONNENTED;  
  106.             mHandler.sendMessage(msg);  
  107.         }  
  108.     }  
  109.   
  110.     //链接服务器  
  111.     private Socket RequestSocket(String host, int port)  
  112.             throws UnknownHostException, IOException {  
  113.         Socket ConSocket = new Socket();  
  114.         //创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。  
  115.         //有效端口值介于 0 和 65535 之间。端口号 zero 允许系统在 bind 操作中挑选暂时的端口。   
  116.         isa = new InetSocketAddress(host, port);  
  117.         //建立一个远程链接  
  118.         ConSocket.connect(isa);  
  119.           
  120.         return ConSocket;  
  121.     }  
  122.   
  123.     //向服务器发送信息  
  124.     private void SendMsg(Socket socket, String msg) throws IOException {  
  125.         writer = new BufferedWriter(new OutputStreamWriter(  
  126.                 socket.getOutputStream()));  
  127.   
  128.         Log.i("msg", msg.replace("\n"" ") + "\n");  
  129.         writer.write(msg.replace("\n"" ") + "\n");  
  130.         writer.flush();  
  131.     }  
  132.   
  133.     // 接收服务器信息  
  134.     private String ReceiveMsg(Socket socket) throws IOException {  
  135.         BufferedReader reader = new BufferedReader(new InputStreamReader(  
  136.                 socket.getInputStream()));  
  137.         String line;  
  138.         String txt = "";  
  139.         while ((line = reader.readLine()) != null) {  
  140.             txt += line + "\n";  
  141.         }  
  142.         reader.close();  
  143.         return txt;  
  144.   
  145.     }  
  146.   
  147.     class tcpClient extends Thread {  
  148.         String commandString;  
  149.   
  150.         public tcpClient() {  
  151.             commandString = "ls";  
  152.         }  
  153.   
  154.         public tcpClient(String command) {  
  155.             commandString = command;  
  156.         }  
  157.   
  158.         public void run() {  
  159.             String recv;  
  160.             try {  
  161.                 connecttoserver();  
  162.                 //向服务器发送命令  
  163.                 SendMsg(socket, commandString);  
  164.                 //等待,接收来自服务器返回的消息  
  165.                 recv = ReceiveMsg(socket);  
  166.                 if (recv != null) {  
  167.                     logMsg += recv;  
  168.                     // close BufferedWriter and socket  
  169.                     writer.close();  
  170.                     socket.close();  
  171.                     // 将服务器返回的消息显示出来  
  172.                     Message msg = new Message();  
  173.                     msg.what = UPDATALOG;  
  174.                     mHandler.sendMessage(msg);  
  175.                 }  
  176.             } catch (UnknownHostException e) {  
  177.                 e.printStackTrace();  
  178.             } catch (IOException e) {  
  179.                 e.printStackTrace();  
  180.             }  
  181.         }  
  182.     }  
  183.   
  184.     private String onLoad() {  
  185.         SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);  
  186.         String mPreferences = settings.getString("preferences", DEFULT_PRES);  
  187.         return mPreferences;  
  188.     }  
  189.   
  190.     private void onSave(String save) {  
  191.         if (TextUtils.isEmpty(save)) {  
  192.             setPreferences(DEFULT_PRES);  
  193.         } else {  
  194.             setPreferences(save);  
  195.         }  
  196.     }  
  197.   
  198.     private void setPreferences(String mPreferences) {  
  199.         SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);  
  200.         SharedPreferences.Editor editor = settings.edit();  
  201.         editor.putString("preferences", mPreferences);  
  202.         editor.commit();  
  203.     }  
  204.   
  205.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  206.         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {  
  207.             AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  208.             builder.setTitle("PC Control");  
  209.             builder.setMessage("exit ?");  
  210.             builder.setPositiveButton("Yes",  
  211.                     new DialogInterface.OnClickListener() {  
  212.                         public void onClick(DialogInterface dialog, int which) {  
  213.                             onSave(ipEdit.getText().toString());  
  214.                             finish();  
  215.                         }  
  216.                     });  
  217.             builder.setNegativeButton("Cancel",  
  218.                     new DialogInterface.OnClickListener() {  
  219.                         public void onClick(DialogInterface dialog, int which) {  
  220.   
  221.                         }  
  222.                     });  
  223.             builder.show();  
  224.         }  
  225.         return super.onKeyDown(keyCode, event);  
  226.     }  
  227.   
  228.     public boolean onCreateOptionsMenu(Menu menu) {  
  229.         menu.add(011"关机");  
  230.         menu.add(022"重启");  
  231.         menu.add(033"退出");  
  232.         return super.onCreateOptionsMenu(menu);  
  233.     }  
  234.   
  235.     public boolean onOptionsItemSelected(MenuItem item) {  
  236.         switch (item.getItemId()) {  
  237.         case 1:  
  238.             tcpClient tcp = new tcpClient("sudo poweroff");  
  239.             tcp.start();  
  240.             return true;  
  241.         case 2:  
  242.             tcp = new tcpClient("sudo reboot");  
  243.             tcp.start();  
  244.             return true;  
  245.         case 3:  
  246.             finish();  
  247.             break;  
  248.         }  
  249.         return super.onOptionsItemSelected(item);  
  250.     }  
  251.   
  252.     Handler mHandler = new Handler() {  
  253.         public void handleMessage(Message msg) {  
  254.             switch (msg.what) {  
  255.   
  256.             case CONNENTED:  
  257.                 logMsg += "Server Connented\n";  
  258.                 log.setText(logMsg);  
  259.                 break;  
  260.   
  261.             case UPDATALOG:  
  262.                 log.setText(logMsg);  
  263.                 log.setScrollContainer(true);  
  264.                 break;  
  265.             }  
  266.         }  
  267.     };  
  268. }  

并记得在 AndroidManifest.xml注册权限

[html] view plaincopyprint?
  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  

好了,大家可以在自己电脑上试试,有什么问题,大家交流一下,彼此学习!