Android端Socket服务器
/**
* Created by Jack Stone on 2016/11/17.
* Socket服务器,PC可以通过USB连接、ADB端口映射连接本服务器,不需要通过Wifi和网络
*/
public class TCPConnect implements Runnable {
private static final String TAG = "TCPConnect";
private final int SERVER_PORT = 10086;
private ServerSocket mServerSocket;
private Socket mClient;
private Callback callback;
public TCPConnect(Callback callback) {
this.callback = callback;
}
@Override
public void run() {
try {
String ip = InetAddress.getLocalHost().getHostAddress();
mServerSocket = new ServerSocket(SERVER_PORT);
callback.call("建立服务器:[" + ip + ":" + SERVER_PORT + "]");
} catch (IOException e) {
callback.call("建立服务器异常:" + e.getMessage());
}
while (true) {
BufferedOutputStream out = null;
BufferedReader in = null;
try {
mClient = mServerSocket.accept();
callback.call("建立链接:" + mClient.getInetAddress().toString() + ":" + mClient.getPort());
out = new BufferedOutputStream(mClient.getOutputStream());
in = new BufferedReader(new InputStreamReader(mClient.getInputStream()));
String request = receive(in);
callback.call("client:"+request);
send(out, request);
} catch (IOException e) {
Log.e(TAG, "run: ", e);
callback.call(e.getMessage());
} finally {
close(out);
close(in);
close(mClient);
}
}
}
private void send(OutputStream out, String msg) throws IOException {
msg += "\n";
out.write(msg.getBytes("utf-8"));
}
private String receive(BufferedReader in) throws IOException {
String r = in.readLine();
callback.call("origin request:"+r);
if(r.contains("\\&")) {
callback.call("进行\\&替换!");
r = r.replaceAll("\\\\&","\n");
}
return r;
}
private void close(OutputStream out) {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void close(BufferedReader in) {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void close(Socket socket) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "run: ", e);
}
}
}
public interface Callback {
void call(String msg);
}
}
using CMDExecutor;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
namespace AndroidUSBSocket
{
public class SocketClient
{
public const string LOCAL_PORT = "12580";
public SocketClient(string adb_path, string remote_port)
{
AdbExecutor adb = AdbExecutor.GetInstance(adb_path);
adb.Forward(LOCAL_PORT, remote_port);
}
public string Request(string msg)
{
Socket client = null;
try
{
client = create();
connect(client, LOCAL_PORT);
if (client.Connected)
{
send(client, msg);
return receive(client);
}
else
{
return "连接失败!";
}
}
catch(Exception e)
{
return $"Error:{e.Message}";
}
finally
{
client.Shutdown(SocketShutdown.Both);
client?.Close();
Request(msg);
}
}
private static void connect(Socket socket,string port)
{
IPAddress myIP = IPAddress.Parse("127.0.0.1");
IPEndPoint EPhost = new IPEndPoint(myIP, int.Parse(port));
socket.Connect(EPhost); //create connection
}
private static Socket create()
{
return new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
}
private static void send(Socket socket, string msg)
{
//request
msg = msg.Replace("\n", "\\&"); //replace all '\n' to '\&', those will be replace to '\n' when server received this msg
msg += "\n"; //server is using readLine(), if not send a '\n' the stream won't push data to server
byte[] data = Encoding.UTF8.GetBytes(msg);
socket.Send(data); //send message to server
//socket.Shutdown(SocketShutdown.Send); //N-E-V-E-R close output stream, the socket will be closed together
Debug.WriteLine($"发送完毕(长度[{msg.Length}] 字节[{data.Length}]):\n{msg}");
}
private static string receive(Socket socket)
{
//get response
string str = "";
byte[] data = new byte[10240];
int len = 0;
int i = 0;
while ((i = socket.Receive(data)) != 0) //read response string
{
len += i;
string piece = Encoding.UTF8.GetString(data, 0, i);
str += piece;
}
Debug.WriteLine($"接收完毕(长度[{str.Length}] 字节[{len}]):\n{str}");
return str;
}
}
}
使用ADB进行端口的映射转发:adb forward tcp:local_port tcp:remote_port
SocketClient构造中的ADBExecutor就是用来执行这个命令的
另外有一点不明白的是 SocketClient的receive方法中,byte[]的size我定的是10240
因为如果定小了,在获取字符串的过程中就会因为这个尺寸不合适导致在边界上的字符变成???
C#不是很熟悉,这个地方不知道该怎么做,索性把size定得大一点,一般用不了这么长的字节数组
使用这个方法要注意的是,只能通过PC主动向Android端发起请求,看了很多文档,貌似Android端是不能主动请求PC的,这个好像跟ADB的机制有关
但是ADB我并不是理解得特别清楚,所以如果有大神知道如何让Android端主动请求PC端的服务器的话,希望不吝赐教!
有一个帖子说,Android通过USB连接电脑后,默认电脑的IP就是10.0.2.2,我试了一下,没啥成果,如果有人成功请联系我。
其他需要注意的地方在代码中的注释我都清楚地写出来了,欢迎交流。