gpt4 book ai didi

c - 第一次 dlopen 后共享库函数可以正常工作

转载 作者:行者123 更新时间:2023-11-30 17:33:38 24 4
gpt4 key购买 nike

我正在用 C 创建一个 websocket 服务器。由于关闭服务器、重新编译它并再次运行它与服务器应用程序应该做的事情适得其反,我正在寻找动态加载我的函数的方法,以便我可以保持主服务器应用程序运行,同时能够更改/创建将在其中使用的新功能。我创建了一个函数,它允许我使用正确的参数按名称调用函数,就像正常的函数调用一样,但是当我第二次调用它时,它不会在我第二次动态调用它时执行相同的操作。要按步骤列出我的问题,请考虑以下情况:

情况1

  1. 启动服务器应用程序而不动态调用 sendMessage。
  2. 通过浏览器连接到 websocket 服务器。
  3. 连接成功后向服务器发送消息(我使用 Hello World)
  4. 服务器将回显客户端发送的消息。
  5. 再次向服务器发送相同的消息。
  6. 服务器将再次回显消息。 (这是当服务器sendMessage函数没有动态加载时
  7. 重复步骤 5 和 6 不会导致客户端断开连接。

现在使用服务器 sendMessage 函数的动态版本来回显客户端消息的情况。

情况2

  1. 启动服务器应用程序,同时允许使用 loadFunction 调用 sendMessage。
  2. 通过浏览器连接到 websocket 服务器。
  3. 连接成功后,向服务器发送一条消息(我再次使用 Hello World)
  4. 服务器将按照应有的方式回显客户端发送的消息。
  5. 再次向服务器发送相同的消息。
  6. 这次服务器不会回显客户端发送的消息。
  7. 在第一条消息之后发送更多消息最终将导致连接结束(这就是我遇到问题的地方

情况 1 是我的函数 sendMessage 被正常调用(不是通过 loadFunction),而情况 2 是我将 sendMessage 替换为我的 loadFunction 调用加载包含 sendMessage 的库,将其分配给位置函数变量(请参阅代码)并像平常一样调用该函数。

我认为问题在于动态加载时 sendMessage 中的 write 函数。但是当我不动态加载它时,该函数可以完美地工作,这对我来说很奇怪。

我的问题是为什么我的 sendMessage 函数的运行方式与我正常调用它和动态调用它时不同?下面是两种情况的一些代码和输出

sendMessage.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include "include/structs.h"
//#include "include/functions.h"

/*
* sendMessage: this function is used then we want to send message (s)
* of length (len) from the server to a client (sock)
*
* ARGUMENTS
* sock: the socket where we want the message to go
* s: A string containing the message we want to send
* len: the length of the string s
*/
void *sendMessage(int sock, char *s, int len) {
int frameCount;
uint16_t len16;
char frame[10];
char *reply = malloc(sizeof(char) * (len + 8));

frame[0] = '\x81';

if (len <= 125) {
frame[1] = len;
frameCount = 2;
} else if (len >= 126 && len <= 65535) {
frame[1] = 126;
len16 = htons(len);
memcpy(frame + 2, &len16, 2);
frameCount = 4;
} else {
frame[1] = 127;
//NOTE: HAVE NOT FULLY CONFIGURED A MESSAGE OF THIS LENGTH (TODO)
//frame[2] = (char)( ((char)len >> 56) & (char)255 );
//frame[3] = (char)( ((char)len >> 48) & (char)255 );
//frame[4] = (char)( ((char)len >> 40) & (char)255 );
//frame[5] = (char)( ((char)len >> 32) & (char)255 );
//frame[6] = (char)( ((char)len >> 24) & (char)255 );
frame[7] = (char)( ((char)len >> 16) & (char)255 );
frame[8] = (char)( ((char)len >> 8) & (char)255 );
frame[9] = (char)( ((char)len) & (char)255 );
frameCount = 10;
}//END IF

memcpy(reply, frame, frameCount);
memcpy(reply + frameCount, s, len);

//printf("sock: %d\ts: %s\tlen: %d\n", sock, s, len);
if (write(sock, reply, strlen(reply)) <= 0) {
printf("\n\nWE ARE NOT WRITING!!\n\n");
} else {
//printf("we did write\n");
}//END IF

free(reply);
reply = NULL;

return NULL;
}//END FUNCTION

loadFunction.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "include/functions.h"

int checkForError(char *error) {
if (error != NULL) {
printf("ERROR: %s\n", error);
exit(EXIT_FAILURE);
}//END IF

return 0;
}//END IF

void * loadFunction(char *func, void ** args) {
void *handle;
//void * (*alterStruct)(int sock, char *action);

int filenameLength;
char * filename;
//void *(*funcPtr);


filenameLength = strlen("lib/lib") + strlen(func) + strlen(".dll");
filename = malloc(sizeof(char) * (filenameLength + 1));
strcpy(filename, "lib/lib");
strcat(filename, func);
strcat(filename, ".dll");

handle = dlopen(filename, RTLD_LAZY);
free(filename);
if (!handle) {
checkForError(dlerror());
}//END IF

dlerror();

if (strncmp(func, "sendMessage", strlen(func)) == 0) {
void * (*funcPtr)(int, char *, int);
//*(void **) (&funcPtr) = dlsym(handle, func);
funcPtr = (void *)dlsym(handle, func);
checkForError(dlerror());
(*funcPtr)((int)args[0], (char *)args[1], (int)args[2]);
//free(*(void **)(&funcPtr));
//*(void **) (&funcPtr) = NULL;
}// else if (strncmp(func, "alterStruct", strlen(func)) == 0) {
//void * (*funcPtr)(int sock, char *action);
//} else if (strncmp(func, "execute", strlen(func)) == 0) {
//void * (*funcPtr)(const char *command, clientStruct s, FILE **in, FILE **out, FILE **err);
//} else {
//void * (*funcPtr)(int sock, char *s, int len);
//}//END IF

dlclose(handle);
handle = NULL;
return NULL;


return NULL;

}//END loadFunction

如果您需要更多代码来解决这个问题,我可以在 GitHub here 上访问它。 (动态分支就是可以发现问题的地方)

此外,我正在使用 Cygwins 的 GNU gcc 编译器(我在编译时从未遇到过问题)来编译我的应用程序和库,因此我可能无法访问某些 Linux 命令(例如 dlmopen) >)。也就是说,请不要说使用不同的编译器,因为到目前为止我没有遇到其他问题,并且我不打算更改编译代码的方式。

我没有记录用于编译 loadFunction 中使用的 libsendMessage.dll 的命令。您可以使用以下方式获取它

gcc -c -fPIC sendMessage.c
mv sendMessage.o objects/sendMessage.o
gcc -shared -o lib/libsendMessage.dll objects/sendMessage.o libfunctions.c

提前谢谢您。

最佳答案

我已经解决了我的问题,而且这是一个很奇怪的问题。

当我测试sendMessage时使用我的动态方法的函数 i printf正是通过套接字发送的内容,显然它正在发送正确的消息。但是,它还发送 loadFunction 中我的文件名变量中的字符。函数对我来说很奇怪,内存地址可以访问 sendMessage当它是malloc时在函数调用动态 sendMessage 之前以 ed、free 和 set to NULL 的方式进行处理被叫了。

解决方案

当我用dlopen(filename, RTLD_LAZY)打开我的图书馆后我用过memset(filename, '\0', filenameLength)将空字符写入文件名的内存地址,使字符串包含所有空字符,当作为字符访问时,这些空字符计为字符串的结尾。

我不确定为什么我必须在这个应用程序中使用这么多 memset,但我知道它多次为我修复了字符串错误。

关于c - 第一次 dlopen 后共享库函数可以正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23701416/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com