C - 通过套接字

时间:2018-03-29 10:14:44

标签: c tcp udp ports

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

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

我已经将端口4242用于服务器,然后尝试将4243和4244用于两个示例客户端。

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

我得到的那些数字看Wikipedia,但因为我不确定如何解释那个表(所以,如果我正确地解释它),因为我知道维基百科可能不那么可靠,我想我可以问这里。

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

提前致谢!

编辑:

这是我的代码!我之前无法上传..我也会试着给它做一个简短的解释 正如我在评论中提到的,我以为我有它,但是一个客户端没有收到来自另一个的消息。所以所有的工作,除了!发送功能,我猜...

客户端
客户端是用“!register username”连接到服务器的用户;这个命令:
- 如果客户是第一次连接到该服务,请将客户注册到该服务,当然还要将其设置为“在线”
- 如果客户已注册该服务,则重新连接客户端;在这种情况下,如果有一些离线消息,则服务器将其传递给te客户端

连接后,客户端可以使用以下命令:
1)!help:显示可用的命令
2)!who:显示在线用户
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 个答案:

答案 0 :(得分:0)

好的,我已经解决了我的问题!

首先,我移动了UDP套接字创建。以前,在我粘贴的代码中,它位于fork()之前。考虑到这一点,我认为这是错误的,因为父母和孩子将共享套接字而孩子会不断地使用它,而且看起来我是对的。所以我为父(发送给其他客户端)和子(接收传输)创建一个单独的UDP。

然后我想到为什么有时代码工作,有时不工作:在我以前的执行中,当程序冻结时我用Ctrl+Z关闭它;看着htop的输出,我注意到它的一些执行(孩子们,确切地说)仍在运行并占用套接字。所以我继续前进并终止它们。

在添加更多错误捕获代码并纠正通信中的错误之后,每次都很顺利,但仍然如此 而且我确保在关闭时让父母kill()成为孩子。

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

答案 1 :(得分:-1)

每个端口都可以用于udp或tcp使用 有些端口由IANA主管分配给特定用途 喜欢80 for http和21 for ftp ...(维基百科页面中的表格) 你的问题是你的reciving程序阅读的内容超过了客户发送的内容 因为通过套接字发送的字符串不包含任何终止字符'\ 0'(strlen不计算终止字符'\ 0') 所以服务器首先读取消息并且不停止读取所以它打印那些奇怪的字符 解决方案是通过在发送函数中添加一个strlen(stirng)来发送终止字符,如下所示

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