UDP-сервер и 2 UDP-клиента на C

#c #udp #udpclient

#c #udp #udpclient

Вопрос:

Я прочитал руководство Beej и создал UDP-сервер и клиент. Я сначала запускаю сервер, а затем запускаю 2 клиента. Предполагается, что сервер обслуживает recevfrom клиента и sendto другого клиента. Когда клиент 1 отправляет что-то, клиент 0 получает это. Когда клиент 0 отправляет что-то, клиент 1 этого не получает. Кто-нибудь может увидеть, что не так с кодом? Я прочитал все вопросы по UDP, C, серверу, чату, но не смог найти ничего, что помогло бы мне. Я компилирую этот код на OSX. Приветствуется любая помощь. Ниже приведен код сервера:

  #include <arpa/inet.h>  
 #include <netinet/in.h>  
 #include <stdio.h>  
 #include <sys/types.h>  
 #include <sys/socket.h>  
 #include <unistd.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #define BUFLEN 512  
 #define PORT 7777  

 void err(char *str)  
 {  
     perror(str);  
     exit(1);  
 }  

 int main(void)  
 {  
     struct sockaddr_in my_addr, cli_addr[2],cli_temp;  
     int sockfd;  
     socklen_t slen[2],slen_temp;
     slen[1]=sizeof(cli_addr[1]); 
     slen[2]=sizeof(cli_addr[2]);
     slen_temp = sizeof(cli_temp);
     char buf[BUFLEN];  
     int clients = 0;
     int client_port[2];

     if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
     {
         printf("testn");
         err("socket");  
     }else{  
         printf("Server : Socket() successfuln");  
     }   
     bzero(amp;my_addr, sizeof(my_addr));  
     my_addr.sin_family = AF_INET;  
     my_addr.sin_port = htons(PORT);  
     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);  

     if (bind(sockfd, (struct sockaddr* ) amp;my_addr, sizeof(my_addr))==-1)
     {
         err("bind");  
     }else{
         printf("Server : bind() successfuln");  
     }

     while(1)  
     {
         //receive
         printf("Receiving...n");
         if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_temp, amp;slen_temp)==-1)  
             err("recvfrom()");
         if (clients==0) {
             //first connection
             //store the temp connection details to the array
             cli_addr[0] = cli_temp;
             //get client 0 port
             client_port[0] = ntohs(cli_addr[0].sin_port);
             clients  ;
             printf("Client 0 connected. Port: %dn",client_port[0]);
             sendto(sockfd, "You are the only client.", 24, 0, (struct sockaddr*)amp;cli_temp, slen_temp);
         }else if (clients==1) {
             //new or existing
             if (client_port[0]==ntohs(cli_temp.sin_port)) {
                 //send back to client 0 that nobody else connected yet
                 sendto(sockfd, "You are the only client.", 24, 0, (struct sockaddr*)amp;cli_addr[0], slen[0]);
                 printf("Only clientn");
             }else{
                 //new connection
                 cli_addr[1] = cli_temp;
                 client_port[1] = ntohs(cli_addr[1].sin_port);
                 clients  ;
                 printf("GOt second clientn");
                 sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[0], slen[0]);
             }
        }else{
            //there are 2 clients connected here. If we get an error from the sendto then we decrement clients
            if (client_port[0]==ntohs(cli_temp.sin_port)) {
                //client 0 talking send to client 1
                printf("Sedning message to client 1n");
                if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[1], slen[1])==-1)
                {
                    clients--;
                    err("sendto()");
                }
            }else {
                //client 1 talking send to client 0
                printf("Sending message to client 0n");
                if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[1], slen[1])==-1)
                {
                    clients--;
                    err("sendto()");
                }
            }

        }
        //printf("Received packet from %s:%dnData: %sn",  
        //        inet_ntoa(cli_addr[clients].sin_addr), ntohs(cli_addr[clients].sin_port), buf);  
     }  

     close(sockfd);  
     return 0;  
}
  

И клиент:

 #include <arpa/inet.h>  
#include <netinet/in.h>  
#include <stdio.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#define BUFLEN 512  
#define PORT 7777  

void err(char *s)  
{  
    perror(s);  
    exit(1);  
}  
sig_atomic_t child_exit_status;

