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://blog.csdn.net/fangchongbory/article/details/7585917