0

我正在使用 UDP 编写私人聊天,但在实现注册服务时遇到了一些问题。当客户端写入他要使用的ID和密码时,服务器会检查ID是否已经存在(ID和密码保存在一个文件中),如果不存在,客户端可以开始与其他用户聊天(我仍然没有实现这部分),如果 ID 已经在使用中,我想告诉用户选择另一个 ID。在这种情况下,我使用 sendto 向客户端发送消息“ID 已在使用中”,但 recvfrom 有时会接收其他消息。正是当用户第一次选择了错误的 ID 时,他收到了正确的消息,然后,如果他再次选择一个已经在使用的 ID,从他从服务器收到的消息中,他读取了他尝试选择的 ID,而不是错误信息。最奇怪的是,在第三次错误尝试时,错误消息是正确的。消息和相关函数在名为 utils.h 的文件中定义

typedef struct Message{
    int type; //Message's type: 0->registration; 1->login; 2->message; 3->ack
    char* dest;
    char* mitt; //source
    char msg[1024];
}Message;

//createMsg is used to fill message struct
int createMsg(int type, char* dest, char* mitt, char * msg, struct Message* message){ //char msg[1024]
    //printf("Sono in createMsg\n");
    memset(message,0,sizeof(*message));
    message->type = type;
    message->dest = dest;
    message->mitt = mitt;
    //printf("msg to write: %s\n",msg);
    strcpy(message->msg,msg);
    //printf("msg written: %s\n",message->msg);
}

//print messages
void printMsg(struct Message* message){
    if(strlen(message->msg)!=0) printf("type: %d, dest: %s, mitt:%s, msg: %s\n",message->type,message->dest,message->mitt,message->msg);
    printf("dim msg tot: %lu\n",sizeof(*message));
    printf("type dim: %lu, dest dim: %lu, mitt dim:%lu, msg dim: %lu, dim tot msg: %lu\n",sizeof(message->type),sizeof(message->dest),sizeof(message->mitt),strlen(message->msg),sizeof(message->msg));
}

//Set message's field to zero
void setToZeroMsg(struct Message* message){
    message->type = 0;
    message->dest = NULL;
    message->mitt = NULL;
    int i=0;
    for(i=0;i<strlen(message->msg);i++){
        message->msg[i]=0;
    }
    //memset(message->msg,0,strlen(message->msg));
}

这是服务器:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>  // htons()
#include <netinet/in.h> // struct sockaddr_in
#include <sys/socket.h>
//#include "utente.h"
#include "utils.h"

#define MAX_CONNECTIONS 5
#define MAX_MESSAGE 1024

