我正在c中创建一个websocket服务器,因为将服务器关闭,重新编译它,并再次运行它对服务器应用程序应该做的事情适得其反,我正在寻找动态加载我的函数的方法,以便我可以保持主服务器应用程序运行,同时能够更改/创建将在其中使用的新函数。我创建了一个函数,它允许我按名称和正确的参数调用函数,就像你调用一个普通的函数一样,但是当我第二次调用它时,它不会做同样的事情,第二次我动态调用它。要按步骤列出我的问题,请考虑以下情况:
情况1
- 启动服务器应用程序而不动态调用sendMessage
- 通过浏览器连接websocket服务器
- 连接成功后向服务器发送消息(我使用
Hello World
) - 服务器回显客户端发送的消息。
- 再次向服务器发送相同的消息
- 服务器将再次回显消息。(这是当服务器sendMessage函数没有动态加载
- 重复步骤5和6不会导致客户端断开连接。
现在是使用动态版本的服务器sendMessage函数来回显客户端消息的情况。
情况2
- 启动服务器应用程序,同时允许使用loadFunction调用sendMessage。
- 通过浏览器连接websocket服务器
- 连接成功后向服务器发送消息(我再次使用
Hello World
) - 服务器将回显客户端发送的消息。
- 再次向服务器发送相同的消息
- 这次服务器不回显客户端发送的消息。
- 在第一个消息之后发送更多消息最终将导致连接结束(这就是我遇到问题的地方
情况1是当我的函数sendMessage
被正常调用时(不是通过loadFunction
),而情况2是我用loadFunction
调用替换sendMessage
,该调用加载持有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: %dts: %stlen: %dn", sock, s, len);
if (write(sock, reply, strlen(reply)) <= 0) {
printf("nnWE ARE NOT WRITING!!nn");
} else {
//printf("we did writen");
}//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: %sn", 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上访问这里(动态分支是可以找到问题的地方)
另外,我正在使用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
提前感谢。
我已经弄明白我的问题了,这是一个相当奇怪的问题。
当我使用我的动态方法i printf
测试sendMessage
函数时,确切地说,通过套接字发送的是什么,显然它正在发送正确的消息。然而,它也在loadFunction
函数中从我的文件名变量发送字符,这对我来说很奇怪,在调用动态sendMessage
的函数调用之前,当malloc
ed,释放并设置为NULL时,内存地址可以访问sendMessage
。
在我用dlopen(filename, RTLD_LAZY)
打开我的库之后,我使用memset(filename, ' ', filenameLength)
将空字符写入文件名的内存地址,使字符串包含所有空字符,当作为字符访问时,这些字符计数为字符串的结束。
我不知道为什么我不得不在这个应用程序中使用memset这么多,但我知道它已经为我多次修复了字符串错误。