2016-05-17 41 views
0

我在C語言模擬聊天服務我發送一個mensage到服務器端像「U:用戶名,密碼;登錄一個用戶,但當我問誰在線它打印的n次(讓n是在線用戶數量)的用戶誰問!什麼是不是預期的行爲的名稱,有人能告訴我爲什麼嗎?爲什麼我的聊天服務模擬寫錯了內容?

server.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <string.h> 
#include <termios.h> 
#include <linux/stat.h> 

#define FIFO_FILE "MYFIFO" 

typedef struct online { 
char* user; 
struct online* next; 
} online; 

typedef struct users{ 
char* name; 
char* password; 
} users; 

online* begin=NULL; 
online* end=NULL; 
FILE *fp; 
void start_server(); 

void add_online(char* user); 

void realocate_end(); 

void remove_online(char* user); 

char* user_access(char* s); 



void who_online(); 

void free_all(); 

int find_username(char* user); 

void add_user_regist(char* user,char* password); 

users* find_user_regist(char* user, char* password); 

int main(int argc, char *argv[]) 
{ 
if(argc>1){ 
    char password[50]; 
    char password2[50]; 

    printf("Password? "); 
    scanf("%s",password); 
    printf("Repita a password? "); 
    scanf("%s",password2); 

    if(strcmp(password,password2)!=0){ 
    printf("Passwords diferentes!\n"); 
    exit(1); 
    } 

    if(find_username(argv[1])){ 
    printf("Utilizador ja existe\n"); 
    exit(1); 
    } 
    add_user_regist(argv[1],password); 
    printf("Utilizador %s adicionado.\n",argv[1]); 
    exit(0); 
} 


char readbuf[250]; 

/* Create the FIFO if it does not exist */ 
umask(0); 
mknod(FIFO_FILE, S_IFIFO|0666, 0); 
printf("Servidor iniciado.\nEm modo de espera de mensagens\n"); 

while(1) 
{ 
    fp = fopen(FIFO_FILE, "r"); 
    fgets(readbuf, 250, fp); 
    fclose(fp); 
    if(readbuf[0]=='U') 
    user_access(readbuf); 
    if(readbuf[0]=='W') 
    who_online(); 
    printf("Received string: %s\n",readbuf); 


} 
return(0); 
} 



void realocate_end(){ 
online* tmp=begin; 
while(tmp!=NULL){ 
    if(tmp->next==NULL) 
    end=tmp; 
    tmp=tmp->next; 
} 
} 

void remove_online(char* user){ 
online* tmp=begin; 
char path[100]; 
sprintf(path,"/tmp/chatroom_%s",user); 
unlink(path); 
while(tmp!=NULL){ 
    if(tmp->user==user && tmp->user == end->user){ 
    free(end); 
    end=NULL; 
    realocate_end(); 
    } 
    else if(tmp->user==user && tmp->user == begin->user){ 
    begin=begin->next; 
    free(tmp); 
    break; 

    } 
    else if(tmp->next->user ==user){ 
    online* tmp2 = tmp->next->next; 
    free(tmp->next); 
    tmp->next = tmp2; 
    realocate_end(); 
    break; 
    } 
    tmp=tmp->next; 
} 
} 

void add_online(char* user){ 
online* tmp = (online*)malloc(sizeof(online)); 
tmp->user = user; 
tmp->next = NULL; 


if(begin==NULL){ 
    begin = tmp; 
    end=tmp; 
} 
else{ 
    end->next=tmp; 
    end=end->next; 
} 
} 

void who_online(){ 
online* tmp = begin; 
while(tmp!=NULL){ 
    printf("%s\n",tmp->user); 
    tmp=tmp->next; 
} 
} 

void free_all(){ 
while(begin!=NULL){ 
    online* tmp = begin->next; 
    free(begin); 
    begin = tmp; 
} 
} 

int find_username(char* user){ 
FILE* fp; 
char line[50]; 
fp=fopen("./regist", "r"); 
while(fscanf(fp,"%s",line)!=EOF){ 
    char* name=strtok(line,","); 
    if(strcmp(name,user)==0){ 
    fclose(fp); 
    return 1; 
    } 
} 
return 0; 
} 

char* user_access(char* s){ 
int i=0 ,begin=2; 
strtok(s,":"); 
char* username=strtok(NULL,","); 
char* password=strtok(NULL,";"); 

add_online(username); 


} 