int main(){
    int sockfd, ret;
    char buffer[MAX_MESSAGE];
    size_t buf_len = sizeof(buffer);
    struct sockaddr_in server_addr, client_addr;
    int serv_addr_len = sizeof(server_addr);
    int client_addr_len = sizeof(client_addr);

    //socket file descriptor
    sockfd = socket(AF_INET, SOCK_DGRAM,0);
    if(sockfd < 0){
        perror("Errore nel creare la socket!");
        exit(EXIT_FAILURE);
    }
    //Setting structure's content to zero
    memset(&server_addr,0,serv_addr_len);
    memset(&client_addr,0,client_addr_len);
    //Server addr
    server_addr.sin_family = AF_INET; //IPv4
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(5500);
    //Bind
    ret = bind(sockfd, (const struct sockaddr *)&server_addr, serv_addr_len);
    if(ret < 0){
        perror("Errore nella bind!");
        exit(EXIT_FAILURE);
    }
    struct Message* newmsg = (struct Message*)malloc(sizeof(struct Message));

    //Start comunication with clients
    //int num_clients = 0;
    while(1){
        setToZeroMsg(newmsg); //Cancel previous messages
        printf("waiting for a message from a client...\n");
        //Receiving a message
        ret = recvfrom(sockfd, newmsg, sizeof(*newmsg), 0, (struct sockaddr*)&client_addr, &client_addr_len);
        if(ret == -1){
            perror("Errore nella recvfrom!");
        }
        printMsg(newmsg);
        int type = newmsg->type;
        if(type == 0){ //Type==0 -> register request
            printf("register request\n");
            int newID = 0; //if is set to -1 the ID already exist
            size_t msg_len=sizeof(newmsg->msg);
            FILE* file = fopen("utenti.txt","r+");
            if(file==NULL){
                perror("Errore nell'apertura del file");
            }
            char* newuser = strcpy(newser,newmsg->msg);
            strtok(newuser,";");
            int size_newuser = sizeof(newuser);
            while(1){
                char* res = fgets(buffer,32,file);
                if(res==NULL) break;
                //printf("%s",buffer);
                char* user = strtok(buffer,";");
                //printf("%s\n",user);
                int size_user = sizeof(user);
                int size = (size_newuser > size_user)? size_newuser : size_user;
                if(strncmp(newuser,user,size) == 0){
                    //printf("This name is already in use!\n");
                    /*memset(newmsg,0,sizeof(Message));
                    newmsg->type = 3;
                    newmsg->dest = NULL;
                    strcpy(newmsg->msg, "This ID is already taken!\n");
                    printf("mess: %s",newmsg->msg);*/
                    //Error message to client
                    creaMsg(3, NULL, NULL, "This ID is already taken!\n", newmsg); //buffer
                    printMsg(newmsg);
                    printf("msg: %s\n",newmsg->msg);
                    //ret = sendto(sockfd, (struct Message*)newmsg, sizeof(*newmsg), 0, (struct sockaddr*)&client_addr, (socklen_t) client_addr_len);
                    ret = sendto(sockfd,newmsg->msg,sizeof(newmsg->msg),0,(struct sockaddr*)&client_addr, (socklen_t) client_addr_len );
                    if(ret == -1){
                        perror("Errore nella sendto!");
                        exit(EXIT_FAILURE);
                    }
                    newID = -1;
                    break;
                }
            }
            if(newID != -1){
                ret = fprintf(file,newmsg->msg,msg_len);
                if(ret == -1){
                    perror("Errore nella scrittura su file");
                }
            }
            if(fclose(file) == -1) perror("Errore nella chiusura del file");
        }
        else if(type==1){

        }
        else if(type==2){

        }
        //This part is not implemented yet
        /*ret = sendto(sockfd, buffer, buf_len,0,(const struct sockaddr*)&client_addr, (socklen_t) client_addr_len);
        if(ret == -1){
            perror("Errore nella sendto!");
        }*/
    }

    close(sockfd);
    return 0;
}

这是客户端文件:


#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>  // htons()
#include <netinet/in.h> // struct sockaddr_in
#include <sys/socket.h>
//#include "utente.h"
#include "utils.h"

#define MAX_MESSAGE 1024
#define quit_command "QUIT"

