我必须编写一个同时充当UDP发送者和放大器的C应用程序。接收器。程序应首先检测广播地址,然后发送消息JOIN(名称被读取),1次/分钟,然后发送一些消息。我理解有广播包的部分。我无法弄清楚如何将发件人变成接收器。 我的代码到目前为止: ---旧代码---
编辑: 我现在知道我已经解决了这个没有select()或poll(),但是使用fork()..就像创建2个单独的进程一样,它们将处理写入套接字并分别从套接字读取数据。我设法发送数据。我有一些麻烦从套接字读取数据。我收到smth就像我发送的字符串的最后一个字符。此外,我有一个错误“:无效的参数”..我已经尝试过调试,但我真的不知道这个错误来自哪里。它出现在我执行fork()之后。我必须能够忽略我以某种方式发送的消息,但是在本地测试它会让人感到困惑(我必须接收来自其他人的消息,并且知道向我发送消息的IP地址)。现在,如果我启动应用程序两次,在一个应用程序中,我不接收来自另一个应用程序的消息,只是应用程序发送的最后一个字符。 这是我的代码:
#includes..
#define MAXLEN 100
#define MAXNAME 20
#define PORT 8888
#define MAX 20
int sockfd;
struct sockaddr_in socket_in; //connector's info
char name[MAXNAME];
int numbytes;
char senders[MAX];
void sendJoin (int signal) {
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
}
void leaveGroup(int signal) {
/* Broadcast LEAVE and end execution */
char msg[10];
strcpy(msg, "LEAVE\0");
if ((numbytes=sendto(sockfd, msg, strlen(msg), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendLEAVE");
exit(1);
}
printf("\nSent LEAVE message to %s (%d bytes)\n", inet_ntoa(socket_in.sin_addr),numbytes);
scanf("%s", msg);
close(sockfd);
exit(1);
}
void read_socks() {
char message[MAXLEN];
int size = sizeof(socket_in);
numbytes = recvfrom (sockfd, &message, 1, 0,
(struct sockaddr*) &socket_in, &size);
if(strcmp(message, name)!=0) {
printf("Received: %s\n", message);
}
}
int main(void){
struct hostent *hst;
int broadcast = 1;
if ((hst=gethostbyname("192.168.240.255")) == NULL) { // get the host info
perror("gethostbyname");
exit(1);
}
if((sockfd=socket(AF_INET, SOCK_DGRAM, 0))==-1) {
perror("socket");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))==-1){
perror("setsockopt(SO_BROADCAST)");
exit(1);
}
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
signal(SIGINT, leaveGroup);
signal(SIGALRM, sendJoin);
printf("NAME: ");
fgets(name,MAXNAME,stdin);
strcpy(name,strcat("JOIN: ", name));
name[strlen(name)-1]='\0';
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
printf("Sent %s to %s (%d bytes)\n", name,inet_ntoa(socket_in.sin_addr),numbytes);
alarm(5);
while (1)
{
int pid = fork();
if(pid==0){ //Child process reads from the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
sockfd = bind(sockfd, (struct sockaddr*) &socket_in, sizeof(socket_in));
if(sockfd==-1) perror("Bind error. Port is already in use!");
read_socks();
exit(0);
}
else if(pid > 0){ //Parent process sends data through the socket
memset(&socket_in, 0, sizeof(socket_in));
socket_in.sin_family = AF_INET;
socket_in.sin_port = htons(PORT);
socket_in.sin_addr = *((struct in_addr *)hst->h_addr);
if ((numbytes=sendto(sockfd, name, strlen(name), 0,
(struct sockaddr *)&socket_in, sizeof(socket_in))) == -1) {
perror("sendto");
exit(1);
}
}
sleep(4);
}
close(sockfd);
return 0;
}
我会非常感激地提出一些建议。
答案 0 :(得分:1)
您需要选择或轮询循环。有很多与这些相关的StackOverflow问题。
我还建议将套接字设置为非阻塞,以避免一些罕见的问题。
或者,如果您在Windows上编写,则可以将网络设置为使用事件。
答案 1 :(得分:0)
您需要做的是暂停您的计划,直到发生以下两种情况之一:
unix上的解决方案,如果你想暂停直到多个事情之一发生,那就是函数select()
。
在您的情况下,另一种可能的解决方案是使用非阻塞I / O并偶尔检查新包 - 但这基本上是主动轮询,主动轮询是坏,坏,坏。
您的代码遇到的问题是您的程序在recvfrom()
被阻止,直到收到消息为止。 (注意:我不能完全确定您的SIGALRM方法是否应该在阻塞的I / O等待期间确实有效,但我假设信号排队等待您的读取操作完成(收到数据))
答案 2 :(得分:0)
select(2)
,poll(2)
和亲戚让您等待文件描述符和超时事件。
使用其中一个系统调用时,无需使用alarm()
。 alarm()
有时用于在超时时启动read(2)
或write(2)
来电(尽管我更喜欢使用select()
,即使在这种情况下,也就是说我不在乎谁其他人可能正在使用SIGALARM
)。
超时到期时,poll()
和select()
都会返回0
。一些select()
实现使用剩余时间更新timeout
参数,而其他实现则不会。在任何情况下,由于select()
或poll()
可能早先被唤醒以处理某些其他事件(或因为它们被信号中断),所以要做的是检查超时是否真的已过期/重新计算超时,这是传统上使用time(2)
或gettimeofday(2)
完成的事情,但现在应该使用clock_gettime(2)
和CLOCK_MONOTONIC
时钟更好地完成,这是免费的时钟调整(date(1)
,闰秒,夏令时,......)。