try { LocalServerSocket loc = new LocalServerSocket("hello_world"); Log.e("test", "myView, Socket Start"); } catch (IOException e) { Log.e("test", "myView," + e.toString()); }
如果在另外一个app中已经创建了这个 "hello_world" 的 LocalServerSocket, 这里再创建会抛异常:java.io.IOException: Address already in use
一 Socket
Socket最初用在基于TCP/IP网络间进程通信中,以客户端/服务器模式进行通信。
实现异步操作,共享资源集中处理,提高客户端响应能力。
Tcp通信基本流程:
服务器端 客户端
1.创建socket 1.创建socket
2.bind()
3.listen()
4.accecp()
----等待客户端连接---- 2.connect()
5.读数据(recv) 3.写数据(send)
6.写数据(send) 4.读数据(recv)
7.关闭socket(closesocket()) 5.关闭socket(closesocket())
数据流:
二 Android LocalSocket
LocalSocket
在Unix域名空间创建一个套接字(非服务端)。
是对Linux中Socket进行了封装,采用JNI方式调用,实现进程间通信。
具体就是Native层Server和Framework层Client之间进行通信,或在各层次中能使用Client/Server模式实现通信。
LocalServerSocket
创建服务器端Unix域套接字,与LocalSocket对应。
LocalSocketImpl
Framework层Socket的实现,通过JNI调用系统socket API。
LocalSocketAddress
Unix域socket的地址以及所处的空间。
JNI访问接口:\frameworks\base\core\jni\android_net_LocalSocketImpl.cpp
socket_create
socket_connect_local
socket_bind_local
socket_listen
……
下面看看这几个类之间的关系:
使用Android的LocalSocket建立socket通信,是基于网络socket过程一致的。
三 native与framework之间的通信
以install这个服务为例:
1 增加socket资源
\system\core\rootdir\init.rc中:
service installd /system/bin/installd
class main
socket installd stream 600 system system
在启动install服务时,就会为install分配socket文件系统资源:dev/socket/installd
Install服务的Socket资源和名称installd绑定起来。
这些都是在开机初始化化init进程中启动service时完成:
service_start
create_socket
publish_socket
2 native层
install进程 建立服务端程序
native 层中作为server:\frameworks\base\cmds\installd\installd.c
int main(const int argc, const char *argv[])
{
//获取已绑定socket
lsocket = android_get_control_socket(SOCKET_PATH);
//监听socket
listen(lsocket, 5);
for (;;) {
//等待客户端建立连接
s = accept(lsocket, &addr, &alen);
for (;;) {
//接收数据 相当于recv
readx(s, buf, count);
//执行相关的操作
execute(s, buf);
}
//关闭socket
close(s);
}
}
3 framework层
客户端程序:
\frameworks\base\services\java\com\android\server\pm\Installer.java
boolean connect()
{
//创建socket
mSocket = new LocalSocket();
//设置连接地址
LocalSocketAddress address = new LocalSocketAddress("installd",
LocalSocketAddress.Namespace.RESERVED);
//建立连接
mSocket.connect(address);
//获取数据输入流 可以读数据
mIn = mSocket.getInputStream();
//获取数据输出流 可以写数据
mOut = mSocket.getOutputStream();
}
因此以native层service与framework建立client/server模式socket通信主要代码:
java层主要代码:
LocalSocket s =null;
LocalSocketAddress l;
s = new LocalSocket();
l = new LocalSocketAddress(SOCKET_NAME,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
native层主要代码:
s_fdListen = android_get_control_socket(SOCKET_NAME);
ret = listen(s_fdListen, n);
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
init.rc中加入:
service myserver /system/bin/myserver
class main
socket myserver stream 600 system system
……
当然建立这种client/server模式并不一定要在native层和framework层,仅在framework层也能够进行。
系统提供了LocalSocket作为客户端使用,同时提供了LocalServerSocket作为服务端使用。
Zygote服务使用了LocalServerSocket作为服务端socket通信。
建立socket通信,也可以在代码执行过程中进行,使用LocalSocket与LocalServerSocket。
在init.rc中为服务端建立的socket资源和初始化时绑定,与在代码中使用LocalServerSocket
建立的服务端socket资源在Linux域空间不同而已,过程是一样的跟一般的socket通信过程一致。
四 LocalSocket与LocalServerSocket建立socket通信
LocalSocket就是作为客户端建立于服务端的连接,发送数据。
LocalServerSocket作为服务端使用,建立socket监听客户端请求。通过构造函数看到有两种方式:
在Linux抽象空间 创建一个新的服务端socket:
public LocalServerSocket(String name) throws IOException
{
//创建socket资源
impl = new LocalSocketImpl();
impl.create(true);
//绑定地址
localAddress = new LocalSocketAddress(name);
impl.bind(localAddress);
//监听
impl.listen(LISTEN_BACKLOG);
}
用文件描述符创建已经存在并且绑定的服务端socket:
如在init.rc中指定socket资源 dev/socket/……,zygote使用此方式创建作为服务端的socket
LocalServerSocket socket = new LocalServerSocket(createFileDescriptor(fileDesc));
public LocalServerSocket(FileDescriptor fd) throws IOException
{
//已绑定 监听
impl = new LocalSocketImpl(fd);
impl.listen(LISTEN_BACKLOG);
localAddress = impl.getSockAddress();
}
通常使用过程中:
客户端代码:
String message;
//创建socket
LocalSocket sender = new LocalSocket();
//建立对应地址连接
sender.connect(new LocalSocketAddress(SOCKET_ADDRESS));
//发送写入数据
sender.getOutputStream().write(message.getBytes());
//关闭socket
sender.getOutputStream().close();
服务端:
//创建socket并绑定监听 新创建的
LocalServerSocket server = new LocalServerSocket(SOCKET_ADDRESS);
while (true) {
//等待建立连接
LocalSocket receiver = server.accept();
//接收获取数据流
InputStream input = receiver.getInputStream();
……
}