前言:
本笔记记录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文件也很方便,可以断点单步调试…
如下图所示:
下断点后,单步进入即可调试库文件