0%

linux平台调用*.so库文件的方法

前言:

本笔记记录linux平台调用so动态库文件的示例,工程创建使用vs2019+visualGDB,这样的组合调试起来方便,开个LINUX虚拟机后,VS2019调试linux平台代码和windows平台调试程序没啥区别,就是算爽。

概念的东西就不罗嗦,直接演示过程。

库文件说明 :

库的头文件:

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef __cplusplus
extern "C" {
#endif
int _xlab_init(void** api, char* confdir);

void _xlab_exit();

int _xlab_network_io_accept(int server_fd);

int _xlab_network_io_read(int socket_fd, void* buf, int count);

int _xlab_network_io_write(int socket_fd, const void* buf, size_t count);

int _xlab_network_io_close(int socket_fd);

int _xlab_network_io_create_socket(int domain, int type, int protocol);
/* We need to know how to solve the problem with AF_INET and AF_INET6 */
int _xlab_network_io_connect(char* host, int port);   

int _xlab_network_io_send_file(int socket_fd, int file_fd, off_t* file_offset, size_t file_count);

int _xlab_network_io_bind(int socket_fd, const struct sockaddr* addr, socklen_t addrlen, int backlog);

int _xlab_network_io_server(int port, char* listen_addr);

#ifdef __cplusplus
}
#endif

库的实现文件:

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include "XLABPlugin.h"
#include "xlab-liana.h"

XLAB_PLUGIN("liana",            /* shortname */
    "Liana Network",            /* name */
    VERSION,                    /* version */
    XLAB_PLUGIN_NETWORK_IO);    /* hooks */

void* xlab_mem_malloc(const size_t size)
{
    void* aux = malloc(size);

    if (!aux && size) {
        perror("malloc");
        return NULL;
    }

    return aux;
}
void xlab_mem_free(void* ptr)
{
    free(ptr);
}
int xlab_socket_set_tcp_nodelay(int sockfd)
{
    int on = 1;

    return setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &on, sizeof(on));
}
int xlab_socket_reset(int socket)
{
    int status = 1;

    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)) ==
        -1) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    return 0;
}
char* xlab_string_build(char** buffer, unsigned long* len,const char* format, ...)
{
    va_list ap;
    int length;
    char* ptr;
    static size_t _mem_alloc = 64;
    size_t alloc = 0;

    *buffer = (char*)xlab_mem_malloc(_mem_alloc);

    if (!*buffer) {
        return NULL;
    }
    alloc = _mem_alloc;

    va_start(ap, format);
    length = vsnprintf(*buffer, alloc, format, ap);
    va_end(ap);

    if (length >= alloc) {
        ptr = realloc(*buffer, length + 1);
        if (!ptr) {
            return NULL;
        }
        *buffer = ptr;
        alloc = length + 1;

        va_start(ap, format);
        length = vsnprintf(*buffer, alloc, format, ap);
        va_end(ap);
    }

    if (length < 0) {
        return NULL;
    }

    ptr = *buffer;
    ptr[length] = '\0';
    *len = length;

    return *buffer;
}
int _xlab_init(void** api, char* confdir)
{
    return 0;
}
void _xlab_exit()
{
}
int _xlab_network_io_accept(int server_fd)
{
    int remote_fd;
    struct sockaddr sock_addr;
    socklen_t socket_size = sizeof(struct sockaddr);

#ifdef ACCEPT_GENERIC
    remote_fd = accept(server_fd, &sock_addr, &socket_size);
    xlab_api->socket_set_nonblocking(remote_fd);
#else
    remote_fd = accept4(server_fd, &sock_addr, &socket_size, SOCK_NONBLOCK);
#endif

    return remote_fd;
}
int _xlab_network_io_read(int socket_fd, void* buf, int count)
{
    ssize_t bytes_read;

    bytes_read = read(socket_fd, (void*)buf, count);

    return bytes_read;
}
int _xlab_network_io_write(int socket_fd, const void* buf, size_t count)
{
    ssize_t bytes_sent = -1;

    bytes_sent = write(socket_fd, buf, count);

    return bytes_sent;
}
int _xlab_network_io_close(int socket_fd)
{
    close(socket_fd);
    return 0;
}
int _xlab_network_io_create_socket(int domain, int type, int protocol)
{
    int socket_fd;

    socket_fd = socket(domain, type, protocol);

    return socket_fd;
}
/* We need to know how to solve the problem with AF_INET and AF_INET6 */
int _xlab_network_io_connect(char* host, int port)
{
    int ret;
    int socket_fd = -1;
    char* port_str = 0;
    unsigned long len;
    struct addrinfo hints;
    struct addrinfo* res, * rp;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    xlab_string_build(&port_str, &len, "%d", port);
    ret = getaddrinfo(host, port_str, &hints, &res);
    xlab_mem_free(port_str);
    if (ret != 0) {
        return -1;
    }
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        socket_fd =_xlab_network_io_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

        if (socket_fd == -1) {
            return -1;
        }

        if (connect(socket_fd,
            (struct sockaddr*)rp->ai_addr, rp->ai_addrlen) == -1) {
            close(socket_fd);
            printf("Can't connect to %s\n", host);
            return -1;
        }

        break;
    }

    return socket_fd;
}
int _xlab_network_io_send_file(int socket_fd, int file_fd, off_t* file_offset, size_t file_count)
{
    ssize_t bytes_written = -1;

    bytes_written = sendfile(socket_fd, file_fd, file_offset, file_count);

    if (bytes_written == -1) {
        return -1;
    }

    return bytes_written;
}
int _xlab_network_io_bind(int socket_fd, const struct sockaddr* addr, socklen_t addrlen, int backlog)
{
    int ret;

    ret = bind(socket_fd, addr, addrlen);

    if (ret == -1) {
        printf("Error binding socket\n");
        return ret;
    }

    ret = listen(socket_fd, backlog);

    if (ret == -1) {
        printf("Error setting up the listener\n");
        return -1;
    }

    return ret;
}
int _xlab_network_io_server(int port, char* listen_addr)
{
    int socket_fd = -1;
    int ret;
    char* port_str = 0;
    unsigned long len;
    struct addrinfo hints;
    struct addrinfo* res, * rp;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    xlab_string_build(&port_str, &len, "%d", port);
    ret = getaddrinfo(listen_addr, port_str, &hints, &res);
    xlab_mem_free(port_str);
    if (ret != 0) {
        printf("Can't get addr info: %s\n", gai_strerror(ret));
        return -1;
    }

    for (rp = res; rp != NULL; rp = rp->ai_next) {
        socket_fd =_xlab_network_io_create_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

        if (socket_fd == -1) {
            printf("Error creating server socket\n");
            return -1;
        }

         xlab_socket_set_tcp_nodelay(socket_fd);
         xlab_socket_reset(socket_fd);
        ret =_xlab_network_io_bind(socket_fd, rp->ai_addr, rp->ai_addrlen, XLAB_SOMAXCONN);

        if (ret == -1) {
            printf("Port %i cannot be used\n", port);
            return -1;
        }
        break;
    }

    return socket_fd;
}

