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" />
好了,大家可以在自己电脑上试试,有什么问题,大家交流一下,彼此学习!