users* find_user_regist(char* user, char* password){ 
    FILE* fp; 
    char line[50]; 

    users* tmp = (users*) malloc(sizeof(users)); 

    fp=fopen("./regist", "r"); 
    while(fscanf(fp,"%s",line)!=EOF){ 
    tmp->name =strtok(line,","); 
    tmp->password = strtok(NULL,";"); 
    if(strcmp(tmp->name,user)==0 && strcmp(tmp->password,password)==0){ 
    fclose(fp); 
    return tmp; 
    } 


    } 
    fclose(fp); 
    return NULL; 
} 

void add_user_regist(char* user,char* password){ 
    FILE* fp; 
    fp=fopen("./regist", "a"); 
    if(fp==NULL) 
    fp=fopen("./regist", "w"); 
    fprintf(fp,"%s,%s;\n",user,password); 
    fclose(fp); 
} 

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <termios.h> 
#include <linux/stat.h> 


#define FIFO_FILE "MYFIFO" 


int main(int argc, char *argv[]) 
{ 
    FILE *fp; 

    char user[50]; 
    char password[50]; 

    if(argc==1){ 
    printf("Não escolheu utilizador\n"); 
    exit(0); 
    } 

    sprintf(user,"%s",argv[1]); 
    printf("Password:\n"); 
    scanf("%s",password); 
    getchar(); 

    char mensagem[250]; 

    if((fp = fopen(FIFO_FILE, "w")) == NULL) { 
    perror("fopen"); 
    exit(1); 
    } 
    char path [100] ; 

    strcpy(path,"."); 
    strcat(path,user); 
    umask(0); 
    mknod(path, S_IFIFO|0666, 0); 

    sprintf(mensagem,"U:%s,%s;",user,password); 
    fputs(mensagem, fp); 
    fclose(fp); 

    while(1){ 

    printf("**Menu**\n1) Listar utilizadores online\n2) Mandar SMS a um utilizador\n3) Logout\n\n"); 

    char opcao; 
    scanf("%c",&opcao); 
    char lixo=getchar(); 

    if(opcao!='1' && opcao!='2' && opcao!='3') 
     continue; 
    if(opcao=='1'){ 
     if((fp = fopen(FIFO_FILE, "w")) == NULL) { 
     perror("fopen"); 
     exit(1); 
    } 
    sprintf(mensagem,"W:%s;",user); 
    fputs(mensagem, fp); 
    fclose(fp); 
    } 
    else if(opcao=='2'){ 

    if((fp = fopen(FIFO_FILE, "w")) == NULL) { 
     perror("fopen"); 
     exit(1); 
    } 

    memset(mensagem,0,sizeof(mensagem)); 
    scanf("%s",mensagem); 
    char lixo=getchar(); 
    fputs(mensagem, fp); 
    fclose(fp); 
    } 
    else if(opcao=='3'){ 
    break; 
    } 

    } 



    return(0); 
} 
+1

的StackOverflow是不是一個調試服務時釋放已分配內存的用戶名。請使用調試器來幫助縮小問題的位置。但首先要確保所有字符串都正確終止,並且記住管道(FIFO是)是*流*通信方法,沒有任何設置的消息邊界。這意味着接收可能收到的信息少於或多於一條,您需要在數據流頂部實施某種協議來自己引入消息邊界(例如,通過啓動/停止序列或固定長度的消息大小頭)。 –

回答

1

這將是一個結果你忘記分配新的內存來存儲你每個用戶的sername。你現在做的方式現在爲每個單獨的用戶分配一個指向字符串的新內存 - 而不是實際的字符串。

如果你遵循的路徑,你在通過函數的結構存儲的值調用,你會看到每一個記錄指向readbuf陣列

考慮一下:

char readbuf[250] = "U:name,password;" 
user_access(readbuf); 

在user_access char *s點字符串的開頭,即U。對strtok的第二次調用返回指向用戶名n開頭的指針,並用空終止符替換,

在調用add_online時的緩衝區現在看起來是這樣的"U\0name\0password\0\0"username指向仍然存儲在readbuf

的C-串"name"當您在鏈接的列表中,您只要將創建一個新的節點指向readbuf中的c字符串的指針,因此用戶名將根據緩衝區中的內容而改變。由於W命令只有一個字符,所以發送到服務器的最後一個用戶名將在緩衝區中保持不變。

要解決這個問題,您可以簡單地爲每個用戶名分配新的內存並複製字符串。

void add_online(char* user){ 
    online* tmp = (online*) malloc(sizeof(online)); 
    tmp->user = (char*) malloc(strlen(user)*sizeof(char)); 
    strcpy(tmp->user, user); 
    tmp->next = NULL; 


    if (begin==NULL){ 
     begin = tmp; 
     end=tmp; 
    } 
    else { 
     end->next=tmp; 
     end=end->next; 
    } 
} 

同樣應該釋放該結構