2017-01-02 12:01:17 tutuchi8650 阅读数 0
     有一台linux设备,android手机通过usb线与该设备连接起来,目前需要手机apk与linux设备上的应用能够相互通信,目前不知道具体用什么方式能实现,征集方案!
2017-01-14 23:54:59 sh21_ 阅读数 5311

最近,做项目需要使用Android(客户端)与Linux(服务器端)进行数据通信,这学期也刚好学习了Linux网络编程的一些知识。所以,实现了一个小Demo,供有需要的朋友参考一下。

效果如下:

客户端向服务器端发送字符串数据,服务器收到客户端的数据显示在Linux终端上,并往客户端回发接收到的数据。客户端把发往服务器端的数据与接收到的数据都显示在一个TextView上面。

Linux服务器端:

Linux服务器端

Android客户端:

Android客户端

首先,有几个小问题要注意一下:

1. 在Android应用程序需要使用Tcp协议进行通信时,需要在AndroidManifest.xml中添加以下权限:
uses-permission android:name=”android.permission.INTERNET”

2. 在真机上面运行调试程序时,要保证手机能Ping通Linux服务器端的IP地址。

3. Android客户端接收数据,最好开一个线程来接收数据,因为是接收数据的read()方法是阻塞式的方法。

代码如下

Linux服务器端:(Server.c)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

#define PORT 8888               //服务器端监听端口号
#define MAX_BUFFER 1024         //数据缓冲区最大值

int main()
{
    struct sockaddr_in server_addr, client_addr;
    int server_sockfd, client_sockfd;
    int size, write_size;
    char buffer[MAX_BUFFER];

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)    //创建Socket
    {
        perror("Socket Created Failed!\n");
        exit(1);
    }
    printf("Socket Create Success!\n");

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);
    bzero(&(server_addr.sin_zero), 8);

    int opt = 1;
    int res = setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));    //设置地址复用
    if (res < 0)
    {
        perror("Server reuse address failed!\n");
        exit(1);
    }

    if (bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)  //绑定本地地址
    {
        perror("Socket Bind Failed!\n");
        exit(1);
    }
    printf("Socket Bind Success!\n");

    if (listen(server_sockfd, 5) == -1)                 //监听
    {
        perror("Listened Failed!\n");
        exit(1);
    }
    printf("Listening ....\n");

    socklen_t len = sizeof(client_addr);

    printf("waiting connection...\n");
    if ((client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len)) == -1)  //等待客户端连接
    {
        perror("Accepted Failed!\n");
        exit(1);
    }
    printf("connection established!\n");
    printf("waiting message...\n");

    while (1)
    {
        memset(buffer, 0, sizeof(buffer));                             //清空数据缓冲区

        if ((size = read(client_sockfd, buffer, MAX_BUFFER)) == -1)    //读取客户端的数据
        {
            perror("Recv Failed!\n");
            exit(1);
        }

        if (size != 0)                                               
        {
            buffer[size] = '\0';
            printf("Recv msg from client: %s\n", buffer);
            if ((write_size = write(client_sockfd, buffer, MAX_BUFFER)) > 0)   //把收到的数据回发给客户端
            {
                printf("Sent msg to client successfully!\n");
            }

        }
    }

    close(client_sockfd);   //关闭Socket
    close(server_sockfd);

    return 0;
}

Android客户端:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.blog_tcp_demo.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:text="地址:"
                android:textSize="20dp"
                android:layout_width="60dp"
                android:layout_height="40dp" />

            <EditText
                android:id="@+id/edtTxt_Addr"
                android:layout_weight="1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>                  //地址

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <TextView
                android:text="端口:"
                android:textSize="20dp"
                android:layout_width="60dp"
                android:layout_height="40dp" />

            <EditText
                android:id="@+id/edtTxt_Port"
                android:layout_weight="1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>                  //端口

        <ToggleButton
            android:id="@+id/tglBtn"
            android:textOn="断开"
            android:textOff="连接"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />                  //连接-断开按钮

        <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="300dp"
            android:layout_weight="0.86" >

            <TextView
                android:id="@+id/tv_Msg"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:text="Ready...\n" />
        </ScrollView>                    //消息显示

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <EditText
                android:id="@+id/edtTxt_Data"
                android:hint="请输入要发送的数据"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <Button
                android:id="@+id/btn_Send"
                android:text="发送"
                android:textSize="20dp"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

        </LinearLayout>                  //数据发送

    </LinearLayout>

</LinearLayout>

