Socket的使用和原理
socket套接字本來(lái)是設(shè)計(jì)給基于TCP/IP協(xié)議的網(wǎng)絡(luò)通信使用的,但由于它是一種C/S架構(gòu)模型,即客戶(hù)端服務(wù)器端架構(gòu),這種模型能帶來(lái)很大的安全性以及快速的響應(yīng)能力,所以也常常用在進(jìn)程之間的通信上。
Socket的使用方式比上面前面提到的其他IPC都要復(fù)雜很多,我們先通過(guò)下圖了解它的使用流程。

我們?cè)诳纯淳唧w的函數(shù)
#include <sys/socket.h>
#include <unistd.h>
#include <unistd.h>
int socket(int protofamily, int type, int protocol);//創(chuàng)建socket
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//綁定socket
int listen(int sockfd, int backlog);//監(jiān)聽(tīng)端口號(hào)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//客戶(hù)端請(qǐng)求建立連接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//服務(wù)端接收連接請(qǐng)求
ssize_t send(int sockfd, const void *buf, size_t len, int flags); //IO寫(xiě)函數(shù)
ssize_t recv(int sockfd, void *buf, size_t len, int flags);//IO讀函數(shù)
int close(int fd); //關(guān)閉函數(shù)
Linux系統(tǒng)中萬(wàn)物皆文件,所以Socket也是一個(gè)虛擬文件,socket文件的數(shù)據(jù)結(jié)構(gòu)中包含了當(dāng)前主機(jī)的ip地址,當(dāng)前主機(jī)進(jìn)程的端口號(hào),發(fā)送端主機(jī)的ip地址等信息,通過(guò)這些信息,我們可以在虛擬文件系統(tǒng)中唯一定位到一個(gè)Socket文件,通過(guò)對(duì)這個(gè)文件的讀寫(xiě)達(dá)到通信的目的。
Socket在Android系統(tǒng)中的使用場(chǎng)景
當(dāng)我們使用socket來(lái)進(jìn)行進(jìn)程間的通信時(shí),實(shí)際是通過(guò)將IP設(shè)置為127.0.0.1這個(gè)本地IP來(lái)實(shí)現(xiàn)的,Android系統(tǒng)為我們提供了LocalSocket來(lái)進(jìn)行進(jìn)程間的通信,LocalSocket的實(shí)質(zhì)也是對(duì)Socket的封裝,通過(guò)直接使用LocalSocket,我們省掉了設(shè)置本機(jī)IP等一系列繁瑣的操作。
我們看一個(gè)LocalSocket的使用場(chǎng)景:當(dāng)我們啟動(dòng)一個(gè)App應(yīng)用時(shí),如果當(dāng)前的應(yīng)用的進(jìn)程不存在,AMS會(huì)通過(guò)Socket通知Zygote去Fork新進(jìn)程。
//文件-->frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// 服務(wù)端
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
……
zygoteServer.registerServerSocket(socketName);
……
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
……
}
ZygoteInit啟動(dòng)時(shí),會(huì)創(chuàng)建一個(gè)ZygoteServer,然后fork生成System Server進(jìn)程,接著啟動(dòng)整個(gè)Framwork的Server,最終執(zhí)行zygoteServer的runSelectLoop函數(shù),始終等待其他進(jìn)程發(fā)送過(guò)來(lái)的fork進(jìn)程的消息。
我們接著看registerServerSocket函數(shù)和runSelectLoop函數(shù)的實(shí)現(xiàn)
//文件-->/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
?
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
?
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
?
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
可以看到registerServerSocket函數(shù)實(shí)際是創(chuàng)建了LocalServerSocket,這個(gè)LocalServerSocket的名字就叫“zygote”,runSelectLoop函數(shù)將ServerSocket加入多路復(fù)用模型里,當(dāng)收到消息時(shí)便調(diào)用runOnce方法去fork進(jìn)程。
//文件-->/frameworks/base/core/java/android/os/Process.java
//客戶(hù)端
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
?
//文件-->/frameworks/base/core/java/android/os/ZygoteProcess.jav
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
?
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
……
synchronized(mLock) {
//連接服務(wù)端socket,并發(fā)送數(shù)據(jù)
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
?
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
……
}
?
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
?
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
?
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
?
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
?
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
?
writer.write(Integer.toString(args.size()));
writer.newLine();
?
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
?
writer.flush();
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
?
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
}
從上面的代碼實(shí)現(xiàn)可以看到,當(dāng)AMS調(diào)用Process的start()函數(shù)時(shí),最終執(zhí)行到了ZygoteProcess類(lèi)中的openZygoteSocketIfNeeded() 函數(shù),連接socket,然后調(diào)用zygoteSendArgsAndGetResult() 函數(shù)通過(guò)LocalSocket 往LocalServerSocket發(fā)送消息 。