int main(){
    int sockfd, ret;
    struct sockaddr_in server_addr;
    int serv_addr_len = sizeof(server_addr);

    char buffer[MAX_MESSAGE];
    size_t buf_len = sizeof(buffer);
    size_t msg_len;
    int quit_command_len = strlen(quit_command);

    //Message struct
    struct Message message = {};
    setToZeroMsg(&message);

    //socket file descriptor
    sockfd = socket(AF_INET, SOCK_DGRAM,0);
    if(sockfd < 0){
        perror("Errore nel creare la socket!");
        exit(EXIT_FAILURE);
    }
    //Structures to zero
    memset(&server_addr,0,serv_addr_len);
    //Initialize server_addr
    server_addr.sin_family = AF_INET; //IPv4
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(5500);

    printf("Welcome in Private Chat!\n");
    while(1){
        char buf_credentials[32];
        memset(buf_credentials,0,sizeof(buf_credentials));
        memset(buffer,0,sizeof(buffer));
        //setToZeroMsg(&message);
        printf("If you want to register write 'r', to login type 'l':\n");
        if (fgets(buffer, MAX_MESSAGE, stdin) != (char*)buffer) {
                fprintf(stderr, "Error while reading from stdin, exiting...\n");
                exit(EXIT_FAILURE);
        }
        if(!memcmp(buffer, "l", 1)){
            printf("not implemented yet");
            break;
        }
        else if(!memcmp(buffer,"r",1)){
            printf("To register choose an ID and a password.\n");
            printf("ID:\n");
            if (fgets(buffer, 15, stdin) != (char*)buffer) {
                fprintf(stderr, "Error while reading from stdin, exiting...\n");
                exit(EXIT_FAILURE);
            }
            //printf("%s\n",buffer);
            strncpy(buf_credentials,buffer,strlen(buffer)-1);
            strcat(buf_credentials,";");
            printf("Inserire password:\n");
            if (fgets(buffer, 15, stdin) != (char*)buffer) {
                fprintf(stderr, "Error while reading from stdin, exiting...\n");
                exit(EXIT_FAILURE);
            }
            strcat(buf_credentials,buffer);
            printf("utente+pass: %s",buf_credentials);
            //Message struct
            /*
            struct Message message = {
            };*/
            setToZeroMsg(&message);
            strcpy(message.msg, buf_credentials);
            //send ID e password to server
            ret = sendto(sockfd, (struct Message*)&message, sizeof(message), 0, (struct sockaddr*)&server_addr, (socklen_t) serv_addr_len);
            if(ret == -1){
                perror("Errore nella sendto!");
                continue;
            }
            setToZeroMsg(&message);
            printf("msg: %s\n",message.msg);
            //ret = recvfrom(sockfd, (struct Message*)&message, sizeof(message), 0, (struct sockaddr*)&server_addr, (socklen_t*)&serv_addr_len);
            ret = recvfrom(sockfd, message.msg, sizeof(message.msg), 0, (struct sockaddr*)&server_addr, (socklen_t*)&serv_addr_len);
            printMsg(&message);
            printf("msg: %s\n",message.msg);
            if(ret == -1){
                perror("Errore nella recvfrom!");
            }
            continue;
        }
        else{ //User didn't type 'r' or 'l'
            printf("Wrong, you have to type 'r' o 'l'\n");
        }
        memset(buffer,0,MAX_MESSAGE);
    }
    //Chatting with server
    while(1){
        memset(buffer,0,MAX_MESSAGE);
        printf("Type the message for the server, QUIT to leave the chat:\n");
        if (fgets(buffer, MAX_MESSAGE, stdin) != (char*)buffer) {
            fprintf(stderr, "Error while reading from stdin, exiting...\n");
            exit(EXIT_FAILURE);
        }
        printf("You wrote: %s\n", buffer);
        msg_len=strlen(buffer);
        //Send Message
        ret = sendto(sockfd, buffer, MAX_MESSAGE, 0, (struct sockaddr*)&server_addr, (socklen_t) serv_addr_len);
        if(ret == -1){
            perror("Errore nella sendto!");
            continue;
        }
        //Server wrote back
        memset(buffer,0,MAX_MESSAGE);
        ret = recvfrom(sockfd, buffer, buf_len, 0, (struct sockaddr*)&server_addr, &serv_addr_len);
        if(ret == -1){
            perror("Errore nella recvfrom!");
        }
        printf("Message received from server: %s\n",buffer);
        //Controlla se il messaggio ricevuto è QUIT
        if (msg_len == quit_command_len+1 && !memcmp(buffer, quit_command, quit_command_len)) break;

    }
    printf("Closing connection!\n");
    close(sockfd);
    return 0;
}

ID和密码存放在文件“utenti.txt”中,用分号隔开,依次为:ID1;password1 ID2;password2 ... 希望我已经把我的问题搞清楚了,谢谢你的帮助!

4

0 回答 0