간단한 tcp채팅 프로그램 만들려하는데 무엇이 문제인지 모르겠습니다.
간단한 tcp를 이용한 채팅프로그램을 만들려고 하고 있습니다. 지금 tcp를 배우는 단계입니다.
그중 채팅 부분은 구현은 성공 하였는데, 그 이후에
파일 전송부분을 어떻게 할까 몇일 생각한 후에, 클라이언트 쓰레드 돌아가는 부분에서 서버와 클라이언트를 쓰레드를 또다시
만들어 보려 했습니다. 코딩은 했는데, 문제가 테스트 결과 다음과 같습니다.
1. 서버측이 종료가 되는것 같다.
2. 파일 다운이 안된다.
번외 3. 왜 그런지 이해가 안된다.
파일 전송을 위해 쓰레드로 만든 부분은 다음 함수와 같습니다.
void *client_send_file_server(void *arg);
void *send_file_function(void *arg);
void *client_resive_file_clnt(void *arg);
void *client_recv_file(void *arg);
혹시 고수님들 초보에게 강의 좀 부탁드립니다.
동작환경은 리눅스 콘솔입니다.
한가지더 있다면 저처럼 만들 경우 $fileup를 몇번이나 쓸경우 메모리 누수가 발생될텐데, 이 경우 어떻게 해결하면 좋습니까?
참고로 저는 tcp/ip배운지 2주된 초보인데(배우는데 1주, 구현에 1주, 남은시간 1주.. 학교 졸업하고.. 밤을.. 더새는 듯합니다. 미니 프로젝트라...)
1주내로 이거 수정해서 완료 시켜야 합니다.
제가 배운게 거의 없어(대학 2학년 전기과... 이후 코딩 한적 없습니다.) 코딩이 조잡하기도 하기때문에 코딩법도 사실 좀 알고 싶습니다.
이건 헤더파일 정의 부분입니다. server측과 server.h와 같다 보시면 됩니다.
#ifndef CLIENT_H_ #define CLIENT_H_ struct USER{ char common[30]; char userid[10]; char userpass[10]; char message[1024]; bool state; int room; bool entered; }; struct FILEUSER{ char filedata[2096]; bool datako; char filename[200]; }; struct FILE_SEND_CLNT{ int clnt_cnt_send; int clnt_socks_send[30]; char filename[200]; };
이 부분은 클라이언트 부분이고요.
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #include <pthread.h> #include <net/if.h> #include <sys/ioctl.h> #include "client.h" using namespace std; pthread_cond_t cond;// = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_o; pthread_mutex_t mutex;// = PTHREAD_MUTEX_INITIALIZER; void *send_msg(void *arg); void *recv_msg(void *arg); void *client_send_file_server(void *arg); void *send_file_function(void *arg); void *client_resive_file_clnt(void *arg); void *client_recv_file(void *arg); USER temp; int main(int argc, char *argv[]) { //cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! int sock; struct sockaddr_in serv_addr; pthread_t snd_thread, rcv_thread; void *thread_return; pthread_mutex_init(&mutex, NULL); if(argc!=2){ printf("usage : %s <IP>\n", argv[0]); exit(1); } printf("start chatting program\n"); sock = socket(PF_INET, SOCK_STREAM, 0); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr=inet_addr(argv[1]); serv_addr.sin_port=htons(9190); if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){ printf("connect() error"); exit(1); } pthread_create(&snd_thread, NULL, send_msg, &sock); pthread_create(&rcv_thread, NULL, recv_msg, &sock); pthread_join(snd_thread, &thread_return); pthread_join(rcv_thread, &thread_return); //close(sock); return 0; } void *send_msg(void *arg){ USER user; int sock = *(int*)arg; int i1=0; pthread_t t_id_send; while(1){ pthread_mutex_lock(&mutex); if(i1==0){i1=1;}else{ if(user.entered==0){ pthread_cond_wait(&cond, &mutex); } } strcpy(user.common, temp.common); user.room=temp.room; user.state=temp.state; user.entered = temp.entered; strcpy(user.userid,temp.userid); strcpy(user.userpass,temp.userpass); pthread_mutex_unlock(&mutex); if(user.entered==0){ if((strcmp(user.common,"$makepass")==0)||(strcmp(user.common, "$enterpass")==0)){ }else{ fflush(stdin); scanf("%s", user.message); } user.state = true; if(strcmp(user.message, "$makeid")==0){ strcpy(user.common, "$makeid"); fputs("make id : \n", stdout); fflush(stdout); fflush(stdin); scanf("%s", user.message); }else if(strcmp(user.common, "$makepass")==0){ fputs("make pass : \n", stdout); fflush(stdout); fflush(stdin); scanf("%s", user.message); }else if(strcmp(user.message, "$enterid")==0){ strcpy(user.common, "$enterid"); fputs("input id : \n", stdout); fflush(stdout); fflush(stdin); scanf("%s", user.message); }else if(strcmp(user.common, "$enterpass")==0){ fputs("input pass : \n", stdout); fflush(stdout); fflush(stdin); scanf("%s", user.message); } }else if(user.entered==1){//분기점 fflush(stdin); scanf("%s", user.message); if(strcmp(user.message, "$enterroom")==0){ strcpy(user.common, "$enterroom"); fputs("insert room number : \n", stdout); fflush(stdout); fflush(stdin); scanf("%d", &user.room); if(user.room>0){ pthread_mutex_lock(&mutex); temp.room=user.room; pthread_mutex_unlock(&mutex); strcpy(user.common, "$chatting"); }else{user.room=0;} }else if(user.room>0){ if(strcmp(user.message, "$fileup")==0){ strcpy(user.common, "$fileup"); //쓰레드 열기 (서버) 송신용 pthread_create(&t_id_send, NULL, client_send_file_server, NULL); //pthread_cond_wait(&cond_o, &mutex); pthread_detach(t_id_send); }else{ strcpy(user.common, "$chatting"); } } } //fgets(user.message, sizeof(user.message), stdin); send(sock, &user, sizeof(user), 0); printf("send\n common:%send\n message:%send\n userid:%send\n userpass:%send\n state:%dend\n room:%dend\n\n", user.common, user.message, user.userid, user.userpass, user.state, user.room); } printf("end chatting"); close(sock); return NULL; } void *recv_msg(void *arg){ USER user; user.state = true; int sock = *((int*)arg); int k; pthread_t t_id_resive; while(1){ user.state = true; k=recv(sock, &user, sizeof(user), 0); if(k>0){ if(user.room==0){ pthread_mutex_lock(&mutex); temp=user;//수정부분 pthread_cond_signal( &cond ); pthread_mutex_unlock(&mutex); }else if(user.room>0){ //pthread_mutex_lock(&mutex); //temp=user;//수정부분 //pthread_cond_signal( &cond ); //pthread_mutex_unlock(&mutex); } } if(user.state==false){ break; } if(user.room>0){ if(strcmp(user.common, "$wannafile")==0){ pthread_mutex_lock(&mutex); fputs(user.message, stdout); fflush(stdout); memset(user.message, 0, sizeof(user.message)); fflush(stdin); scanf(user.message, stdin); pthread_mutex_unlock(&mutex); printf("recv\n common:%send\n message:%send\n userid:%send\n userpass:%send\n state:%dend\n room:%dend\n\n", user.common, user.message, user.userid, user.userpass, user.state, user.room); if(strcmp(user.message, "$yesfile")==0) { //스레드 열기(클라이언트)받기 fputs("11111111111111", stdout); fflush(stdout); pthread_create(&t_id_resive, NULL, client_resive_file_clnt, NULL); pthread_detach(t_id_resive); }else if(strcmp(user.message, "$nofile")==0){ strcpy(user.common, "$chatting"); }else{ strcpy(user.common, "$chatting"); } }else{ strcpy(user.common, "$chatting"); printf("%s : %s\n",user.userid, user.message); } }else if(user.room==0){ printf("%s\n", user.message); } } printf("end chatting"); close(sock); return NULL; } void *client_send_file_server(void *arg){ //send_file_function(void *arg) FILE_SEND_CLNT file_send_clnt; int serv_sock_send, clnt_sock_send; struct sockaddr_in serv_adr_send, clnt_adr_send; socklen_t clnt_adr_sz_send; pthread_t t_id_send; pthread_mutex_init(&mutex, NULL); serv_sock_send=socket(PF_INET, SOCK_STREAM, 0); memset(&serv_adr_send, 0, sizeof(serv_adr_send)); serv_adr_send.sin_family=AF_INET; serv_adr_send.sin_addr.s_addr=htonl(INADDR_ANY); serv_adr_send.sin_port=htons(9191); pthread_mutex_lock(&mutex); fputs("enter your file : ", stdout); fflush(stdout); fflush(stdin); scanf(file_send_clnt.filename, stdin); //pthread_cond_signal( &cond_o ); pthread_mutex_unlock(&mutex); if(bind(serv_sock_send, (struct sockaddr*)&serv_adr_send, sizeof(serv_adr_send))!=-1){ if(listen(serv_sock_send, 5)!=-1){ while(1){ clnt_adr_sz_send=sizeof(clnt_adr_send); clnt_sock_send=accept(serv_sock_send, (struct sockaddr*)&clnt_adr_send, &clnt_adr_sz_send); pthread_mutex_lock(&mutex); file_send_clnt.clnt_socks_send[file_send_clnt.clnt_cnt_send++]=clnt_sock_send; pthread_mutex_unlock(&mutex); pthread_create(&t_id_send, NULL, send_file_function,(void*)&file_send_clnt); pthread_detach(t_id_send); } } } close(serv_sock_send); return 0; } void *send_file_function(void *arg){ FILE_SEND_CLNT *file_send_clnt; FILEUSER select_file; FILE *fd; int clnt_sock_send; int i; file_send_clnt=(FILE_SEND_CLNT *)arg; clnt_sock_send=file_send_clnt->clnt_socks_send[file_send_clnt->clnt_cnt_send]; strcpy(select_file.filename, file_send_clnt->filename); fd=fopen(select_file.filename,"r"); while(fgets(select_file.filedata, sizeof(select_file.filedata), fd)){ select_file.datako=1; send(clnt_sock_send, &select_file, sizeof(select_file), 0); } select_file.datako=0; memset(select_file.filedata, 0, sizeof(select_file.filedata)); sprintf(select_file.filedata,"%s data download clear\n", select_file.filename); send(clnt_sock_send, &select_file, sizeof(select_file),0); pthread_mutex_lock(&mutex); for(i=0; i<file_send_clnt->clnt_cnt_send; i++){ if(clnt_sock_send==file_send_clnt->clnt_socks_send[i]){ while(i++<file_send_clnt->clnt_cnt_send-1){ file_send_clnt->clnt_socks_send[i]=file_send_clnt->clnt_socks_send[i+1]; } break; } } file_send_clnt->clnt_cnt_send--; pthread_mutex_unlock(&mutex); fclose(fd); close(clnt_sock_send); return 0; } void *client_resive_file_clnt(void *arg){ int sock_resive; struct sockaddr_in serv_addr_resive; pthread_t rcv_thread_resive; void *thread_return_resive; int fd_recv; struct ifreq ifrq; struct sockaddr_in *sin; fd_recv = socket(AF_INET, SOCK_DGRAM, 0); strcpy(ifrq.ifr_name, "eth0"); ioctl(fd_recv, SIOCGIFADDR, &ifrq); sin = (sockaddr_in *)&ifrq.ifr_addr; sock_resive=socket(PF_INET, SOCK_STREAM, 0); memset(&serv_addr_resive, 0, sizeof(serv_addr_resive)); serv_addr_resive.sin_family=AF_INET; serv_addr_resive.sin_addr.s_addr=inet_addr(inet_ntoa(sin->sin_addr)); serv_addr_resive.sin_port=htons(9191); connect(sock_resive, (struct sockaddr*)&serv_addr_resive, sizeof(serv_addr_resive)); pthread_create(&rcv_thread_resive, NULL, client_recv_file, (void*)&sock_resive); pthread_join(rcv_thread_resive, &thread_return_resive); return 0; } void *client_recv_file(void *arg){ int sock_resive=*((int*)arg); FILEUSER user_resive_file; FILE *fd; char buf[200]; recv(sock_resive, &user_resive_file, sizeof(user_resive_file), 0); sprintf(buf,"~/%s", rtrimtoslash(user_resive_file.filename)); fd=fopen(buf, "w"); while(1){ if(user_resive_file.datako==1){ fputs(user_resive_file.filedata, fd); recv(sock_resive, &user_resive_file, sizeof(user_resive_file), 0); }else if(user_resive_file.datako==0){ printf("%s\n",user_resive_file.filedata); break; } } return 0; }
이 부분은 서버 측 소스 입니다.
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #include <pthread.h> #include "server.h" using namespace std; pthread_mutex_t mutex; int clnt_cnt=0; int clnt_socks[30]; USER s_clnt_master[30]; void *chatting_handle(void *arg); void send_msg(USER *user, int clnt); int main(int argc, char *argv[]) { //cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!! int serv_sock, clnt_sock; struct sockaddr_in serv_adr, clnt_adr; int clnt_adr_size; pthread_mutex_init(&mutex, NULL); pthread_t t_id; serv_sock=socket(PF_INET, SOCK_STREAM, 0); memset(&serv_adr, 0, sizeof(serv_adr)); serv_adr.sin_addr.s_addr=htonl(INADDR_ANY); serv_adr.sin_port = htons(9190); if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1){ printf("bind() error"); exit(1); } if(listen(serv_sock, 20) == -1){ printf("listen() error"); exit(1); } while(1){ clnt_adr_size = sizeof(clnt_adr); clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, (unsigned int *)&clnt_adr_size); //printf("connection request : %s : %d\n", inet_ntoa(clnt_adr.sin_addr), ntohs(clnt_adr.sin_port)); pthread_mutex_lock(&mutex); clnt_socks[clnt_cnt++] = clnt_sock; pthread_mutex_unlock(&mutex); pthread_create(&t_id, NULL, chatting_handle, (void *)&clnt_sock); pthread_detach(t_id); } pthread_mutex_destroy(&mutex); close(serv_sock); return 0; } void *chatting_handle(void *arg){ USER user; int clnt_sock = *((int*)arg); int i; while(1){ user.state = false; recv(clnt_sock, &user, sizeof(user), 0); pthread_mutex_lock(&mutex); for(i=0; i<clnt_cnt; i++){ if(clnt_sock==clnt_socks[i]){ s_clnt_master[i]=user; break; } } pthread_mutex_unlock(&mutex); send_msg(&user, clnt_sock); if(user.state==false){ break; } } printf("end chatting\n"); pthread_mutex_lock(&mutex); for(i=0; i<clnt_cnt; i++){ if(clnt_sock==clnt_socks[i]){ while(i++<clnt_cnt-1){ clnt_socks[i] = clnt_socks[i+1]; s_clnt_master[i] = s_clnt_master[i+1]; } break; } } clnt_cnt--; pthread_mutex_unlock(&mutex); return 0; } void send_msg(USER *user, int clnt){ int i;//,fd; FILE *fd; USER usersize; char buf[4096]; char *ptr; int checkid; if(user->entered==0){ if(strcmp(user->common, "$makeid")==0){ fd=fopen("./db/db.dat","r+a"); fgets(buf, 4096, fd); for(i =0; i<30; i++){ user->common[i]=0; } ptr=strtok(buf," "); checkid =1; while(ptr!=NULL){ if(strcmp(user->message, ptr)==0) { checkid=0; break; } //printf("%s\n",ptr); ptr=strtok(NULL," "); ptr=strtok(NULL," "); } if(checkid==1){ strcpy(user->common, "$makepass"); strcpy(user->userid, user->message); } for(i =0; i<1024; i++){ user->message[i]=0; } fclose(fd); }else if(strcmp(user->common,"$makepass")==0){ fd=fopen("./db/db.dat","r+a"); fgets(buf, 4096, fd); for(i=0; i<30; i++){ user->common[i]=0; } if(((user->userid[0]>0x40)&&(user->userid[0]<0x5b))||((user->userid[0]>0x60)&&(user->userid[0]<0x7b))||((user->userpass[0]>0x40)&&(user->userpass[0]<0x5b))||((user->userpass[0]>0x60)&&(user->userpass[0]<0x7b))){ fputs(user->userid, fd); fputs(" ", fd); fputs(user->message, fd); fputs(" ", fd); } for(i=0; i<30; i++){ user->userid[i]=0; } strcpy(user->message, "id make success"); fclose(fd); }else if(strcmp(user->common, "$enterid")==0){ fd=fopen("./db/db.dat","r"); fgets(buf, 4096, fd); for(i=0; i<30; i++){ user->common[i]=0; } checkid = 0; ptr=strtok(buf," "); while(ptr != NULL){ checkid=0; if(strcmp(user->message, ptr)==0) { checkid=1; break; } ptr=strtok(NULL," "); ptr=strtok(NULL," "); } if(checkid==1){ strcpy(user->userid, user->message); strcpy(user->common, "$enterpass"); } for(i =0; i<1024; i++){ user->message[i]=0; } fclose(fd); }else if(strcmp(user->common, "$enterpass")==0){ fd=fopen("./db/db.dat","r"); fgets(buf, 4096, fd); for(i=0; i<30; i++){ user->common[i]=0; } ptr=strtok(buf," "); checkid =1; while(ptr!=NULL){ if(strcmp(user->userid, ptr)==0) { checkid=0; break; } ptr=strtok(NULL," "); ptr=strtok(NULL," "); } printf("test\n"); ptr=strtok(NULL," "); if(strcmp(ptr, user->message)==0) { if(checkid==0){ user->entered = 1; strcpy(user->message, "you enter id"); }else{ strcpy(user->message, "you cannot enter this id"); for(i=0; i<10; i++){ user->userid[i]=0; } } } fclose(fd); } }else if(user->entered==1){//분기점 if(user->room==0){ }else if(user->room>0){ if(strcmp(user->common, "$chatting")==0){ //////////////////////////////////여기가 파일 명령어 처리 부분 } } } printf(" common:%send\n message:%send\n userid:%send\n userpass:%send\n state:%dend\n room:%dend\n\n", user->common, user->message, user->userid, user->userpass, user->state, user->room); pthread_mutex_lock(&mutex); if(user->entered==0){ send(clnt, user, sizeof(usersize),0); }else if(user->entered==1){ if(user->room==0){ send(clnt, user, sizeof(usersize),0); }else if(user->room>0){ if(strcmp(user->common, "$chatting")==0){ for(i = 0; i<clnt_cnt; i++){ if(s_clnt_master[i].room==user->room){ send(clnt_socks[i], user, sizeof(usersize),0); } } }else if(strcmp(user->common, "$fileup")==0){ memset(user->common, 0, sizeof(user->common)); strcpy(user->common, "$wannafile"); for(i = 0; i<clnt_cnt; i++){ if(s_clnt_master[i].room==user->room){ if(clnt_socks[i]!=clnt){ strcpy(user->message, "wanna file down? [$nofile/$yesfile]"); for(i = 0; i<clnt_cnt; i++){ if(s_clnt_master[i].room==user->room){ if(clnt_socks[i]!=clnt){ send(clnt_socks[i], user, sizeof(usersize),0); } } } } } } }else{ strcpy(user->common, "$chatting"); for(i = 0; i<clnt_cnt; i++){ if(s_clnt_master[i].room==user->room){ send(clnt_socks[i], user, sizeof(usersize),0); } } } }else{ send(clnt, user, sizeof(usersize),0); } } pthread_mutex_unlock(&mutex); }
댓글 달기