【问题标题】:UDP sender & receiver at the same time CUDP 发送方和接收方同时 C
【发布时间】:2011-07-26 09:43:29
【问题描述】:

我必须编写一个同时充当 UDP 发送方和接收方的 C 应用程序。程序应该首先检测广播地址,然后发送消息JOIN(名字被读取),1次/分钟,然后是一些消息。我理解广播包的部分。我也不知道如何将我的发送者变成接收者。 到目前为止我的代码: ---旧代码---

编辑: 我现在知道我已经在没有 select() 或 poll() 的情况下解决了这个问题,但是使用了 fork()..类似于创建 2 个单独的进程来处理写入套接字和分别从套接字读取数据。我设法发送数据。我在从套接字读取数据时遇到了一些麻烦。我收到的东西就像我发送的字符串的最后一个字符一样。另外,我有一个错误“:无效参数”..我试过调试,但我真的不知道这个错误来自哪里。它出现在我执行 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;
}

我会非常感谢一些建议。

【问题讨论】:

    标签: c udp broadcast


    【解决方案1】:

    您需要做的是暂停您的程序,直到发生以下两种情况之一:

    • 有人向您发送 UDP 消息
    • 时间到了(您需要发送广播消息)

    unix 上的解决方案,如果你想暂停直到发生多件事情之一,是函数select()

    在您的情况下,另一种可能的解决方案是使用非阻塞 I/O 并不时检查新包 - 但这基本上是主动轮询,而主动轮询是坏、坏、坏。

    您的代码面临的问题是您的程序被阻止在recvfrom() 中,直到它收到一条消息。 (注意:我不完全确定您的 SIGALRM 方法是否应该在阻塞的 I/O 等待期间确实有效,但我假设信号会排队,直到您的读取操作完成(收到数据))

    【讨论】:

    • 使用 joanna 使用的 signal(),SIGALRM 不会中断。如果 joanna 使用了 sigaction() ,则有一个 SA_RESTART 标志,当设置为 0 时,大多数系统调用都会产生信号中断。
    【解决方案2】:

    您需要一个选择或轮询循环。有很多与这些相关的 StackOverflow 问题。

    我还建议将您的套接字设置为非阻塞以避免一些罕见的问题。

    或者,如果您在 Windows 上编写,您可以将您的网络设置为使用事件。

    【讨论】:

      【解决方案3】:

      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)、闰秒、日光节省时间,...)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-01-04
        • 2013-11-19
        • 1970-01-01
        • 2021-12-21
        • 1970-01-01
        • 2016-07-28
        • 2016-01-09
        相关资源
        最近更新 更多