编译后库文件–xlab-liana.so

调用库文件 :

代码如下:

#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/socket.h>
#include <err.h>
#include <unistd.h>

#define PLUGIN_PATH "/tmp/VisualGDB/e/2021Code/xlab_prj/load_so_files/xlab-liana/Debug/xlab-liana.so"
struct plugin_info {
    const char* shortname;
    const char* name;
    const char* version;
    unsigned int hooks;
};
struct plugin_network_io
{
    int (*accept) (int);
    int (*read) (int, void*, int);
    int (*write) (int, const void*, size_t);
    int (*close) (int);
    int (*connect) (char*, int);
    int (*send_file) (int, int, off_t*, size_t);
    int (*create_socket) (int, int, int);
    int (*bind) (int, const struct sockaddr* addr, socklen_t, int);
    int (*server) (int, char*);
};

struct plugin_network_io* plg_netiomap=NULL;


void* xlab_mem_malloc(const size_t size)
{
    void* aux = malloc(size);

    if (!aux && size) {
        perror("malloc");
        return NULL;
    }

    return aux;
}
void xlab_mem_free(void* ptr)
{
    free(ptr);
}

void* xlab_plugin_load(char* path)
{
    void* handle;

    handle = dlopen(path, RTLD_LAZY);
    if (!handle) {
        printf("dlopen() %s", dlerror());
    }

    return handle;
}
void* xlab_plugin_load_symbol(void* handler, const char* symbol)
{
    char* err;
    void* s;

    dlerror();
    s = dlsym(handler, symbol);
    if ((err = dlerror()) != NULL) {
        return NULL;
    }

    return s;
}

/* Just IPv4 for now... */
int xlab_socket_server(int port, char* listen_addr)
{
    int socket_fd;

    socket_fd = plg_netiomap->server(port, listen_addr);

    if (socket_fd < 0) {
        exit(EXIT_FAILURE);
    }

    return socket_fd;
}
int main(int argc, char *argv[])
{
    int server_fd;
    int remote_fd;
    int recv[64];
    int bytes=0;
    char* path = PLUGIN_PATH;
    void* handle;
    char* ip = "0.0.0.0";
    short int port = 2001;
    struct plugin_info* info;
    
    plg_netiomap = xlab_mem_malloc(sizeof(struct plugin_network_io));

    handle = xlab_plugin_load(path);
    if (!handle) {
        printf("Invalid plugin '%s'", path);
    }

    info = (struct plugin_info*)xlab_plugin_load_symbol(handle, "_plugin_info");

    if (!info) {
        printf("Plugin '%s' is not registering properly", path);
        return -1;
    }
    printf("shortname %s\n", info->shortname);
    printf("name %s\n", info->name);
    printf("version %s\n", info->version);
    printf("hooks %d\n", info->hooks );
   
#if 0 //test
    plg_netiomap->connect = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_connect");    
    plg_netiomap->send_file = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_send_file");
    plg_netiomap->create_socket = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_create_socket");
    plg_netiomap->bind = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_bind");
#endif // 0  

    plg_netiomap->accept = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_accept");
    plg_netiomap->server = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_server");
    plg_netiomap->read = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_read");
    plg_netiomap->write = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_write");
    plg_netiomap->close = (int (*)())xlab_plugin_load_symbol(handle, "_xlab_network_io_close");

   /* Server listening socket */
   server_fd=xlab_socket_server(port,ip);
   remote_fd = plg_netiomap->accept(server_fd);
   if (remote_fd == -1) {
       exit(1);
   }
   printf("remote_fd %d\n", remote_fd);
   while (1) {
       bytes = plg_netiomap->read(remote_fd, recv, 4);
      
       if ( bytes> 0) {           
           plg_netiomap->write(remote_fd, recv, 4);
       }
       else if (bytes == 0) {
           plg_netiomap->close(remote_fd);
           break;
       }
       else
       {
          continue;
       }
       usleep(1000000);
   }
   xlab_mem_free(plg_netiomap);
    return 0;
}

测试结果:

总结:

用vs2019+visualGDB这样的方式非常棒,主要是调试方便,且可以断点到so文件内部代码,也就是说调试so文件也很方便,可以断点单步调试…
如下图所示:

下断点后,单步进入即可调试库文件