我在C中创建一个websocket服务器。由于关闭服务器,重新编译它,再次运行它会对服务器应用程序应该做什么起反作用,我正在寻找动态加载我的函数的方法,这样我就可以保持主服务器应用程序运行,同时能够更改/创建将在其中使用的新功能。我创建了一个函数,允许我通过正确的参数调用一个函数,就像你正常的函数调用一样,但是当我第二次调用它时,第二次它不会做同样的事情,我第二次动态调用它。要按步骤列出我的问题,请考虑以下情况:
情况1
Hello World
)现在使用动态版本的服务器sendMessage函数来回显客户端消息。
情况2
Hello World
)情况1是指我的函数sendMessage
被正常调用(而不是通过loadFunction
),而情境2是我用加载库的sendMessage
调用替换loadFunction
的地方保持sendMessage
,将其分配给位置函数变量(参见代码)并像通常那样调用函数。
我认为问题在于sendMessage
中的动态加载时的写函数。但是当我不动态加载它时,该功能可以正常工作,这对我来说很奇怪。
我的问题是为什么我的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&#39; 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
提前谢谢。
答案 0 :(得分:0)
我已经发现了我的问题,这是一个奇怪的问题。
当我使用我的动态方法i sendMessage
测试printf
函数时,确切地说是通过套接字发送了什么,显然它正在发送正确的消息。但是,它也发送了loadFunction
函数中我的文件名变量中的字符,对我来说奇怪的是,当sendMessage
malloc
编辑,释放和设置时,内存地址可以访问sendMessage
在调用动态dlopen(filename, RTLD_LAZY)
的函数之前调用NULL方式。
<强>解决方案强>
用memset(filename, '\0', filenameLength)
打开我的库后,我使用{{1}}将空字符写入filename的内存地址,使字符串包含所有空字符,当作为字符访问时计为字符串的结尾
我不确定为什么我必须在这个应用程序中使用memset,但我知道它已多次修复了我的字符串错误。