android socket通讯
2014-01-07 16:20
429 查看
项目中要用到进程间通讯,服务端接收应用的请求数据,对串口进行读写操作。考虑到android的socket服务比较实用,并且可以支持多个客户端同时连接。
服务端写成一个服务,在init.rc中启动,示例代码如下:
socket_keyboard.c:
客户端可以是c/c++代码,也可以是应用层代码,c代码如下:
客户端的c代码是仿照android socket源代码搬写过来的,源代码路径在system/core/libcutils/socket_local_client.c中。
Android.mk:
把编译出来的执行文件放入/system/bin/目录,接着在init.rc中加入启动服务:
这里权限要更改成777 和 user,否则应用程序没有权限连接该服务。系统启动后在/dev/socket/目录下发现多了一个文件:
执行./socket_client 即可连接上服务端。
应用层代码如下:
package com.example.keyboardsocketclient;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
LocalSocket mSocket;
InputStream mIn;
OutputStream mOut;
byte buf[] = new byte[1024];
int ret = 0;
String write_str = "this is from client******************************************";
String write_str1 = "close";
ServerSocketThread mthread;
boolean isInterrupted = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mthread = new ServerSocketThread();
mthread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
Log.d("spi-keyboard", "onDestroy");
super.onDestroy();
mthread.interrupt();
finish();
}
void connect() throws IOException
{
//创建socket
mSocket = new LocalSocket();
//设置连接地址
LocalSocketAddress address = new LocalSocketAddress("spi-keyboard",
LocalSocketAddress.Namespace.RESERVED);
//建立连接
mSocket.connect(address);
//获取数据输入流 可以读数据
mIn = mSocket.getInputStream();
//获取数据输出流 可以写数据
mOut = mSocket.getOutputStream();
}
private class ServerSocketThread extends Thread {
public void interrupt(){
isInterrupted = true;
super.interrupt();
}
@Override
public void run() {
try {
connect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (!isInterrupted) {//不能用this.isInterrupted()来判断,因为sleep时候,中断线程,只会catch异常,接着下一次循环中isInterrupted()还是为false
try {
Thread.sleep(1000);//括号里面的5000代表5000毫秒,也就是5秒,可以该成你需要的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
mOut.write(write_str.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int count = 0;
while (count == 0) {
try {
count = mIn.available();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byte[] b = new byte[count];
try {
ret = mIn.read(b);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (ret > 0) {
String str = "";
try {
str = new String(b, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("keyboard client", "" + str);
}
}
}
}
}
运行该apk可以发现,服务端又为这个客户端创建一个线程,这样两个客户端可以同时连接,要注意LocalSocketAddress的第二个参数必须为LocalSocketAddress.Namespace.RESERVED,这个值为1,android专门为路径/dev/socket通讯而留的。
服务端写成一个服务,在init.rc中启动,示例代码如下:
socket_keyboard.c:
#define LOG_TAG "socket-keyboard" #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <inttypes.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #include <ctype.h> #include <fcntl.h> #include <errno.h> #include <utime.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> #include <cutils/fs.h> #include <cutils/sockets.h> #include <cutils/log.h> #include <cutils/properties.h> #include <cutils/multiuser.h> #include <private/android_filesystem_config.h> #define SOCKET_PATH "spi-keyboard" //#define ALOGE LOGE void *thr_fn(void *arg) { int s = (int)arg; char buf[1024]; int count; char *respone = "this is from service"; ALOGE("new thread: "); while (1) { ALOGE("read..."); count = read(s,buf, sizeof(buf)); if (count > 0) { buf[count] = '\0'; ALOGE("read client:%s", buf); if (!memcmp(buf, "close", 5)) break; } ALOGE("write..."); count = write(s, respone, strlen(respone)); } return NULL; } int main(const int argc, const char *argv[]) { struct sockaddr addr; socklen_t alen; int lsocket, s; ALOGE("socket keyboard service start"); lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); exit(1); } if (listen(lsocket, 5)) { ALOGE("Listen on socket failed: %s\n", strerror(errno)); exit(1); } ALOGE("socket keyboard service loop......"); for (;;) { ALOGE("accept..."); alen = sizeof(addr); s = accept(lsocket, &addr, &alen); if (s < 0) { ALOGE("Accept failed: %s\n", strerror(errno)); continue; } else { int err; pthread_t ntid; err = pthread_create(&ntid, NULL, thr_fn, (void *)s); } } ALOGE("service close"); return 0; }
客户端可以是c/c++代码,也可以是应用层代码,c代码如下:
#define LOG_TAG "socket-client" #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <inttypes.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #include <ctype.h> #include <fcntl.h> #include <errno.h> #include <utime.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> #include <cutils/fs.h> #include <cutils/sockets.h> #include <cutils/log.h> #include <cutils/properties.h> #include <cutils/multiuser.h> #include <stdlib.h> #include <stdio.h> #include <stddef.h> #include <sys/un.h> #include <errno.h> #include <private/android_filesystem_config.h> #define SOCKET_PATH "socket-keyboard" #define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/" int main(const int argc, const char *argv[]) { char buf[1024] = {0}; struct sockaddr_un addr; struct sockaddr_un *p_addr; socklen_t alen; int fd, s, count; size_t namelen; char *str = "this is from client"; char *name = "spi-keyboard"; p_addr = &addr; memset (p_addr, 0, sizeof (*p_addr)); strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); strcat(p_addr->sun_path, name); p_addr->sun_family = AF_LOCAL; namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; ALOGE("socket keyboard client start"); fd = socket(PF_LOCAL, SOCK_STREAM, 0); if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { ALOGE("connet spi keyboard server err[%s]", strerror(errno)); exit(-1); } while (1) { ALOGE("write"); write(fd, str, strlen(str) + 1); ALOGE("read"); count = read(fd, buf, sizeof(buf)); if (count) { ALOGE("client: %s", buf); } sleep(1); } return 0; }
客户端的c代码是仿照android socket源代码搬写过来的,源代码路径在system/core/libcutils/socket_local_client.c中。
Android.mk:
LOCAL_PATH := $(call my-dir) # # Executable # include $(CLEAR_VARS) LOCAL_SRC_FILES := \ socket_keyboard.c LOCAL_SHARED_LIBRARIES := \ libcutils LOCAL_STATIC_LIBRARIES := \ libdiskusage LOCAL_MODULE := spi-keyboard LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ socket_client.c LOCAL_SHARED_LIBRARIES := \ libcutils LOCAL_STATIC_LIBRARIES := \ libdiskusage LOCAL_MODULE := socket-client LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE)
把编译出来的执行文件放入/system/bin/目录,接着在init.rc中加入启动服务:
service spi-keyboard /system/bin/spi-keyboard class main socket spi-keyboard stream 777 user user
这里权限要更改成777 和 user,否则应用程序没有权限连接该服务。系统启动后在/dev/socket/目录下发现多了一个文件:
adbd keystore property_service spi-keyboard dnsproxyd mdns rild vold installd netd rild-debug zygote这就是新的socket服务spi-keyboard。
执行./socket_client 即可连接上服务端。
应用层代码如下:
package com.example.keyboardsocketclient;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
LocalSocket mSocket;
InputStream mIn;
OutputStream mOut;
byte buf[] = new byte[1024];
int ret = 0;
String write_str = "this is from client******************************************";
String write_str1 = "close";
ServerSocketThread mthread;
boolean isInterrupted = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mthread = new ServerSocketThread();
mthread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
Log.d("spi-keyboard", "onDestroy");
super.onDestroy();
mthread.interrupt();
finish();
}
void connect() throws IOException
{
//创建socket
mSocket = new LocalSocket();
//设置连接地址
LocalSocketAddress address = new LocalSocketAddress("spi-keyboard",
LocalSocketAddress.Namespace.RESERVED);
//建立连接
mSocket.connect(address);
//获取数据输入流 可以读数据
mIn = mSocket.getInputStream();
//获取数据输出流 可以写数据
mOut = mSocket.getOutputStream();
}
private class ServerSocketThread extends Thread {
public void interrupt(){
isInterrupted = true;
super.interrupt();
}
@Override
public void run() {
try {
connect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (!isInterrupted) {//不能用this.isInterrupted()来判断,因为sleep时候,中断线程,只会catch异常,接着下一次循环中isInterrupted()还是为false
try {
Thread.sleep(1000);//括号里面的5000代表5000毫秒,也就是5秒,可以该成你需要的时间
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
mOut.write(write_str.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int count = 0;
while (count == 0) {
try {
count = mIn.available();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byte[] b = new byte[count];
try {
ret = mIn.read(b);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (ret > 0) {
String str = "";
try {
str = new String(b, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("keyboard client", "" + str);
}
}
}
}
}
运行该apk可以发现,服务端又为这个客户端创建一个线程,这样两个客户端可以同时连接,要注意LocalSocketAddress的第二个参数必须为LocalSocketAddress.Namespace.RESERVED,这个值为1,android专门为路径/dev/socket通讯而留的。
相关文章推荐
- Android listview 利用反射的自动绑定Adapter
- android4.0 及以上 版本 wifi 和 蓝牙不显示 原因
- android弹出窗口的实现(PopupWindow)
- android签名APK注意事项
- android 编解码
- android悬浮窗口的实现
- ShareSDK for Android 2.3.1已经发布
- [原]Android用户界面菜单之上下文菜单(Context Menu)
- Android用户界面菜单之上下文菜单(Context Menu)
- Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)
- android 裁剪图片大小 控制图片尺寸
- android_移植memtester
- Android需要提升权限的操作
- Android 编程下 Canvas and Drawables
- android 实现按键精灵
- 两分钟彻底让你明白Android Activity生命周期(图文)!
- [转]Android 企业需求与开发者状况简析(转)
- Android 企业需求与开发者状况简析(转)
- Android内存管理-SoftReference的使用
- android系统信息(内存、cpu、sd卡、电量、版本)获取