Android Socket 通信

最近在开发过程中遇到一个需求:Java 层和 C 层两个进程之间用Socket 通信。利用LocalServerSocket 类和 ServerSocket 类可以很容易实现Java 层和 C 层进程间通信。

1.Java层作为Server,利用Android LocalServerSocket类创建。LocalServerSocket 被Android 封装得过于简单,不能设置 timeout 和 reuse 端口。

    /**
     * Create the server socket by Android LocalServerSocket
     */
    public void createSocket() {
        new Thread() {
            @Override
            public void run() {
                LocalSocket receiver = null;
                try {
                    mSocketServer = new LocalServerSocket(SOCKET_NAME);
                    receiver = mSocketServer.accept();
                    if (receiver != null) {
                        handleSockectRequest(receiver);
                    }
                } catch (Throwable t) {
                    e.printStackTrace();
                } finally {
                    if (receiver != null) {
                        try {
                            receiver.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    
                    if (mSocketServer != null) {
                        try {
                            mSocketServer.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        mSocketServer = null;
                    }
                }
            }
        }.start();
    }

    /**
     * Force to close the socket if it exist.
     */
    public void closeSocket() {
        if (mSocketServer != null) {
            try {
                mSocketServer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mSocketServer = null;
        }
    }
    
    /**
     * Start the handle the socket client request.
     */
    private void handleSockectRequest(final LocalSocket receiver) {
        InputStream input = null;
        BufferedReader reader = null;
        try {
            input = receiver.getInputStream();  
            reader = new BufferedReader(new InputStreamReader(input));
            String line = reader.readLine();
            if (line != null && line.length() > 0) {
                StringBuffer buffer = new StringBuffer();
                buffer.append(line).append(END_SYMBOL);
                String response = buffer.toString();
                if (response != null && response.length() > 0) {
                    sendToSocket(receiver, response.getBytes());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * Send back data to the socket client.
     */
    private void sendToSocket(final LocalSocket receiver, byte[] data) {
        OutputStream output = null;
        try { 
            output = receiver.getOutputStream();
            output.write(data); 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.flush();
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
若Java层作为Client,具体代码如下:
    public void createSocketCliet() {
        LocalSocket so = new LocalSocket();
        LocalSocketAddress addr = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.ABSTRACT);
        try {
            so.connect(addr);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
若C 层作为Client,具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <android/log.h>

#define SEND_BUFFER_LENGTH		0x43
#define RECEIVE_BUFFER_LENGTH 	0x1000
#define MAX_INDEX				(0x24-1)
#define MIN_INDEX				0

#define END_OF_DATA_SYMBOL "#" //customer define
#define SOCKET_NAME	       "my_socket_name"
#define LOG_TAG            "myTag"
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)

int main() {

    //1.generate random request data
    char rawDataTable[] = {"abcdefghijklmnopqrstuvwxyz0123456789"};
    char requestData[SEND_BUFFER_LENGTH] = {0};
    srand((unsigned) time(NULL));
    int i = 0;
    for (i = 0; i < SEND_BUFFER_LENGTH; i++) {
        int index = rand() % (MAX_INDEX - MIN_INDEX) + MIN_INDEX;
        requestData[i] = rawDataTable[index];
    }
    LOGD("cookie:%s", requestData);

    //2. create socket
    int s = socket(AF_UNIX, SOCK_STREAM, 0);
    if (s < 0) {
        LOGD("failed to create socket");
        return -1;
    }

    //3. connect to local server
    struct sockaddr_un server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sun_family = AF_UNIX;
    server_addr.sun_path[0] = '\0';  /* abstract namespace */
    strcpy(&server_addr.sun_path[1], SOCKET_NAME);
    int server_addr_len = 1 + strlen(SOCKET_NAME) + offsetof(struct sockaddr_un, sun_path);
    if (connect(s, (struct sockaddr *) &server_addr, server_addr_len) < 0) {
        LOGD("failed to connect local server");
        return -1;
    }

    //4. set send/receive timeout
    struct timeval timeout = {10,0}; //timeout=10s
    setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

    //5. send request data to socket server
    if (send(s, requestData, strlen(requestData), 0) != strlen(requestData)) {
        LOGD("send cookie to server failed");
        close(s);
        if (errno == EAGAIN) {
            LOGD("send data timeout");
            return -1;
        }
        return -1;
    }

    //6. read response data from socket server
    char *recv_buffer = (char *)malloc(RECEIVE_BUFFER_LENGTH);
    if (recv_buffer == NULL) {
        LOGD("allocate recv_buffer failed");
        close(s);
        return -1;
    } else {
        memset(recv_buffer, 0, RECEIVE_BUFFER_LENGTH);
    }

    int recv_length = 0;
    for (i = 0; i < RECEIVE_BUFFER_LENGTH; i++) {
        char b = '\0';
        int bytes = recv(s, &b, 1, MSG_WAITALL);
        if (bytes < 1) {
            LOGD("receive bytes from server failed");
            close(s);
            if (recv_buffer != NULL) {
                free(recv_buffer);
            }
            if (errno == EAGAIN) {
                LOGD("recv data timeout");
                return -1;
            } else {
                return -1;
            }
        }

        //Judge if reach the end of data
        if (b == END_OF_DATA_SYMBOL) {
            recv_length = i;
            recv_buffer[i] = '\0';
            break;
        } else {
            recv_buffer[i] = b;
        }
    }

    if (recv_length == 0) {
        LOGD("receive bytes from server failed");
    }
    if (recv_buffer != NULL) {
        free(recv_buffer);
    }
    close(s);
}

2.Java层作为Server,利用Java 原生类 ServerSocket创建,可以设置setReuseAddress,setSoTimeout,更加灵活:

    /**
     * Create the server socket by Java ServerSocket
     */
    public void createJavaServerSocket() {
        new Thread() {
            @Override
            public void run() {
                Socket receiver = null;
                try {
                    mSocketServer = new ServerSocket();
                    mSocketServer.setReuseAddress(true);
                    mSocketServer.setSoTimeout(SOCKET_TIME_OUT);
                    mSocketServer.bind(new InetSocketAddress(SOCKET_BIND_PORT));
                    
                    receiver = mSocketServer.accept();
                    if (receiver != null) {
                        handleSockectRequest(receiver);
                    }
                } catch (Throwable t) {
                    if (ALILog.LOGENABLE) {
                        ALILog.e("createJavaServerSocket",  "Error = " + t.toString());
                    }
                } finally {
                    if (receiver != null) {
                        try {
                            receiver.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if (mSocketServer != null) {
                        if (ALILog.LOGENABLE) {
                            ALILog.d("createJavaServerSocket",  "close Socket... ");
                        }
                        try {
                            mSocketServer.close();
                        } catch (IOException e) {
                            if (ALILog.LOGENABLE) {
                                ALILog.e("createJavaServerSocket",  "close Socket error = " + e.toString());
                            }
                        }
                        mSocketServer = null;
                    }
                }
            }
        }.start();
    }
C 层作为Client ,具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/endian.h>
#include <linux/in.h>
#include <errno.h>
#include <arpa/inet.h>
#include "Alog.h"
#include "rsa.h"
#include "base64.h"

#define END_OF_DATA_SYMBOL			'#'
#define MAX_RAW_DATA_LENGTH 			0x40
#define MAX_RAW_DATA_BUFFER_LENGTH		0x43
#define ENCRYPTED_DATA_LENGTH 			0x80
#define MAX_ENCRYPTED_DATA_LENGTH 		0x1000
#define MAX_INDEX				(0x24-1)
#define MIN_INDEX				0
#define SOCKET_PORT                             19521

static char DATA_TABLE[] = {"abcdefghijklmnopqrstuvwxyz0123456789"};

/**
 * Send the raw data to local socket and get back the response data
 */
char* getDataFromLocalSocket(char* rawData) {
    //1. create socket
    int s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        LOGE("failed to create socket");
        return NULL;
    }

    //2. connect to socket server
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SOCKET_PORT);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if(connect(s, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) < 0) {
        LOGE("failed to connect local server");
        close(s);
        return NULL;
    }

    //3. set send/receive timeout
    struct timeval timeout = {10,0}; //timeout=10s
    setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

    //4. send raw data
    if (send(s, rawData, strlen(rawData), 0) != strlen(rawData)) {
        LOGE("send data to server failed");
        if (errno == EAGAIN) {
            LOGE("send data timeout");
        }
        close(s);
        return NULL;
    }

    //5. allocate receive data buffer
    char *recvBuffer = (char *)malloc(MAX_ENCRYPTED_DATA_LENGTH);
    if (recvBuffer == NULL) {
        LOGE("allocate recvBuffer failed");
        close(s);
        return NULL;
    } else {
        memset(recvBuffer, 0, MAX_ENCRYPTED_DATA_LENGTH);
    }

    //6. receive encrypt data
    int recvLength = 0;
    int i = 0;
    for (i = 0; i < MAX_ENCRYPTED_DATA_LENGTH; i++) {
        char b = '\0';
        int bytes = recv(s, &b, 1, MSG_WAITALL);
        if (bytes < 1) {
            LOGE("receive bytes from server failed");
            if (errno == EAGAIN) {
                LOGE("receive data timeout");
            }

            free(recvBuffer);
            close(s);
            return NULL;
        }

        if (b == END_OF_DATA_SYMBOL) {
            recvLength = i;
            recvBuffer[i] = '\0';
            break;
        } else {
            recvBuffer[i] = b;
        }
    }

    //7. close socket and return
    close(s);
    if (recvLength == 0) {
        LOGE("receive data failed: recvLength == 0");
        free(recvBuffer);
        return NULL;
    } else {
        return recvBuffer;
    }
}

int main() {
    //1. generate random data
    char rawData[MAX_RAW_DATA_BUFFER_LENGTH] = {0};
    srand((unsigned) time(NULL));
    int i = 0;
    for (i = 0; i < MAX_RAW_DATA_LENGTH; i++) {
        int index = rand() % (MAX_INDEX - MIN_INDEX) + MIN_INDEX;
        rawData[i] = DATA_TABLE[index];
    }
    rawData[MAX_RAW_DATA_BUFFER_LENGTH-3] = '\r';
    rawData[MAX_RAW_DATA_BUFFER_LENGTH-2] = '\n';
    rawData[MAX_RAW_DATA_BUFFER_LENGTH-1] = '\0';
    LOGD("rawData: %s", rawData);

    //2. get encrypt data from server
    char* encyptData = getDataFromLocalSocket(rawData);
    if (encyptData != NULL) {
        LOGD("receive encrypt data: %s", encyptData);
        free(encyptData);
    } else {
        LOGE("Error: receive NULL data from server");
    }
}
3. C层实现TCP 协议

Server 端代码tcp_server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	int server_sockfd;//服务器端套接字
	int client_sockfd;//客户端套接字
	int len;
	struct sockaddr_in my_addr;   //服务器网络地址结构体
	struct sockaddr_in remote_addr; //客户端网络地址结构体
	int sin_size;
	char buf[BUFSIZ];  //数据传送的缓冲区
	memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
	my_addr.sin_family=AF_INET; //设置为IP通信
	my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
	my_addr.sin_port=htons(8000); //服务器端口号
	
	/*创建服务器端套接字--IPv4协议,面向连接通信,TCP协议*/
	if((server_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
	{  
		perror("socket");
		return 1;
	}
 
        /*将套接字绑定到服务器的网络地址上*/
	if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
	{
		perror("bind");
		return 1;
	}
	
	/*监听连接请求--监听队列长度为5*/
	listen(server_sockfd,5);
	
	sin_size=sizeof(struct sockaddr_in);
	
	/*等待客户端连接请求到达*/
	if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0)
	{
		perror("accept");
		return 1;
	}
	printf("accept client %s/n",inet_ntoa(remote_addr.sin_addr));
	len=send(client_sockfd,"Welcome to my server/n",21,0);//发送欢迎信息
	
	/*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/
	while((len=recv(client_sockfd,buf,BUFSIZ,0))>0))
	{
		buf[len]='/0';
		printf("%s/n",buf);
		if(send(client_sockfd,buf,len,0)<0)
		{
			perror("write");
			return 1;
		}
	}
	close(client_sockfd);
	close(server_sockfd);
        return 0;
}
Client 端代码tcp_client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	int client_sockfd;
	int len;
	struct sockaddr_in remote_addr; //服务器端网络地址结构体
	char buf[BUFSIZ];  //数据传送的缓冲区
	memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零
	remote_addr.sin_family=AF_INET; //设置为IP通信
	remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器IP地址
	remote_addr.sin_port=htons(8000); //服务器端口号
	
	/*创建客户端套接字--IPv4协议,面向连接通信,TCP协议*/
	if((client_sockfd=socket(PF_INET,SOCK_STREAM,0))<0)
	{
		perror("socket");
		return 1;
	}
	
	/*将套接字绑定到服务器的网络地址上*/
	if(connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr))<0)
	{
		perror("connect");
		return 1;
	}
	printf("connected to server/n");
	len=recv(client_sockfd,buf,BUFSIZ,0);//接收服务器端信息
         buf[len]='/0';
	printf("%s",buf); //打印服务器端信息
	
	/*循环的发送接收信息并打印接收信息--recv返回接收到的字节数,send返回发送的字节数*/
	while(1)
	{
		printf("Enter string to send:");
		scanf("%s",buf);
		if(!strcmp(buf,"quit")
			break;
		len=send(client_sockfd,buf,strlen(buf),0);
		len=recv(client_sockfd,buf,BUFSIZ,0);
		buf[len]='/0';
		printf("received:%s/n",buf);
	}
	close(client_sockfd);//关闭套接字
         return 0;
}
4. C层实现UDP 协议
Server 端代码udp_server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	int server_sockfd;
	int len;
	struct sockaddr_in my_addr;   //服务器网络地址结构体
         struct sockaddr_in remote_addr; //客户端网络地址结构体
	int sin_size;
	char buf[BUFSIZ];  //数据传送的缓冲区
	memset(&my_addr,0,sizeof(my_addr)); //数据初始化--清零
	my_addr.sin_family=AF_INET; //设置为IP通信
	my_addr.sin_addr.s_addr=INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上
	my_addr.sin_port=htons(8000); //服务器端口号
	
	/*创建服务器端套接字--IPv4协议,面向无连接通信,UDP协议*/
	if((server_sockfd=socket(PF_INET,SOCK_DGRAM,0))<0)
	{  
		perror("socket");
		return 1;
	}
 
        /*将套接字绑定到服务器的网络地址上*/
	if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))<0)
	{
		perror("bind");
		return 1;
	}
	sin_size=sizeof(struct sockaddr_in);
	printf("waiting for a packet.../n");
	
	/*接收客户端的数据并将其发送给客户端--recvfrom是无连接的*/
	if((len=recvfrom(server_sockfd,buf,BUFSIZ,0,(struct sockaddr *)&remote_addr,&sin_size))<0)
	{
		perror("recvfrom"); 
		return 1;
	}
	printf("received packet from %s:/n",inet_ntoa(remote_addr.sin_addr));
	buf[len]='/0';
	printf("contents: %s/n",buf);
	close(server_sockfd);
        return 0;
}
Client 端代码udp_client.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
	int client_sockfd;
	int len;
        struct sockaddr_in remote_addr; //服务器端网络地址结构体
	int sin_size;
	char buf[BUFSIZ];  //数据传送的缓冲区
	memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零
	remote_addr.sin_family=AF_INET; //设置为IP通信
	remote_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器IP地址
	remote_addr.sin_port=htons(8000); //服务器端口号

         /*创建客户端套接字--IPv4协议,面向无连接通信,UDP协议*/
	if((client_sockfd=socket(PF_INET,SOCK_DGRAM,0))<0)
	{  
		perror("socket");
		return 1;
	}
	strcpy(buf,"This is a test message");
	printf("sending: '%s'/n",buf);
	sin_size=sizeof(struct sockaddr_in);
	
	/*向服务器发送数据包*/
	if((len=sendto(client_sockfd,buf,strlen(buf),0,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr)))<0)
	{
		perror("recvfrom"); 
		return 1;
	}
	close(client_sockfd);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值