MainActivity.java:

package com.example.blog_tcp_demo;

import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private EditText edtTxt_Addr;
    private EditText edtTxt_Port;
    private ToggleButton tglBtn;
    private TextView tv_Msg;
    private EditText edtTxt_Data;
    private Button btn_Send;

    private TcpClientConnector connector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        InitWidgets();
        connector = TcpClientConnector.getInstance();   //获取connector实例
        tglBtn.setOnCheckedChangeListener(new TglBtnCheckedChangeEvents());
        btn_Send.setOnClickListener(new ButtonClickEvent());

    }

    /***
     * 控件初始化
     */
    private void InitWidgets(){
        edtTxt_Addr = (EditText) findViewById(R.id.edtTxt_Addr);
        edtTxt_Port = (EditText) findViewById(R.id.edtTxt_Port);
        tglBtn = (ToggleButton) findViewById(R.id.tglBtn);
        tv_Msg = (TextView) findViewById(R.id.tv_Msg);
        edtTxt_Data = (EditText) findViewById(R.id.edtTxt_Data);
        btn_Send = (Button) findViewById(R.id.btn_Send);
    }

    class TglBtnCheckedChangeEvents implements ToggleButton.OnCheckedChangeListener{

        @Override
        public void onCheckedChanged(CompoundButton btnView, boolean isChecked){
            if(btnView == tglBtn){
                if(isChecked == true){
                    //连接Tcp服务器端
                    //connector.createConnect("172.16.46.41",8888);   //调试使用
                    connector.createConnect(edtTxt_Addr.getText().toString(),Integer.parseInt(edtTxt_Port.getText().toString()));
                    connector.setOnConnectListener(new TcpClientConnector.ConnectListener() {
                        @Override
                        public void onReceiveData(String data) {
                            //Received Data,do somethings.
                            tv_Msg.append("Server:"+ data + "\n");
                        }
                    });
                }else{
                    try{   //断开与服务器的连接
                        connector.disconnect();
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    class ButtonClickEvent implements View.OnClickListener{
        public void onClick(View v){
            if (v == btn_Send){
                //发送数据
                try{
                    connector.send(edtTxt_Data.getText().toString());
                    tv_Msg.append("Client:"+ edtTxt_Data.getText().toString() + "\n");
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

TcpClientConnector.java:

package com.example.blog_tcp_demo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TcpClientConnector {

    private static TcpClientConnector mTcpClientConnector;
    private Socket mClient;
    private ConnectListener mListener;
    private Thread mConnectThread;

    public interface ConnectListener {
        void onReceiveData(String data);
    }

    public void setOnConnectListener(ConnectListener listener) {
        this.mListener = listener;
    }

    public static TcpClientConnector getInstance() {
        if (mTcpClientConnector == null)
            mTcpClientConnector = new TcpClientConnector();
        return mTcpClientConnector;
    }

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 100:
                    if (mListener != null) {
                        mListener.onReceiveData(msg.getData().getString("data"));
                    }
                    break;
            }
        }
    };

    public void createConnect(final String mSerIP, final int mSerPort) {
        if (mConnectThread == null) {
            mConnectThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        connect(mSerIP, mSerPort);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            mConnectThread.start();
        }
    }

    /**
     * 与服务端进行连接
     *
     * @throws IOException
     */
    private void connect(String mSerIP, int mSerPort) throws IOException {
        if (mClient == null) {
            mClient = new Socket(mSerIP, mSerPort);
        }
        InputStream inputStream = mClient.getInputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer)) != -1) {
            String data = new String(buffer, 0, len);
            Message message = new Message();
            message.what = 100;
            Bundle bundle = new Bundle();
            bundle.putString("data", data);
            message.setData(bundle);
            mHandler.sendMessage(message);
        }
    }

    /**
     * 发送数据
     *
     * @param data 需要发送的内容
     */
    public void send(String data) throws IOException {
        OutputStream outputStream = mClient.getOutputStream();
        outputStream.write(data.getBytes());
    }

    /**
     * 断开连接
     *
     * @throws IOException
     */
    public void disconnect() throws IOException {
        if (mClient != null) {
            mClient.close();
            mClient = null;
        }
    }
}

其中,Android客户端的代码参考了这位朋友的博客(^__^) ,写得的确很好,给个大写的赞!:Android Socket 通信

2016-05-11 15:53:38 give_me_555 阅读数 715

Android和Linux底层通信机制实现


Android系统把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层(HAL层)运行在用户空间,而Linux内核驱动程序运行在内核空间。

为什么要这样安排呢?这是为了保护厂家的利益,把对硬件的支持逻辑都放在内核空间。我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在Linux驱动层,那就意味着发布时要公开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了。内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。

下图描述了硬件抽象层在Android系统中的位置以及与其它层的关系: 

法术都是



2018-12-15 12:10:27 lin5103151 阅读数 6971

最近忙于查找Linux和android平台的资料,今天将其整理整理,根据本人拙见分享给大家。

Android和Linux作为现行主流的操作系统,无论在消费类产品还是在工控领域,都有广泛的应用。都说Android系统是脱胎于Linux系统,那么是不是Android是不是属于Linux的一种。现在就来谈谈Android和Linux系统的异同点。
在这里插入图片描述
1. 两者的共同点
Android是基于Linux内核的系统。Android和Linux系统的核心系统服务都依赖于Linux内核,如安全、内核管理、进程管理、网络堆栈、驱动模型等。Linux内核也作为两者的硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层应用开发提供统一的服务。
在这里插入图片描述
2. 系统框架的差异
Linux系统与Android表面上为两个不同的操作系统,但是Android本质上还是一个Linux系统,只不过Google对它进行了裁剪和定制。
另外,相较于Linux系统,android在其Linux内核上面运行了一个叫Dalvik(4.4版本后改为ART)的Java虚拟机(JVM),因而使用JAVA开发的android的应用程序可以通过JAVA虚拟机运行在Android系统上。而Linux的应用程序使用的是C/C++开发的,可以机器码的形式运行在内核系统上,两者的系统框架差异,如图。
在这里插入图片描述
在这里插入图片描述

3. Linux与android底层驱动软件的差异
Android除了Linux内核具备的常用核心驱动外,还增加了自己专有的内核驱动程序,如显示驱动、蓝牙驱动、相机驱动、内存卡驱动、Binder IPC驱动等。
另外,Android系统为了保护硬件厂商的知识产权,增加了HAL层,可将驱动具体的实现部分抽取发到HAL中去实现,从而规避了硬件驱动开源的风险,所以android的驱动程序是分为两部分,一部分写入内核中,一部分写入HAL层中。
Android除要实现底层驱动的开发外,还需要根据JNI规则将驱动程序封装为JNI层接口,以达到应用程序(JAVA程序) 可通过JNI来调用内核驱动程序。以显示驱动程序Framebuffer为例,如图。
在这里插入图片描述
Linux系统的显示驱动模型
在这里插入图片描述
Android系统的显示驱动模型

(1)Linux系统:Framebuffer驱动只需要编译到Linux内核中,并留出相应的read、write、ioctl等接口,便可供上位机应用程序调用。
(2)Android系统:Framebuffer驱动先将简单的硬件寄存器读写操作的驱动编译进入内核中,再将具体的硬件实现方式的驱动写入HAL层中,并根据JNI规格封装为JNI接口,才可供上位机应用程序调用。

4. Linux与android应用层软件的差异
但是Android应用程序是使用java语言写的,不能直接调用C语言实现的系统接口,而Linux系统中可以用C语言调用系统接口来与内核进行通信,于是Android系统中就有了一个叫做JNI的概念,用实现java与C/C++程序之间的信息交互。

(1)Android应用程序访问Android内核驱动程序的方式:

  1. APP—>JNI—>Android内核驱动程序
  2. APP—>硬件访问服务—>Android内核驱动程序

(2)Linux应用程序访问linux驱动程序的方式

  1. APP—> Linux内核驱动程序
  2. APP—>C库—>Linux内核驱动程序

如果您喜欢,可关注个人公众号“电子应用学习馆”,获取更多的资料例程。
在这里插入图片描述

2014-04-16 10:45:57 ceko_wu 阅读数 0
linux c进程与android进程间通信

1、linux c进程间通信简介

      linux 提供本地进程通信的方式有很多,除管道(pipe\fifo)、ipc(内存共享、信号量、消息队列)外,另外就是通过socket实现本地进程之间的通信,基于c/s框架来实现。
          socket通信分为两种,一种是基于网络;另一种用于非网络。网络通信不在此说明,非网络通信,这种可以用于进程间通信。

2、android进程与linux c进程通信

        android进程要与linux进程进行通信,常用通信方式是socket,这种方式比较简单,android为此专门提供了一个叫LocalSocekt的套接字,典型事例就是android phone进程与rild的通信,采用此方法,当然还有很多进程也采用此方法来通信。