Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄。应用程序通常通过“套接字”向网络发送请求或者应答网络请求
一个客户端要发起一次通信,首先必须知道运行服务器端的主机IP地址和通信端口。然后由网络基础设施利用目标地址,将客户端发送的信息传递到正确的主机上,在Java中,地址可以由字符串来定义,字符串可以使数字型的地址(比如192.168.1.108),也可以是主机名,端口为6000
下面实现一个例子,手机为客户端,PC机(linux系统)为服务器,手机和服务器约定一个端口号6000.手机通过socket向服务器发送命令,服务器监听约定的端口号6000,接收来自客户端的socket套接字,执行命令,并将命令返回给手机客户端。手机客户端接收服务器返回的消息,并将消息显示出来。从而实现从手机端发送服务器发送命令,并显示服务器端执行命令后的结果。采用这种方法,可以使用手机控制服务器的运行,譬如重启,关机,查看文件等。
实例:
服务器端
package com.android.server; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.io.LineNumberReader; public class Server extends Thread { private ServerSocket server = null; private static final int PORT = 6000; private BufferedWriter writer; private BufferedReader reader; private Server() throws IOException { // 创建Socket服务器 CreateSocket(); } public void run() { Socket client; String txt; try { // 线程无限循环,实时监听socket端口 while (true){ client = ResponseSocket(); // 响应客户端链接请求。。 while (true) { txt = ReceiveMsg(client); // 链接获得客户端发来的命令 System.out.println(txt); if (txt != null) { // 执行命令 txt = exceCommand(txt); } // 向客户端返回消息 SendMsg(client, txt); // 中断,关闭此次连接 break; } CloseSocket(client); } } catch (IOException e) { System.out.println(e); } } //创建一个ServerSocket实例,绑定到一个特定的端口。一个服务器端口最多可以支持50个链接,超出了则拒绝链接。 //所以,最多只能有50个客户端同时使用这个指定的端口向服务器发送消息 private void CreateSocket() throws IOException { server = new ServerSocket(PORT); System.out.println("Server starting.."); } /* ServerSocket:这个类是实现了一个服务器端的Socket,利用这个类可以监听来自网络的请求。 1、创建ServerSocket的方法: ServerSocket(Int localPort) ServerSocket(int localport,int queueLimit) ServerSocket(int localport,int queueLimit,InetAddress localAddr) 创建一个ServerSocket必须指定一个端口,以便客户端能够向该端口号发送连接请求。端口的有效范围是0-65535 2、ServerSocket操作 Socket accept() void close accept()方法为下一个传入的连接请求创建Socket实例,并将已成功连接的Socket实例返回给服务器套接字,如果没有连接请求, accept()方法将阻塞等待; close方法用于关闭套接字 */ private Socket ResponseSocket() throws IOException { Socket client = server.accept(); System.out.println("client connected.."); return client; } //关闭socket private void CloseSocket(Socket socket) throws IOException { reader.close(); writer.close(); socket.close(); System.out.println("client closed.."); } //向客户端发送消息 private void SendMsg(Socket socket, String Msg) throws IOException { writer = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())); writer.write(Msg + "\n"); writer.flush(); } //接收来自客户端的消息。服务器通过server.accept();接收来自客户端的套接字,采用I/O方式 //将套接字的消息取出来 private String ReceiveMsg(Socket socket) throws IOException { reader = new BufferedReader(new InputStreamReader( socket.getInputStream())); System.out.println("server get input from client socket.."); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); return line; } return line; } //执行客户端发送来的命令。服务器将在本机执行客户端发送过来的消息(命令)。 //并返回执行命令后,服务器返回的结果。譬如,在linux下执行“ls”命令,返回的是当前目录 //下面的所有文件的名称 private String exceCommand(String command) { String msg = ""; try { //Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec() //方法指示Java虚拟机创建一个子进程执行指定的可执行程序(命令),并返回与该子进程对应的Process对象实例。 //通过Process可以控制该子进程的执行或获取该子进程的信息 Process process = Runtime.getRuntime().exec(command); InputStreamReader ir = new InputStreamReader( process.getInputStream()); LineNumberReader input = new LineNumberReader(ir); String line; while ((line = input.readLine()) != null) { System.out.println(line); msg += line + "\n"; } } catch (java.io.IOException e) { System.err.println("IOException " + e.getMessage()); } return msg; } public static void main(final String args[]) throws IOException { Server commandServer = new Server(); if (commandServer != null) { // commandServer.stop(); commandServer.start(); } } }
手机客户端:
package com.control; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class ControlActivity extends Activity { //服务器ip地址 public static final String DEFULT_PRES = "192.168.1.108"; public static final String PREFS_NAME = "PreferencesFile"; public static final int CONNENTED = 0; public static final int UPDATALOG = 1; private static final int PORT = 6000; private EditText command; private EditText ipEdit; private TextView log; private Button send; private Button clean; private String ip; private String logMsg; private Socket socket; private BufferedWriter writer; private InetSocketAddress isa = null; Context mContext; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mContext = this; findviews(); setonclick(); init(); } public void findviews() { command = (EditText) this.findViewById(R.id.command); log = (TextView) this.findViewById(R.id.log); send = (Button) this.findViewById(R.id.send); ipEdit = (EditText) this.findViewById(R.id.ipEdit); clean = (Button) this.findViewById(R.id.clean); } private void init() { log.setMovementMethod(ScrollingMovementMethod.getInstance()); logMsg = log.getText().toString(); //创建一个socket实例 socket = new Socket(); ip = onLoad(); if (ip != null) { ipEdit.setText(ip); } } private void setonclick() { send.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { ip = ipEdit.getText().toString(); //当点击发送按钮时,开启一个tcpClient线程,向服务器发送消息 tcpClient tcp = new tcpClient(command.getText().toString()); tcp.start(); } }); clean.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub logMsg = ""; log.setText(logMsg); } }); } //在向服务器发送消息之前,必须先链接到服务器。 public void connecttoserver() throws UnknownHostException, IOException { socket = RequestSocket(ip, PORT); //判断是否链接成功 if (socket.isConnected()) { Message msg = new Message(); msg.what = CONNENTED; mHandler.sendMessage(msg); } } //链接服务器 private Socket RequestSocket(String host, int port) throws UnknownHostException, IOException { Socket ConSocket = new Socket(); //创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。 //有效端口值介于 0 和 65535 之间。端口号 zero 允许系统在 bind 操作中挑选暂时的端口。 isa = new InetSocketAddress(host, port); //建立一个远程链接 ConSocket.connect(isa); return ConSocket; } //向服务器发送信息 private void SendMsg(Socket socket, String msg) throws IOException { writer = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())); Log.i("msg", msg.replace("\n", " ") + "\n"); writer.write(msg.replace("\n", " ") + "\n"); writer.flush(); } // 接收服务器信息 private String ReceiveMsg(Socket socket) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader( socket.getInputStream())); String line; String txt = ""; while ((line = reader.readLine()) != null) { txt += line + "\n"; } reader.close(); return txt; } class tcpClient extends Thread { String commandString; public tcpClient() { commandString = "ls"; } public tcpClient(String command) { commandString = command; } public void run() { String recv; try { connecttoserver(); //向服务器发送命令 SendMsg(socket, commandString); //等待,接收来自服务器返回的消息 recv = ReceiveMsg(socket); if (recv != null) { logMsg += recv; // close BufferedWriter and socket writer.close(); socket.close(); // 将服务器返回的消息显示出来 Message msg = new Message(); msg.what = UPDATALOG; mHandler.sendMessage(msg); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } private String onLoad() { SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); String mPreferences = settings.getString("preferences", DEFULT_PRES); return mPreferences; } private void onSave(String save) { if (TextUtils.isEmpty(save)) { setPreferences(DEFULT_PRES); } else { setPreferences(save); } } private void setPreferences(String mPreferences) { SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putString("preferences", mPreferences); editor.commit(); } public boolean onKeyDown(int keyCode, KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("PC Control"); builder.setMessage("exit ?"); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { onSave(ipEdit.getText().toString()); finish(); } }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }); builder.show(); } return super.onKeyDown(keyCode, event); } public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 1, 1, "关机"); menu.add(0, 2, 2, "重启"); menu.add(0, 3, 3, "退出"); return super.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 1: tcpClient tcp = new tcpClient("sudo poweroff"); tcp.start(); return true; case 2: tcp = new tcpClient("sudo reboot"); tcp.start(); return true; case 3: finish(); break; } return super.onOptionsItemSelected(item); } Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case CONNENTED: logMsg += "Server Connented\n"; log.setText(logMsg); break; case UPDATALOG: log.setText(logMsg); log.setScrollContainer(true); break; } } }; }
并记得在 AndroidManifest.xml注册权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
好了,大家可以在自己电脑上试试,有什么问题,大家交流一下,彼此学习!
原文来自 http://www.eoeandroid.com/thread-148913-1-1.html