c - UDP 服务器只响应一个客户端

标签 c sockets udp client server

我有一些用于 UDP 服务器和客户端的 C 代码(它必须是 UDP,而不是 TCP)。我在尝试向所有连接的客户端发送消息时遇到问题。

当服务器收到来自客户端的消息时,它可以回复同一个客户端,但它不会为其他连接的客户端提供服务。 有人可以帮我解决这个问题吗?

服务器.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "lib/colors/colors.h"
#include "lib/simlist/simclist.h"



typedef char* string; // to make life easier

#define PORT "9034"

void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

    int main(void){

        fd_set master;    
        fd_set read_fds;  
        int fdmax;        
        int listener;     
        int newfd;     

        struct sockaddr_storage remoteaddr; 
        socklen_t addrlen;

        char buf[1024];    
        int nbytes;

        char remoteIP[INET6_ADDRSTRLEN];

        int yes = 1;       
        int i, j, rv;

        struct addrinfo hints, *ai, *p;

        FD_ZERO(&master);    
        FD_ZERO(&read_fds);

        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_PASSIVE;
        rv = getaddrinfo(NULL, PORT, &hints, &ai);

    /* simlist initialisation */
        list_t clients;
        typedef struct client{
            fd_set socket_number;
            char *username[100];
        } client;

        list_init(&clients);

        client new_client;
        string client_username;
    /* end of simlist */

        if ( rv != 0) {
            fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
            exit(1);
        }

        for(p = ai; p != NULL; p = p->ai_next) {

            listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

            if (listener < 0) {
                continue;
            }

            setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));

            if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
                close(listener);
                continue;
            }
            break;
        }

        if (p == NULL) {
            printf( "failed to bind\n");
            exit(2);
        }

        freeaddrinfo(ai);

        if (listen(listener, 10) == -1) {
            perror("listen");
            exit(3);
        }

        FD_SET(listener, &master);
        fdmax = listener;

        for(;;) {
            read_fds = master;
            if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
                perror("select");
                exit(4);
            }

            for(i = 0; i <= fdmax; i++) {

                if (FD_ISSET(i, &read_fds)) {

                    if (i == listener) {
                        addrlen = sizeof remoteaddr;
                        newfd = accept(listener,
                            (struct sockaddr *)&remoteaddr,
                            &addrlen);

                        if (newfd == -1) {
                            perror("accept");
                        } else {
                            FD_SET(newfd, &master);
                            if (newfd > fdmax) {
                                fdmax = newfd;
                            }
                            // @TODO
                            // insert into list user, ip, port combination
                            printf("new connection from %s on socket %d\n",
                                inet_ntop(remoteaddr.ss_family,
                                    get_in_addr((struct sockaddr*)&remoteaddr),
                                    remoteIP, INET6_ADDRSTRLEN),
                                newfd);
                        }
                    } else {
                        nbytes = recv(i, buf, sizeof buf, 0);
                        printf("nb of bytes received : %d \n", nbytes);
                        if ( nbytes <= 0) {
                            if (nbytes == 0) {
                                printf("%s socket %d hung up \n", warning_msg(""), i);
                                // delete user from list
                            } else {
                                perror("recv");
                            }
                            close(i);
                            FD_CLR(i, &master);
                        } else {
                            // data received from client
                            for(j = 0; j <= fdmax; j++) {
                                // send to everyone!
                                if (FD_ISSET(j, &master)) {
                                    // except the listener and ourselves
                                    if ( j != listener || j != i) {
                                        printf("available sockets %d \n", j);
                                        printf("SENDING : %s\n", buf);
                                        send(j,buf,nbytes, 0);
                                        // if (send(j, buf, nbytes, 0) == -1) {
                                        //  perror("send");
                                        // }
                                    }
                                }
                            }
                        }

                    }
                }
            }
        }

        return 0;
    }

客户端.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "lib/colors/colors.h"

#define PORT "9034"

#define MAXDATASIZE 1024

void *get_in_addr(struct sockaddr *sa){
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(int argc, char *argv[]){
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];

    if (argc != 3) {
        fprintf(stderr,"usage: ./client [hostname] [username] \n");
        exit(1);
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
            perror("client: socket");
        continue;
    }

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("client: connect");
        continue;
    }

    break;
}

if (p == NULL) {
    fprintf(stderr, "client: failed to connect\n");
    return 2;
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
printf("client: connecting to %s\n", s);

char *username = argv[2];
send(sockfd, username, MAXDATASIZE-1, 0);

while(1){
    char word[MAXDATASIZE];
    printf(">");
    fgets(word, sizeof(word), stdin);
    send(sockfd, word, MAXDATASIZE-1, 0);
    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    exit(1);
    }else{
        printf("RECEIVED : %s\n",buf);    
    }

}

freeaddrinfo(servinfo);


buf[numbytes] = '\0';

printf("client: received '%s'\n",buf);

close(sockfd);

return 0;
}

最佳答案

您想要的方式(向每个连接的 客户端发送消息)需要单独处理每个客户端。您可以通过遍历连接表向每个客户端发送一条消息来做到这一点。这与您已有的没有太大区别。

如果你想做“真正的”广播,如果其他未连接机器也收到消息并不重要,请查找广播(如果你只在同一网段内工作没有在您的路由器上配置特殊的 IP 助手)和/或多播。

关于c - UDP 服务器只响应一个客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29645504/

相关文章:

c - 'typedef in C' 有什么用?

android - Asynctask 无法显示服务器响应

javascript - Socket.io 在使用命名空间时不发出/接收事件

c++ - 无法在matlab中的UDP客户端和linux中的服务器之间发送数据

opencv - 多个应用程序访问同一个 DeckLink 设备(openCV 和 rtmp 推送)?我有什么选择?

java - 需要java中udp套接字编程的帮助

c - 从 C 独立调用 (GNU) Prolog 的示例

c - 使用堆栈和二叉树c构建表达式树

c - 函数指针结构体数组 C

C++ 从 HTTP 响应中获取图片