代码之家  ›  专栏  ›  技术社区  ›  slim71

C-通过套接字向客户端发送UDP消息

  •  -1
  • slim71  · 技术社区  · 6 年前

    我有一个简单的问题。 至少我认为这很简单!

    我正在做一个大学项目,我构建了一个服务器客户端即时消息服务,其结构如下:
    -服务器创建 套接字 侦听客户端请求
    -除了其他功能外,每个客户端都可以向另一个客户端发送消息包(即使是脱机) 使用UDP

    我为服务器使用了端口4242,然后尝试为两个示例客户端使用4243和4244。

    我的问题是:这些端口是否不可用于UDP通信?
    我这样问是因为当我尝试向这些端口发送消息时,接收客户端会获取并打印“奇怪”字符串。
    准确地说 ,因为它存储了先例消息,并首先打印新消息,然后打印一大块先例消息。
    另一方面,如果我使用例如4303和4486,它将按预期工作。

    我看到了那些数字 Wikipedia ,但由于我不确定如何解释该表(因此,如果我解释正确的话),而且我知道维基百科不太可靠,我想我可以在这里问一下。

    另一方面,如果我提供的链接不可靠,是否有任何命令或资源来检查这些内容?

    提前感谢!

    编辑:

    这是我的密码!我以前无法上传。。我也会试着给你一个简短的解释。
    正如我在评论中提到的,我认为我已经收到了,但一个客户没有收到另一个客户的消息。所以,所有的工作,除了!发送功能,我想。。。

    客户
    客户端是使用“!register username”连接到服务器的用户;此命令:
    -如果客户端是第一次连接到该服务,则将其注册到该服务,并将其设置为“联机”
    -如果客户端已注册到服务,则重新连接客户端;在这种情况下,如果有一些脱机消息,服务器会将其传递给te客户端

    连接后,客户端可以使用以下命令:
    1) 哦!帮助:显示可用命令
    2) 哦!谁:显示在线用户
    3) 哦!注销:正如nam所建议的,从服务器注销客户端
    4) 哦!发送用户名:如果目标客户端联机,服务器返回UDP目标地址和端口,客户端直接发送消息;如果目标客户端脱机,服务器将存储消息,以便在连接目标客户端后将其发送到目标客户端

        #include <stdlib.h>
        #include <string.h>
        #include <arpa/inet.h>
        #include <netinet/in.h>
        #include <sys/types.h>
        #include <sys/socket.h>
        #include <unistd.h>
        #include <stdio.h>
    
        #define DIM 1024
        #define ADDR_DIM 16
        #define PORT_DIM 5
        #define CMD_DIM 12
        #define NAME_DIM 21
    
        void cl_help(int sckt) {
        int rv, length, l;
        char* text = "!help";
        char answer[DIM];
    
        length = strlen(text);
        l = htons(length);
    
        //Sending command dimension
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    
        //Sending the command itself
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
        puts(answer);
        }
    
        void cl_quit(int sckt) {
        int rv, length, l;
        char* text = "!quit";
        char answer[DIM];
    
        length = strlen(text);
        l = htons(length);
    
        //Sending command dimension
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    
        //Sending the command itself
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
        puts(answer);
        }
    
        void cl_who(int sckt) {
        int rv, length, l, n_net, n, i;
        char* text = "!who";
        char answer[DIM];
    
        length = strlen(text);
        l = htons(length);
    
        //Sending the dimension of the command
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    
        //Sending the command itself
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
        puts(answer);
    
        if( (strcmp(answer, "Nessun utente in linea") != 0)\
            && (strcmp(answer, "Devi essere connesso per poter utilizzare questa funzione") != 0) ) { //No user online; Yuo have to be registered
    
            //Receiving number of users online
            rv = recv(sckt, (void*) &l, sizeof(l), 0);
            if(rv < 0) {};
    
            length = ntohs(l);
    
            rv = recv(sckt, (void*) &n_net, length, 0);
            if(rv < 0) {};
    
            n = ntohs(n_net);
    
            //Getting every username
            for(i=0; i<n; i++) {
                rv = recv(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                length = ntohs(l);
    
                rv = recv(sckt, (void*) answer, length, 0);
                if(rv < 0) {};
    
                answer[length] = '\0';
                puts(answer);
            };
        };
    
        }
    
        void cl_deregister(int sckt) {
        int rv, length, l;
        char* text = "!deregister";
        char answer[DIM];
    
        //Sending command dimension
        length = strlen(text);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    
        //Receiving answer
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
        puts(answer);
        }
    
        void cl_register(int sckt, char* name, char* port) {
        int rv, length, l, n, n_net, i;
        char msg[DIM+NAME_DIM+4];
        char answer[DIM];
    
        sprintf(msg, "!register %s %s", name, port);
    
        //Sending command
        length = strlen(msg);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) msg, length, 0);
        if(rv < 0) {};
    
        //Receiving answer
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
        puts(answer);
    
        if(strcmp(answer, "L'utente era gia' registrato al servizio: riconnessione completata.\n") == 0) { //Users already registered: reconnection
            //Receiving info
            rv = recv(sckt, (void*) &l, sizeof(l), 0);
            if(rv < 0) {};
    
            length = ntohs(l);
    
            rv = recv(sckt, (void*) answer, length, 0);
            if(rv < 0) {};
    
            answer[length] = '\0';
            puts(answer);
    
            if(strcmp(answer, "Messaggi offline presenti.") == 0) { //Offline messages found
                //Receiving the number of messages
                rv = recv(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                length = ntohs(l);
    
                rv = recv(sckt, (void*) &n_net, length, 0);
                if(rv < 0) {};
    
                n = ntohs(n_net);
    
                //Recevingi messages
                for(i=0; i<n; i++) {
                    rv = recv(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    length = ntohs(l);
    
                    rv = recv(sckt, (void*) msg, length, 0);
                    if(rv < 0) {};
    
                    msg[length] = '\0';
                    puts(msg);
                };
            };
        };  
        }
    
        void cl_send(int sckt, int udp_sd, char* name, char* info, char* source) {
        struct sockaddr_in dest;
        int rv, length, l,p;
        char msg[DIM+NAME_DIM+4];
        char address[ADDR_DIM];
        char port[PORT_DIM];
        char answer[DIM];
        char *pointer;
    
        sprintf(msg, "!send %s", name);
    
        //Sending command
        length = strlen(msg);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) msg, length, 0);
        if(rv < 0) {};
    
        //Receiving answer
        rv = recv(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        length = ntohs(l);
    
        rv = recv(sckt, (void*) answer, length, 0);
        if(rv < 0) {};
    
        answer[length] = '\0';
    
        puts(answer);
    
        if(strcmp(answer, "Devi essere connesso per poter utilizzare questa funzione.\n") != 0) { //You have to be registered
            if(strncmp(answer, "Client attualmente connesso", 27) == 0) { //User connected right now
                pointer = answer+29; //to get only the address and the port number
                sscanf(pointer, "%s %s", address, port);
                address[ADDR_DIM] = '\0';
                port[PORT_DIM] = '\0';
                p = ntohs(atoi(port));
    
                memset(&dest, 0, sizeof(dest));
                memset(&msg, 0, sizeof(msg));f
    
                //Destination UDP socket
                dest.sin_family = AF_INET;
                dest.sin_port = htons(p);
                inet_pton(AF_INET, address, &dest.sin_addr);
    
                //Sending direct message using UDP
                sprintf(msg, "%s > ", source);
                strcat(msg, info);
    
                length = strlen(msg);
                l = htons(length);
    
                //Sending message
                rv = sendto(udp_sd, (void*) &l, sizeof(l), 0, (struct sockaddr*) &dest, sizeof(dest));
                if(rv < 0) {};
    
                rv = sendto(udp_sd, (void*) msg, length, 0, (struct sockaddr*) &dest, sizeof(dest));
                if(rv < 0) {};
    
            } else { //Offline transmission: transmits message to server using TCP
                length = strlen(info);
                l = htons(length);
    
                rv = send(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                rv = send(sckt, (void*) info, length, 0);
                if(rv < 0) {};
    
                //Getting info from the server
                rv = recv(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                length = ntohs(l);
    
                rv = recv(sckt, (void*) answer, length, 0);
                if(rv < 0) {};
    
                answer[length] = '\0';
                puts(answer);
            };
        };
        }
    
        int main(int argc, char* argv[]) {
        struct sockaddr_in srv_addr;
        struct sockaddr_in my_addr;
        int sd, udp;
        int err;
        int pid;
        int length, l;
        char buffer[DIM];
        char cmd[CMD_DIM];
        char dest[NAME_DIM];
        char my_name[NAME_DIM];
        char in[DIM];
        char to_send[DIM+NAME_DIM+4];
        char part[DIM] = "";
    
        if(argc != 5) {
            //Check argument
            exit(EXIT_FAILURE);
        };
    
        //TCP socket
        sd = socket(AF_INET, SOCK_STREAM, 0);
        //UDP socket
        udp = socket(AF_INET, SOCK_DGRAM, 0);
    
        //Pulizia
        memset(&srv_addr, 0, sizeof(srv_addr));
        memset(&my_addr, 0, sizeof(my_addr));
    
        //TCP server parameters
        srv_addr.sin_family = AF_INET;
        srv_addr.sin_port = htons(atoi(argv[4]));
        inet_pton(AF_INET, argv[3], &srv_addr.sin_addr);
    
        //my UDP parameters
        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons(atoi(argv[2]));
        inet_pton(AF_INET, argv[1], &my_addr.sin_addr);
    
        //Bind for UDP socket
        err = bind(udp, (struct sockaddr*) &my_addr, sizeof(my_addr));
        if(err < 0) {};
    
        //Connecting to the server
        err = connect(sd, (struct sockaddr*) &srv_addr, sizeof(srv_addr));
        if(err < 0) {};
    
        //Auto-sending help command to display available operations
        strcpy(cmd, "!help");
    
        length = strlen(cmd);
        l = htons(length);
    
        err = send(sd, (void*) &l, sizeof(l), 0);
        if(err < 0) {};
    
        err = send(sd, (void*) cmd, length, 0);
        if(err < 0) {};
    
        //Receiving info from the server -> available operations
        err = recv(sd, (void*) &l, sizeof(l), 0);
        if(err < 0) {};
    
        length = ntohs(l);
    
        err = recv(sd, (void*) buffer, length, 0);
        if(err < 0) {};
    
        buffer[strlen(buffer)] = '\0';
        puts(buffer);
    
        pid = fork();
        if(pid == 0) {
            //Child
            close(sd);
    
            while(1) {
                memset(to_send, 0, sizeof(to_send));
    
                err = recvfrom(udp, (void*) &l, sizeof(l), 0, 0, 0);
                if(err < 0) {
                    puts("error recvfrom");
                    exit(EXIT_FAILURE);
                };
    
                length = ntohs(l);
    
                err = recvfrom(udp, (void*) to_send, length, MSG_WAITALL, 0, 0);
                if(err < 0) {
                    puts("error recvfrom");
                    exit(EXIT_FAILURE);
                };
    
                to_send[length] = '\0';
                puts(to_send);
            };
        } else {
            //Parent
    
            while(1) {
                //Asking the user to prompt the command
                memset(cmd, 0, sizeof(cmd));
                memset(in, 0, sizeof(in)); 
                memset(dest, 0, sizeof(dest));
                puts("\nInserisci un comando: "); //Insert a command
                fgets(in, DIM, stdin);
    
                in[strlen(in)-1] = '\0';
                sscanf(in, "%s", cmd);
                cmd[CMD_DIM-1] = '\0';
    
                if(strcmp(cmd, "!help") == 0) {
                    cl_help(sd);
                    continue;
                };
    
                if(strcmp(cmd, "!deregister") == 0) {
                    cl_deregister(sd);
                };
    
                if(strcmp(cmd, "!register") == 0) {
                    sscanf(in, "%s %s", cmd, dest);
                    cmd[CMD_DIM-1] = '\0';
                    dest[NAME_DIM-1] = '\0';
                    strcpy(my_name, dest);
                    if(strlen(dest) == 0) { //to avoid an empty username
                        puts("Errore: non hai inserito alcun username; riprova.\n"); //Please insert an username
                    } else {
                        cl_register(sd, dest, argv[2]);
                    };
                    continue;
                };
    
                if(strcmp(cmd, "!who") == 0) {
                    cl_who(sd);
                    continue;
                };
    
                if(strcmp(cmd, "!send") == 0) {
                    sscanf(in, "%s %s", cmd, dest);
                    cmd[CMD_DIM-1] = '\0';
                    dest[NAME_DIM-1] = '\0';
    
                    while(1) {
                        memset(part, 0, sizeof(part));
    
                        fgets(part, DIM-(strlen(to_send)-NAME_DIM-4), stdin);
                        l = strlen(part);
    
                        if((part[l-2] == '.') && (part[l-1] == '\n') && (strlen(part) == 2)) {
                            part[l-2] = '\0';
                            break;
                        } else {
                            strcat(to_send, part);
                        };
    
                        if(strlen(to_send) >= DIM+NAME_DIM+3) {
                            to_send[DIM+NAME_DIM+3] = '\0';
                            break;
                        };
                    };
                    strcat(to_send, "\0"); 
                    cl_send(sd, udp, dest, to_send, my_name);
                    memset(to_send, 0, sizeof(to_send)); //to empty the buffer used to store the message sent
                    continue;
                };
    
                if(strcmp(cmd, "!quit") == 0) {
                    cl_quit(sd);
                    close(sd);
                    break;
                } else{
                    puts("Comando non valido.\n"); //Not a valid command
                }; 
            };
        };
    
        return 0;
        }
    

    服务器
    服务器响应来自客户端的请求,并被构造为并发服务器。

    #include <sys/mman.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    
    #define MAX_CONN 100
    #define DIM 1024
    #define ADDR_DIM 16
    #define CMD_DIM 12
    #define NAME_DIM 20
    #define MSG_DIM DIM+NAME_DIM+4
    #define PORT_DIM 5
    #define MAX_UTN 1024
    
    struct users {
        char username[NAME_DIM];
        char status; //c = connected, o = offline
        struct sockaddr_in address;
        char pendent[DIM][DIM]; 
        char sender[DIM][NAME_DIM];
        int msg; //last message to be sent
    };
    
    void srv_help(int sckt) {
        int rv, length, l;
    
        char* text = "Sono disponibili i seguenti comandi: \n\
     !help --> mostra l'elenco dei comandi disponibili \n\
     !register username --> registra il client presso il server\n\
     !deregister --> de-registra il client presso il server\n\
     !who --> mostra l'elenco degli utenti disponibili\n\
     !send username --> invia un messaggio ad un altro utente\n\
                    (messaggio subito dopo comando\n\
     !quit --> disconnette il client dal server ed esce\n\
     ('username': max 20 caratteri)\n\
     (per terminare messaggio inserisci un . da solo)\n";//info about the available commands
    
        length = strlen(text);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};  
    };
    
    void srv_who(int sckt, struct users* reg, int last) {
        int i, rv, length, l;
        char text[DIM];
    
        strcpy(text, "Nessun utente in linea\n");//No user online
    
        if(last == 0) { //if no user is online
            length = strlen(text);
            l = htons(length);
    
            rv = send(sckt, (void*) &l, sizeof(l), 0);
            if(rv < 0) {};
    
            rv = send(sckt, (void*) text, length, 0);
            if(rv < 0) {};
        } else { 
            strcpy(text, "Utenti in linea:\n"); //Users online:
    
            length = strlen(text);
            l = htons(length);
    
            rv = send(sckt, (void*) &l, sizeof(l), 0);
            if(rv < 0) {};
    
            rv = send(sckt, (void*) text, length, 0);
            if(rv < 0) {};
    
            //Here I send the number of users online, to synchronize server and client
            length = sizeof(last);
            l = htons(length);
    
            rv = send(sckt, (void*) &l, sizeof(l), 0);
            if(rv < 0) {};
    
            l = htons(last);
            rv = send(sckt, (void*) &l, length, 0);
            if(rv < 0) {};
    
            //Transmitting users
            for(i=0; i<last; i++) {
                if(reg[i].status == 'c') {
                    length = strlen(reg[i].username);
                    l = htons(length);
    
                    rv = send(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    rv = send(sckt, (void*) reg[i].username, length, 0);
                    if(rv < 0) {};
                };
            };
        };
    };
    
    void srv_deregister(int sckt, struct users* reg, char* name, int* last) {
        int i, rv, length, l;
        char text[DIM];
        strcpy(text, "Deregistrazione completata.\n"); //De-registration completed
    
        for(i=0; i<*last; i++) {
            if(strcmp(reg[i].username, name) == 0) { //user found
                reg[i] = reg[*last];
                (*last)--;
    
                length = strlen(text);
                l = htons(length);
    
                rv = send(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                rv = send(sckt, (void*) text, length, 0);
                if(rv < 0) {};
    
                return;
            };
        };
    }
    
    int srv_register(int sckt, struct users* reg, char* name, struct sockaddr_in client, int p, int* last) { //char*
        int i, rv, length, l, j, pos;
        //char pos[MSG_DIM]; // = "";
        char text[DIM];
        char buffer[MSG_DIM];
    
        memset(text, 0, DIM);
        strcpy(text, "Registrazione effettuata con successo.\n"); //Registration completed
    
    
        for(i=0; i<*last; i++) {
    
            if(strcmp(reg[i].username, name) == 0) { //User already registered: re-connection
                strcpy(text, "L'utente era gia' registrato al servizio: riconnessione completata.\n"); //Re-connection completed
                reg[i].status = 'c';
                reg[i].address.sin_family = client.sin_family;
                reg[i].address.sin_port = p;
                reg[i].address.sin_addr.s_addr = client.sin_addr.s_addr;
    
                length = strlen(text);
                l = htons(length);
    
                rv = send(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                rv = send(sckt, (void*) text, length, 0);
                if(rv < 0) {};
    
                if(reg[i].msg > 0) { //messaggi offline
                    strcpy(text, "Messaggi offline presenti.\n"); //Offline messages found
    
                    length = strlen(text);
                    l = htons(length);
    
                    rv = send(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    rv = send(sckt, (void*) text, length, 0);
                    if(rv < 0) {};
    
                    //Sending number of messages to be sent
                    length = sizeof(*last);
                    l = htons(length);
    
                    rv = send(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    l = htons(*last);
    
                    rv = send(sckt, (void*) &l, length, 0);
                    if(rv < 0) {};
    
                    for(j=0; j<reg[i].msg; j++) {
    
                        sprintf(buffer, "%s > ", reg[i].sender[j]);
                        strcat(buffer, reg[i].pendent[j]);
    
                        length = strlen(buffer);
                        l = htons(length);
    
                        rv = send(sckt, (void*) &l, sizeof(l), 0);
                        if(rv < 0) {};
    
                        rv = send(sckt, (void*) buffer, length, 0);
                        if(rv < 0) {};
                    };
    
                    //Set number of messages to send to 0
                    reg[i].msg = 0;
                } else {
                    strcpy(text, "Nessun messaggio offline presente.\n"); //No offline messages
    
                    rv = send(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    rv = send(sckt, (void*) text, length, 0);
                    if(rv < 0) {};
                };
                return 1;
            };
        };
    
        //If the user is not already registered
    
        if(*last == MAX_UTN) { //max number of users reached
            strcpy(text, "Impossibile registrarsi al servizio: numero limite di utenti raggiunto.\n"); //Max number of users reached
            pos = -1;
        } else {
            strcpy(reg[*last].username, name);
            reg[*last].address.sin_family = client.sin_family;
            reg[*last].address.sin_port = p;
            reg[*last].address.sin_addr.s_addr = client.sin_addr.s_addr;
            reg[*last].status = 'c';
            reg[*last].msg = 0;
            (*last)++;
            pos = 1;
        };
    
        length = strlen(text);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {}
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {}
    
        return pos;
    }
    
    void srv_quit(int sckt, struct users* reg, char* user, int num) {
        int i, length, l, rv;
        char text[DIM];
        memset(text, 0, DIM);
        strcpy(text, "Utente disconnesso.\n"); //_User disconnected
    
        for(i=0; i<num; i++) {
            if(strcmp(reg[i].username, user) == 0) { //user actually registered to the service
                if(reg[i].status == 'c') {
                    reg[i].status = 'o';
                };
                memset(&reg[i].address, 0, sizeof(reg[i].address));
    
                length = strlen(text);
                l = htons(length);
    
                rv = send(sckt, (void*) &l, sizeof(l), 0);
                if(rv < 0) {};
    
                rv = send(sckt, (void*) text, length, 0);
                if(rv < 0) {};
    
                printf("%s disconnesso.\n", user); //<User> disconnected
    
                return;
                };
            }; 
        //if here, user is not registered to the service
        strcpy(text, "L'utente non era registrato al servizio.\n"); //User not registered
    
        length = strlen(text);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    }
    
    void srv_send(int sckt, struct users* reg, int num, char* dest, char* source) {
        int i, rv, length, l;
        char text[DIM];
        char addr[ADDR_DIM];
        memset(text, 0, DIM);
    
        for(i=0; i<num; i++) {
            if(strcmp(reg[i].username, dest) == 0) { //User registered
    
                if(reg[i].status == 'c') { //user connected: provides destination UDP address to the sender (it will directly send the message)
                    inet_ntop(AF_INET, &reg[i].address.sin_addr.s_addr, addr, sizeof(addr));
                    sprintf(text, "Client attualmente connesso: %s %d \n", addr , ntohs(reg[i].address.sin_port));
                    break;
                } else { //user disconnected: save offline message
                    //Getting the message
                    rv = recv(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    length = ntohs(l);
    
                    rv = recv(sckt, (void*) reg[i].pendent, length, 0);
                    if(rv < 0) {};
    
                    reg[i].pendent[reg[i].msg][length] = '\0';
                    strcpy(reg[i].sender[reg[i].msg], source);
                    reg[i].msg++;
    
                    //Sending info to te sender
                    strcpy(text, "Messaggio salvato per l'invio offline.\n"); //Message saved offline
    
                    length = strlen(text);
                    l = htons(length);
    
                    rv = send(sckt, (void*) &l, sizeof(l), 0);
                    if(rv < 0) {};
    
                    rv = send(sckt, (void*) text, length, 0);
                    if(rv < 0) {};
    
                    return;
                };
            };
        };
        //Here if got into the if statement
        length = strlen(text);
        l = htons(length);
    
        rv = send(sckt, (void*) &l, sizeof(l), 0);
        if(rv < 0) {};
    
        rv = send(sckt, (void*) text, length, 0);
        if(rv < 0) {};
    }
    
    int main(int argc, char* argv[]) {
        //shared (mapped) memory
        struct users* registered = mmap(0, MAX_CONN*sizeof(struct users), PROT_READ | PROT_WRITE,  MAP_ANONYMOUS | MAP_SHARED, 0, 0);
        //last index with user struct to be used
        int* last = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0); 
    
        int sd; //socket descriptor
        int conn_sd; //socket descriptor after connect()
        struct sockaddr_in my_addr;
        struct sockaddr_in cl_addr;
        int err; //for errors
        int udp_port;
        char check[NAME_DIM]; //will containg the username of the client connected
        socklen_t len;
        int pid;
        int dim_rcvd_net, dim_rcvd, dim_sent_net, dim_sent;
        char buffer[DIM];
        char cmd[CMD_DIM];
        char name[NAME_DIM];
        char port[PORT_DIM];
    
        *last = 0;
        memset(registered, 0, MAX_CONN*sizeof(struct users));
        memset(check,0,  NAME_DIM);
        puts("Avvio del servizio...\n"); //Service starting..
    
    
        if(argc != 2) {
            printf("Errore: troppi argomenti. \n Utilizzare solamente un argomento."); //Please use only one argument
            exit(EXIT_FAILURE);
        };
    
        //Maybe check the argument itself?
    
        sd = socket(AF_INET, SOCK_STREAM, 0);
    
        memset(&my_addr, 0, sizeof(my_addr));
    
        //Socket parameters
        my_addr.sin_family = AF_INET;
        my_addr.sin_port = htons(atoi(argv[1]));
        my_addr.sin_addr.s_addr = INADDR_ANY;
    
        err = bind(sd, (struct sockaddr*) &my_addr, sizeof(my_addr));
        if(err < 0) {};
    
        err = listen(sd, MAX_CONN);
        if(err < 0) {};
        puts("Servizio attivo.\n"); //Service activated
    
        //Concurrent server
        while(1) {
    
            len = sizeof(my_addr);
            conn_sd = accept(sd, (struct sockaddr*) &cl_addr, &len);
            //error check to be done
    
            pid = fork();
            if(pid == 0) {
                //Child         
                close(sd);
    
                while(1) {
                    //Command dimension
                    err = recv(conn_sd, (void*) &dim_rcvd_net, sizeof(dim_rcvd), 0);
                    if(err < 0) {};
    
                    dim_rcvd = ntohs(dim_rcvd_net);
    
                    //Command
                    err = recv(conn_sd, (void*) buffer, dim_rcvd, 0);
                    if(err < 0) {};
    
                    buffer[dim_rcvd] = '\0';
    
                    sscanf(buffer, "%s", cmd);
    
                    if(strcmp(cmd, "!help") == 0) {
                        srv_help(conn_sd);
                    };
    
                    if(strcmp(cmd, "!register") == 0) {
                        if(strlen(check) > 0) { //Already connected with another username
                            puts("Sei già connesso con altro nome.\n"); //Already connected
                        } else {
                            sscanf(buffer, "%s %s %s", cmd, name, port);
                            udp_port = atoi(port);
    
                            if(srv_register(conn_sd, registered, name, cl_addr, udp_port, last) == 1) {
                                strcpy(check, name);
                            };
                        };
                    };
    
                    if(strcmp(cmd, "!deregister") == 0) {
                        if(strlen(check) <= 0) { //if not registered
                            strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione.\n"); //You have to be registered
    
                            dim_sent = strlen(buffer);
                            dim_sent_net = htons(dim_sent);
    
                            err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
                            if(err < 0) {};
    
                            err = send(conn_sd, (void*) buffer, dim_sent, 0);
                            if(err < 0) {};
                        } else {
                            srv_deregister(conn_sd, registered, check, last);
                            strcpy(check, "");
                        };
                    };
    
                    if(strcmp(cmd, "!send") == 0) {
                        if(strlen(check) <= 0) { //if not registered
                            strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione.\n"); //You have to be registered
    
                            dim_sent = strlen(buffer);
                            dim_sent_net = htons(dim_sent);
    
                            err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
                            if(err < 0) {};
    
                            err = send(conn_sd, (void*) buffer, dim_sent, 0);
                            if(err < 0) {};
                        } else {
                            sscanf(buffer, "%s %s", cmd, name);
                            srv_send(conn_sd, registered, *last, name, check);
                        };
                    };
    
                    if(strcmp(cmd, "!who") == 0) {
    
                        if(strlen(check) <= 0) { //if not registered
                            strcpy(buffer, "Devi essere connesso per poter utilizzare questa funzione"); //You have to be registered
    
                            dim_sent = strlen(buffer);
                            dim_sent_net = htons(dim_sent);
    
                            err = send(conn_sd, (void*) &dim_sent_net, sizeof(dim_sent_net), 0);
                            if(err < 0) {};
    
                            err = send(conn_sd, (void*) buffer, dim_sent, 0);
                            if(err < 0) {};
                        } else {
                            srv_who(conn_sd, registered, *last);
                        };
                    };
    
                    if(strcmp(cmd, "!quit") == 0) {
                        srv_quit(conn_sd, registered, check, *last);
                        close(conn_sd);
                        exit(EXIT_SUCCESS);
                    };
                };
    
            } else {
    
                //Parent
                close(conn_sd);
            };
    
        };
    
        close(sd);
        return 0;
    }
    

    编辑2 有件事我不明白。我刚刚重新执行了粘贴在这里的完全相同的程序,它似乎正确地发送了消息(目前仅在线)。
    可能是同步问题吗?
    编辑3 以下是作业内容: http://www2.ing.unipi.it/c.vallati/files/reti/Progetto2017.pdf
    正如我在评论中所说,这是意大利语。。

    2 回复  |  直到 6 年前
        1
  •  0
  •   slim71    6 年前

    好了,我的问题解决了!

    首先,我移动了UDP套接字的创建。之前,在我粘贴到这里的代码中 fork() 。想想看,我认为这是错误的,因为父母和孩子会共享这个插座,而孩子会一直使用它,而我似乎是对的。因此,我为父级(发送给其他客户端)和子级(接收传输)创建了一个单独的UDP。

    然后我明白了为什么代码有时有效,有时无效:在我以前的执行中,当程序冻结时,我用 Ctrl+Z ;查看的输出 htop ,我注意到它的一些执行(准确地说,是孩子们)仍在运行并占用插槽。所以我继续终止了他们。

    在添加了更多的错误捕获代码并纠正了通信中的错误之后,一切都很好,而且仍然正常。
    是时候让我的父母 kill() 关闭时的子对象。

    所以是的,关于“双重”传输(首先是文本的维度,然后是文本本身)的方法,所有的工作都如期进行。

        2
  •  -1
  •   DJAMEL DAHMANE    6 年前

    每个端口都可以用于udp或tcp使用 IANA正式指定了一些特定用途的端口 例如http为80,ftp为21。。。(维基百科页面中的表格) 您的问题是接收程序读取的内容比客户端发送的内容多 因为通过套接字发送的字符串不包含任何终止字符“\0”(strlen不计算终止字符“\0”) 所以服务器首先读取消息,并且不会停止读取,所以它会打印奇怪的字符 解决方案是通过在发送函数中向strlen(stirng)添加一个终止字符来发送终止字符,如下所示

    bytes_sent = send(client_socket, thestring, strlen(thestirng)+1, 0);