void clean_up_child_process (int signal_number) 
{
    /* Clean up the child process. */ 
    int status; 
    wait (amp;status); 
    /* Store its exit status in a global variable. */ 
    child_exit_status = status;
}
 int main(int argc, char** argv)  
 {  
     struct sockaddr_in serv_addr;  
     int sockfd, slen=sizeof(serv_addr);  
     char buf[BUFLEN];  
     struct sigaction sigchld_action; 
     memset (amp;sigchld_action, 0, sizeof (sigchld_action)); 
     sigchld_action.sa_handler = amp;clean_up_child_process; 
     sigaction (SIGCHLD, amp;sigchld_action, NULL);
     int pid,ppid;

     if(argc != 2)  
     {  
       printf("Usage : %s <Server-IP>n",argv[0]);  
       exit(0);  
     }  

     if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)  
         err("socket");  

     bzero(amp;serv_addr, sizeof(serv_addr));  
     serv_addr.sin_family = AF_INET;  
     serv_addr.sin_port = htons(PORT);  
     if (inet_aton(argv[1], amp;serv_addr.sin_addr)==0)  
     {  
         fprintf(stderr, "inet_aton() failedn");  
         exit(1);  
     }
     pid = fork();
     if (pid<0) {
         err("Fork Error");
     }else if (pid==0) {
         //child process will receive from server
         while (1) {
             bzero(buf,BUFLEN);
             printf("Attempting to READ to socket %d: ",sockfd);
             fflush(stdout);
             //recvfrom here
             if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;serv_addr, amp;slen)==-1)  
                 err("recvfrom()");

             printf("The message from the server is: %s n",buf);
             if (strcmp(buf,"byen") == 0) {
                 ppid = getppid();
                 kill(ppid, SIGUSR2);

                 break;
             }
         }
     }else {
         //parent will send to server
         while(1){
             printf("Please enter the message to send: ");
             bzero(buf,BUFLEN);
             fgets(buf,BUFLEN,stdin);
             printf("Attempting to write to socket %d: ",sockfd);
             fflush(stdout);
             //send to here
             if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;serv_addr, slen)==-1)
             {
                 err("sendto()");
             }
         }
     }
     close(sockfd);  
     return 0;  
}
  

Спасибо.

Ответ №1:

В начале main у вас есть этот код:

  struct sockaddr_in my_addr, cli_addr[2],cli_temp;  
 int sockfd;  
 socklen_t slen[2],slen_temp;
 slen[1]=sizeof(cli_addr[1]); 
 slen[2]=sizeof(cli_addr[2]);
  

Это должно быть изменено на:

  struct sockaddr_in my_addr, cli_addr[2],cli_temp;  
 int sockfd;  
 socklen_t slen[2],slen_temp;
 slen[0]=sizeof(cli_addr[0]); 
 slen[1]=sizeof(cli_addr[1]);
  

Я просмотрел остальную часть вашего кода и не увидел никаких других ошибок. Я не уверен, решит ли это вашу проблему, но это определенно неправильно.

(вы, вероятно, знаете это, но) это неправильно, потому что первым элементом массива является array[0] , не array[1] , поэтому, если у вас есть массив с 2 элементами, то array[2] он не будет существовать.

Обновить

Изменение

 else {
            //client 1 talking send to client 0
            printf("Sending message to client 0n");
            if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[1], slen[1])==-1)
            {
                clients--;
                err("sendto()");
            }
        }
  

Для

 else {
            //client 1 talking send to client 0
            printf("Sending message to client 0n");
            if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[0], slen[1])==-1)
            {
                clients--;
                err("sendto()");
            }
        }
  

Комментарии:

1. изменил его, но остался тем же.

Ответ №2:

В вашем коде у вас есть следующее:

         // there are 2 clients connected here. If we get an error from the sendto
        // then we decrement clients
        if (client_port[0]==ntohs(cli_temp.sin_port)) {
            //client 0 talking send to client 1
            printf("Sedning message to client 1n");
            if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[1], slen[1])==-1)
            {
                clients--;
                err("sendto()");
            }
        }else {
            //client 1 talking send to client 0
            printf("Sending message to client 0n");
            if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)amp;cli_addr[1], slen[1])==-1)
            {
                clients--;
                err("sendto()");
            }
        }
  

Обратите внимание, что оба раздела (от 1 до 0, а также от 0 до 1) отправляют в amp;cli_addr[1] . Для меня это похоже на ошибку.

Комментарии:

1. Вы нереальны. Теперь он работает так, как должен. Миллион благодарностей