现在的位置: 首页 > 综合 > 正文

Android 之 Socket通信

2013年08月26日 ⁄ 综合 ⁄ 共 9204字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.