execl 在服务器端的 while(1) 循环中不起作用; C脚本
我有一个小 C 脚本的问题,它应该作为服务器运行并为每条到达的消息启动一个弹出窗口。 execl 语法是正确的,因为如果我尝试一个小脚本,
main() { execl(...); }
它就可以工作。
当我将它放入 while(1) 循环中时,它不起作用。其他一切都正常,例如 printf 或字符串操作,但 execl 不行。即使我分叉也不起作用。 我怎样才能让它发挥作用?
我尝试过使用 fork(),但它也不起作用。
这是完整的服务器 C 代码。
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#define BUFLEN 512
#define PORT 9930
void diep(char *s) {
perror(s);
exit(1);
}
int main() {
struct sockaddr_in si_me, si_other;
int s, i, slen=sizeof(si_other), broadcastPermission;
char buf[100], zeni[BUFLEN];
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("socket");
broadcastPermission = 1;
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
diep("setsockopt() failed");
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, &si_me, sizeof(si_me))==-1)
diep("bind");
while (1) {
if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1) diep("recvfrom()");
//printf("Received packet from %s:%d\nData: %s\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
strcpy(zeni, "");
strcat(zeni, "zenity --warning --title Hack!! --text ");
strcat(zeni, buf);
printf("cmd: %s\n", zeni);
//system (zeni);
execl("/usr/bin/zenity", "/usr/bin/zenity", "--warning", "--title", "Warn!", "--text", buf, (char *) NULL);
}
close(s);
return 0;
}
I have a problem with a little C script which should run as a server and launch a popup for every message arriving.
The execl syntax is correct because if I try a little script with
main() { execl(...); }
it works.
When I put it in a while(1) loop it doesn't work. Everything else is working, like printf
or string operation, but not the execl
. Even if I fork it doesn't work.
How can I make it work?
And I've tried with the fork()
, but it doesn't work either.
Here's the complete server C code.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#define BUFLEN 512
#define PORT 9930
void diep(char *s) {
perror(s);
exit(1);
}
int main() {
struct sockaddr_in si_me, si_other;
int s, i, slen=sizeof(si_other), broadcastPermission;
char buf[100], zeni[BUFLEN];
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("socket");
broadcastPermission = 1;
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
diep("setsockopt() failed");
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, &si_me, sizeof(si_me))==-1)
diep("bind");
while (1) {
if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1) diep("recvfrom()");
//printf("Received packet from %s:%d\nData: %s\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
strcpy(zeni, "");
strcat(zeni, "zenity --warning --title Hack!! --text ");
strcat(zeni, buf);
printf("cmd: %s\n", zeni);
//system (zeni);
execl("/usr/bin/zenity", "/usr/bin/zenity", "--warning", "--title", "Warn!", "--text", buf, (char *) NULL);
}
close(s);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
@jweyrich 已经指出了使用
recvfrom
的一些问题,但是还有一个更根本的问题。该代码最多只会执行一次。这是因为
exec
系列系统调用(包括execl
)将当前执行的程序替换为execl
调用中给出的程序。实际上,execl
永远不会返回,除非出现错误。要在unix中创建新的子进程,必须首先调用
fork
,它克隆现有进程,然后在子进程中调用execl
(或一些相关的系统调用)来将子进程替换为您实际要运行的程序。手动正确执行此操作有些棘手,因此system
函数会为您完成此操作,但它有其自身的缺点。@jweyrich has already pointed out some problems with your use of
recvfrom
, however there is a more fundamental problem. The codewill only ever execute at most once. This because the
exec
family of system calls (includingexecl
) replace the the program currently executing with the one given in the call toexecl
. In effect,execl
never returns, except with an error.To create a new child process in unix, you must first call
fork
, which clones the existing process, and then within the child callexecl
(or some related system call) to replace child process with the program you actually want to run. Doing this correctly manually is somewhat tricky, so thesystem
function wraps this up for you, however it has it's own drawbacks.对
recvfrom
的调用中存在堆栈溢出。我相信你混合了两个缓冲区。您使用的是
buf
,其大小为 100,但指定其大小为 BUFLEN,即 512。每当有人发送超过 100 个字节时,您的程序很可能会崩溃。除此之外,
recvfrom
可能不会返回,因为它没有接收到任何内容。你的 printf 正在执行吗?更新:正如 @Daniel 和 @Dale 所指出的,除非发生错误,否则 execl 不会返回。引用手册页:
作为替代方案,您可以使用
system
。There's a stack overflow in your call to
recvfrom
.I believe you mixed the 2 buffers. You're using
buf
, which has size 100, but telling its size is BUFLEN, which is 512. Whenever someone sends more than 100 bytes, it's very likely your program is going to crash.Besides that, it's possible that the
recvfrom
is not returning because it isn't receiving anything. Is yourprintf
being executed?UPDATE: as pointed by @Daniel and @Dale,
execl
won't return unless an error occurs. Quoting from the man-page:As alternative, you can use
system
.请阅读 exec(3) 手册页。
在你的情况下 execl 系统调用将用以下图像替换当前进程图像
/usr/bin/zenity”。
您有两种解决方案:使用您尝试过的 system(3) 或执行 fork 并在子进程中运行 execlp。
Please read exec(3) man page.
In your case execl system call will replace current processes image with the image of
/usr/bin/zenity".
You have two solutions: use system(3) as you tried there or do a fork and inside the child run execlp.