3

Actually,i have do a test with the server.c and client.c in the android emulator(ps:they both runs sucesssfully and are compiled with the android genric cross-compiler).And,then i go further,i rewrite the client-side via the jni.But,in this case,the client fail to connect to the server-side,though new client is very similar to the client.c. After searching,someone mentions that the permission matters.But,when i add the <uses-permission android:name="android.permission.INTERNET" />(ps:this tags is outside the application tags),the problem still appears. And as the logcat shows,the java code actually invode the c method,but,why not it behave the same as the client.c? Any idea will benefit me so much。Thanks in advance!

the server.c:

/*  Make the necessary includes and set up the variables.  */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int server_sockfd, client_sockfd;
    int server_len, client_len;
    struct sockaddr_un server_address;
    struct sockaddr_un client_address;

/*  Remove any old socket and create an unnamed socket for the server.  */

    unlink("server_socket");
    server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

/*  Name the socket.  */

    server_address.sun_family = AF_UNIX;
    strcpy(server_address.sun_path, "server_socket");
    server_len = sizeof(server_address);
    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

/*  Create a connection queue and wait for clients.  */

    listen(server_sockfd, 5);
    while(1) {
        char ch;

        printf("server waiting\n");

/*  Accept a connection.  */

        client_len = sizeof(client_address);
        client_sockfd = accept(server_sockfd, 
            (struct sockaddr *)&client_address, &client_len);

/*  We can now read/write to client on client_sockfd.  */

        read(client_sockfd, &ch, 1);
        ch++;
        write(client_sockfd, &ch, 1);
        close(client_sockfd);
    }
}

client.c:

/*  Make the necessary includes and set up the variables.  */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int sockfd;
    int len;
    struct sockaddr_un address;
    int result;
    char ch = 'A';

/*  Create a socket for the client.  */

    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

/*  Name the socket, as agreed with the server.  */

    address.sun_family = AF_UNIX;
    strcpy(address.sun_path, "server_socket");
    len = sizeof(address);

/*  Now connect our socket to the server's socket.  */

    result = connect(sockfd, (struct sockaddr *)&address, len);

    if(result == -1) {
        perror("oops: client1");
        exit(1);
    }

/*  We can now read/write via sockfd.  */

    write(sockfd, &ch, 1);
    read(sockfd, &ch, 1);
    printf("char from server = %c\n", ch);
    close(sockfd);
    exit(0);
}

java code: package gz.kaiwii;

public class NSocket {
    static{
        System.loadLibrary("NSocket");
    }
    public native void start();
}

native code:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <android/log.h>
#include <android/bitmap.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>

#define  LOG_TAG    "NSocket"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)



JNIEXPORT void JNICALL Java_gz_kaiwii_NSocket_start
  (JNIEnv * env, jobject object){
    LOGI("JNICALL Java_gz_kaiwii_NSocket_start is called!");

    int sockfd;
    int len;
    struct sockaddr_un address;
    int result;
    char ch = 'A';

/*  Create a socket for the client.  */

    LOGI(" Create a socket for the client!");

    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(sockfd==-1){
    LOGE("create socket error!!!!!");
}

/*  Name the socket, as agreed with the server.  */

    address.sun_family = AF_UNIX;
    strcpy(address.sun_path, "server_socket");
    len = sizeof(address);

/*  Now connect our socket to the server's socket.  */

    result = connect(sockfd, (struct sockaddr *)&address, len);

    LOGI("  Now connect our socket to the server's socket.");

    if(result == -1) {
        LOGE("connect error!");
        exit(1);
    }


/*  We can now read/write via sockfd.  */

    write(sockfd, &ch, 1);
    read(sockfd, &ch, 1);
    /*
    printf("char from server = %c\n", ch);
    */
    LOGI("char from server = %c\n", ch);
    close(sockfd);
}

the logcat: enter image description here

3
  • i have aready edit it with the logcat.thx! Commented Jun 22, 2012 at 7:37
  • Is server listening? How about printing error message on connect failure? Use errno and strerror for that. Commented Jun 22, 2012 at 7:46
  • @ Mārtiņš Možeiko,the server prompt the error,No such file or directory.And the client prompt connecttion refused.But,if i donn't use the jni to call the native code,everyhing runs okay. Commented Jun 25, 2012 at 3:15

2 Answers 2

1

If I use the abstract namespace as the name,everything runs okay.But,one thing should be cautioned is the length!

Sign up to request clarification or add additional context in comments.

1 Comment

your question was very helpful to me. Can you please tell if we can have both the server and the client in the jni itself??? If so than how do we start the server and the client at the same time for sending and receiving the data respectively...
0

There are two pitfalls when implement unix domain socket using NDK.

  1. Tha abstract name: The Android “LocalServerSocket(String name)” the document suggest that

Creates a new server socket listening at specified name.

This name is the Linux's abstract namespace for Unix domain sockets. You can checkout the current opened unix socket by using the adb shell command:

cat /proc/net/unix

$ cat /proc/net/unix
0000000000000000: 00000002 00000000 00010000 0001 01 8451293 @stetho_com.xxxx:channel_devtools_remote

You can see that the abstract name is start with a "@". So you need to have to do some convert operation before connecting to the LocalServerSocket.

  1. When you use connect method in c, you should watch out for the address length. It is the size of the address is the offset of the start of the filename, plus its length (not including the terminating null byte).
/* Bind a name to the socket. */
name.sun_family = AF_LOCAL;
strncpy (name.sun_path, filename, sizeof (name.sun_path));
name.sun_path[sizeof (name.sun_path) - 1] = '\0';

/* The size of the address is
the offset of the start of the filename,
plus its length (not including the terminating null byte).
Alternatively you can just do:
size = SUN_LEN (&name);
*/
size = (offsetof (struct sockaddr_un, sun_path)
          + strlen (name.sun_path));

You can checkout the full example here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.