채팅프로그램 구현중 오류
글쓴이: ch0nn0m / 작성시간: 월, 2010/08/23 - 6:22오후
리눅스 상에서 채팅프로그램을 구현했는데요...
컴파일까지는 에러없이 잘 진행이 되었는데...
실행을 하게 되면...
서버측에서 세그멘테이션 오류가 나오면서 끊겨버리네요...
어디가 잘못된것인지요??
server.c
/* 연결리스트로 구현하여 무한의 유저 수와 방 개수 가질 수 있는 채팅서버 - 각 방이 가지는 유저에 대해서는 구조체로 관리 동시처리에 대해서는 select이용 */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <strings.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> /* 유저가 가질수 있는 데이터 : 대화명(귓속말등 기타 기능 추가시 서버에서 관리) / 소켓 기술자 / 다음 유저(연결리스트) */ struct user_node { char user_name[30]; int user_sockfd; struct user_node *next_user; }; /* Linked List로 유저에 대한 동적인 할당 방이 가지는 데이터 : 방인원수 / 방이름 / 다음 방 노드 포인터 / 사용자 데이터 */ struct room_node { int user_count; char room_name[30]; struct room_node *next_room; struct user_node *user; }; typedef struct user_node user; typedef struct room_node room; int Socket(int family, int type, int protocol); void Bind (int sockfd, const struct sockaddr * socketaddr, socklen_t addrlen); void Listen(int sockfd, int backlog); int Accept(int sockfd, struct sockaddr* cliaddr, socklen_t *addrlen); //명령어 확인 함수 int command_valid(char *); int main(int argc, char * argv[]) { //프로그램 실행시 인자 확인 if(argc != 2){ printf("포트번호를 인자로 받아야 함. ex)tcs 22030\n"); exit(1); } room *roomlist, *new_node, *temp_node, *prev_node, *make_node; user *userlist, *new_user, *temp_user, *prev_user, *prev_remove_user; int server_socket; int client_socket; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int addrsize, msgsize, all_user_count=0; char BUFF[1024] = {0}; char temp_char[30]; fd_set readfd; int maxfd; //방번호 int room_index, i, j; char char_room_index[10] = {10}; int tempsockfd; //명령어 flag int order_flag = 0; //방조인 flag int join_flag = 0; int join_num = 0; //사용자 중복 flag int user_flag = 0; //1:1대화 char talk_user[30]; char char_talk_port[6]; int talk_port = 0; int talk_sockfd = 0; int talk_flag = 0; new_node = NULL; temp_node = NULL; //대기실 설정 roomlist = (room *)malloc(sizeof(room)); memset(roomlist->room_name, '\0', 30); strcpy(roomlist->room_name, ""); roomlist->user_count = 0; roomlist->next_room = new_node; roomlist->user = NULL; //new_node는 언제나 roomlist만 나타낸다. new_node = roomlist; /*1. 서버소켓생성*/ server_socket = Socket(AF_INET, SOCK_STREAM, 0); /*서버 IP및 포트 설정*/ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(atoi(argv[1])); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); memset(&(server_addr.sin_zero), 0, 8); //소켓 bind Bind(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); //소켓 listen Listen(server_socket, 0); while(1) { FD_ZERO(&readfd); maxfd = server_socket; /*서버에접속한 클라이언트 소켓 기술자[각 방의 유저구조체포함]를 fd_set에 설정*/ FD_SET(server_socket, &readfd); //첫번째방(대기실)을 지정 roomlist = new_node; while(roomlist) { //각 방의 처음 유저를 지정 temp_user = roomlist->user; while(temp_user) { //사용자들의 소켓 기술자를 설정 / 최대값 저장 tempsockfd = temp_user->user_sockfd; FD_SET(tempsockfd, &readfd); if (tempsockfd > maxfd) maxfd = tempsockfd; temp_user = temp_user->next_user; } roomlist = roomlist->next_room; } maxfd = maxfd + 1; select(maxfd, &readfd, NULL, NULL, NULL); /*서버로의 접속이 있는 클라이언트에 대한 처리*/ if (FD_ISSET(server_socket, &readfd)) { addrsize = sizeof(struct sockaddr_in); client_socket = Accept(server_socket, (struct sockaddr*)&server_addr, &addrsize); memset(BUFF, '\0', sizeof(BUFF)); msgsize = read(client_socket, BUFF, sizeof(BUFF)); //사용자 이름 중복 확인 roomlist = new_node; while(roomlist) { temp_user = roomlist->user; while(temp_user) { if (strcmp(BUFF, temp_user->user_name)==0) //사용자와 같은 이름을 가진 사람이 있을 경우 user_flag = 1; temp_user = temp_user->next_user; } roomlist = roomlist->next_room; } //같은 이름이 존재하는 경우 if(user_flag == 1){ strcat(BUFF, "같은 이름이 존재합니다. 다시 접속해주십시요.\n"); write(client_socket, BUFF, strlen(BUFF)); close(client_socket); user_flag = 0; } //같은 이름이 없을 경우 else{ if (msgsize <=0) { printf("Enter user Error\n"); continue; } printf("Receive Message:%s\n", BUFF); //새로운 유저 데이터 공간 할당 new_user = (user *)malloc(sizeof(user)); new_user->user_sockfd = client_socket; memset(new_user->user_name, '\0', 30); strcpy(new_user->user_name, BUFF); roomlist = new_node; temp_user = roomlist->user; while(temp_user) { prev_user = temp_user; temp_user = temp_user->next_user; } //첫번째로 입장한 경우 if(prev_user == NULL){ roomlist->user = new_user; new_user->next_user = NULL; } //첫번째로 입장한 경우가 아닌 경우 else{ new_user->next_user = prev_user->next_user; prev_user->next_user = new_user; } //방의 인원 증가 / 전체 인원 증가 roomlist->user_count++; all_user_count++; printf("현재 접속 인원은 %d명 입니다.\n", all_user_count); printf("%s가 접속했습니다.\n", new_user->user_name); memset(BUFF, '\0', sizeof(BUFF)); strcpy(BUFF, "ConnectOK\n"); //현재의 방, 사용자 접속 정보 roomlist = new_node; room_index = 0; strcat(BUFF, "############현재 접속 현황############\n"); while(roomlist) { if(room_index == 0) strcat(BUFF, "대기실 "); else{ sprintf(char_room_index, "%d", room_index); //방번호 문자열로 변환 strcat(BUFF, char_room_index); strcat(BUFF, "번방 " ); } strcat(BUFF, roomlist->room_name); strcat(BUFF, " : "); temp_user = roomlist->user; while(temp_user) { strcat(BUFF, temp_user->user_name); strcat(BUFF, ", "); temp_user = temp_user->next_user; } strcat(BUFF, "\n"); roomlist = roomlist->next_room; ++room_index; } strcat(BUFF, "########################################\n"); //사용자에게 방, 사용자 접속 정보를 보내줌 write(client_socket, BUFF, strlen(BUFF)); printf("%s\n", BUFF); continue; } } /* 각 방에 속한 모든 유저들의 소켓 기술자의 변화를 감지하여 해당 수신 데이터에 대한 응답을 같은 방에 있는 유저에 한해서 송신 */ roomlist = new_node; prev_node = NULL; room_index = 0; while(roomlist) { temp_user = roomlist->user; prev_remove_user = NULL; while(temp_user) { //현재 temp_user에서 데이터 변화가 있을 경우 if (FD_ISSET(temp_user->user_sockfd, &readfd)) { memset(BUFF, '\0', sizeof(BUFF)); tempsockfd = temp_user->user_sockfd; msgsize = read(tempsockfd, BUFF, sizeof(BUFF)); //사용자가 없을 경우 if (msgsize <= 0) { roomlist->user_count--; all_user_count--; printf("%s is out!\n", temp_user->user_name); //방의 첫번째 포인터에 있는 사용자일 경우 if(prev_remove_user == NULL) { roomlist->user = temp_user->next_user; } else { prev_remove_user->next_user = temp_user->next_user; } close(temp_user->user_sockfd); free(temp_user); } //사용자가 메시지를 보냈을 경우 else { prev_user = roomlist->user; printf("Receive Message=>%s\n", BUFF); msgsize = strlen(BUFF); //명령어 확인 함수 order_flag = command_valid(BUFF); switch(order_flag){ case 0 : //보통 대화문 while(prev_user) { //같은 방에서 자신을 제외한 사람들에게 메시지를 전송 if(prev_user->user_sockfd != tempsockfd){ write(prev_user->user_sockfd, BUFF, msgsize); printf("tempusersockfd %d\n", prev_user->user_sockfd); } prev_user = prev_user->next_user; } break; case 1 : //방 만들기 //방 설정 make_node = (room *)malloc(sizeof(room)); printf("%s\n", BUFF+6); memset(make_node->room_name, '\0', 30); strcpy(make_node->room_name, BUFF+6); make_node->user_count = 1; make_node->next_room = roomlist->next_room; roomlist->next_room = make_node; roomlist->user_count--; //현재방 인원 감소 //유저 설정 if(prev_remove_user == NULL) { roomlist->user = temp_user->next_user; } else { prev_remove_user->next_user = temp_user->next_user; } make_node->user = temp_user; temp_user->next_user = NULL; printf("새로운 방이 만들어졌습니다.\n"); strcpy(BUFF, "방을 만들었습니다."); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); break; case 2 : //방 조인 //들어갈 방 찾기 join_flag = 0; join_num = atoi(BUFF+6); temp_node = new_node; for(i = 0; i < join_num; i++){ temp_node = temp_node->next_room; join_flag = 1; } if(join_flag == 1){ roomlist->user_count--; //현재방 인원 감소 //유저 설정 if(prev_remove_user == NULL) { roomlist->user = temp_user->next_user; } else { prev_remove_user->next_user = temp_user->next_user; } new_user = temp_node->user; while(new_user) { prev_user = new_user; new_user = new_user->next_user; } temp_user->next_user = prev_user->next_user; prev_user->next_user = temp_user; temp_node->user_count++; //들어가는 방 인원 증가 strcpy(BUFF, "방을 들어갔습니다."); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); } else { strcpy(BUFF, "방을 찾을 수 없습니다."); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); } break; case 3 : //방에서 나가기 //방 설정 roomlist->user_count--; //현재방 인원 감소 //유저 설정 if(prev_remove_user == NULL) { roomlist->user = temp_user->next_user; } else { prev_remove_user->next_user = temp_user->next_user; } temp_node = new_node; new_user = temp_node->user; while(new_user) { prev_user = new_user; new_user = new_user->next_user; } temp_user->next_user = prev_user->next_user; prev_user->next_user = temp_user; temp_node->user_count++; //들어가는 방 인원 증가 if(roomlist->user_count == 0) //방에 인원이 한명도 없을 경우 { if(strcmp(roomlist->room_name, "") != 0){ prev_node->next_room = roomlist->next_room; free(roomlist); printf("방이 없어졌습니다.\n"); } } strcpy(BUFF, "방을 나갔습니다."); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); break; case 4 : //채팅 종료하기 //방 설정 roomlist->user_count--; //현재방 인원 감소 all_user_count--; //총 인원 감소 printf("%s is out!\n", temp_user->user_name); //유저 설정 if(prev_remove_user == NULL) { roomlist->user = temp_user->next_user; } else { prev_remove_user->next_user = temp_user->next_user; } close(temp_user->user_sockfd); free(temp_user); temp_node = new_node; if(roomlist->user_count == 0) //방에 인원이 한명도 없을 경우 { if(strcmp(roomlist->room_name, "") != 0){ //대기실이 아닌 경우 prev_node->next_room = roomlist->next_room; free(roomlist); printf("방이 없어졌습니다.\n"); } } break; case 5 : //방 현황 보여주기 memset(BUFF, '\0', sizeof(BUFF)); //현재 방, 사용자 접속 정보 temp_node = new_node; room_index = 0; strcat(BUFF, "############현재 접속 현황############\n"); while(temp_node) { if(room_index == 0) strcat(BUFF, "대기실 "); else{ sprintf(char_room_index, "%d", room_index); //방번호 문자열로 변환 strcat(BUFF, char_room_index); strcat(BUFF, "번방 " ); } strcat(BUFF, temp_node->room_name); strcat(BUFF, " : "); prev_user = temp_node->user; while(prev_user) { strcat(BUFF, prev_user->user_name); strcat(BUFF, ", "); prev_user = prev_user->next_user; } strcat(BUFF, "\n"); temp_node = temp_node->next_room; ++room_index; } strcat(BUFF, "######################################\n"); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); break; case 6 : //1:1대화 //상대편 이름, 채팅 포트 분류 talk_flag = 0; strcpy(temp_char, BUFF+6); for(i=0; i<30; i++){ if(temp_char[i] == ' '){ break; } talk_user[i] = temp_char[i]; } talk_user[i] = 0; for(j=0; j<30; j++){ if(temp_char[i] == 0){ break; } char_talk_port[j] = temp_char[i]; i++; } char_talk_port[j] = 0; talk_port = atoi(char_talk_port); //사용자 이름 찾기 temp_node = new_node; while(temp_node) { prev_user = temp_node->user; while(prev_user) { if (strcmp(talk_user, prev_user->user_name)==0){ //사용자와 같은 이름을 가진 사람이 있을 경우 talk_sockfd = prev_user->user_sockfd; talk_flag = 1; } prev_user = prev_user->next_user; } temp_node = temp_node->next_room; } if(talk_flag == 1) { memset(BUFF, '\0', sizeof(BUFF)); strcpy(BUFF, ".multi"); strcat(BUFF, char_talk_port); msgsize = strlen(BUFF); write(talk_sockfd, BUFF, msgsize); } else { strcat(BUFF, "사용자가 존재하지 않습니다."); msgsize = strlen(BUFF); write(temp_user->user_sockfd, BUFF, msgsize); } break; default : break; } } } prev_remove_user = temp_user; temp_user = temp_user->next_user; } prev_node = roomlist; roomlist = roomlist->next_room; } } return 0; } int Socket(int family, int type, int protocol) { int result = 0; result = socket(family, type, protocol); if (result == -1) { printf("Socket Contructing Error\n"); exit(0); } return result; } void Bind(int sockfd, const struct sockaddr * socketaddr, socklen_t addrlen) { int result = 0; result = bind(sockfd, socketaddr, addrlen); if (result == -1) { printf("Socket Binding Error\n"); exit(0); } else { printf("Success Binding\n"); } } void Listen(int sockfd, int backlog) { int result = 0; result = listen(sockfd, backlog); if (result == -1) { printf("Listening Error\n"); exit(0); } else { printf("Success Listening\n"); } } int Accept(int sockfd, struct sockaddr* cliaddr, socklen_t *addrlen) { int result = 0; result = accept(sockfd, cliaddr, addrlen); if (result == -1) { printf("Accept Error\n"); exit(0); } else { printf("Success Accept\n"); } return result; } //명령어 확인 함수 int command_valid(char *BUFF){ char temp[5]; int i; for(i = 0; i < 5; i++){ temp[i] = *BUFF; BUFF++; } if(strcmp(temp, ".make")==0){ //방만들기 return 1; } else if(strcmp(temp, ".join")==0){ //방조인 return 2; } else if(strcmp(temp, ".quit")==0){ //방나가기 return 3; } else if(strcmp(temp, ".exit")==0){ //접속 종료 return 4; } else if(strcmp(temp, ".show")==0){ //방 / 접속 인원 현황 return 5; } else if(strcmp(temp, ".talk")==0){ //1:1대화 신청 return 6; } return 0; }
client.c
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <strings.h> #include <unistd.h> #include <stdio.h> #include <pthread.h> int Socket(int family, int type, int protocol); void Connect(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen); int command_valid(char *, int); int msg_conf(char *); void Multicast_exe(); //멀티 채팅용 void* thread_process(void * sockfd); struct sockaddr_in multicast_group_addr; struct ip_mreq mreq; int multi_exit(char *BUFF); int main(int argc, char * argv[]) { //실행시 인자 확인 if(argc != 3){ printf("도메인 네임과 포트번호를 인자로 받아야 함. ex)tcs 203.250.148.46 22030\n"); exit(1); } struct sockaddr_in connect_addr; int connect_fd, i, j; int msgsize; char name[30] = {0}; char msg[1024] = {0}; fd_set readfd; int temp_index; int state_flag = 0; //사용자 위치 flag : 0일 경우 대기실, 1일 경우 방 안 int msg_flag = 0; //보낸 메시지 flag int rec_flag = 0; //받은 메시지 flag //1:1 채팅 사용 변수 int multicast_send_sockfd; int multicast_recv_sockfd; int multicast_index; int ttl; char send_data[1024] = {0}; pthread_t thread; char user_name[30] = {0}; int send_result; ttl = 64; multicast_index = 1; int rec_port = 0; char temp_char[30]; char char_talk_port[30]; int talk_port = 0; printf("#################################\n"); printf("###Welcome to Chatting Browser###\n"); printf("#################################\n"); printf("#Enter User Name=> "); memset(name, '\0', sizeof(name)); /*사용자 대화명 입력 처리*/ fgets(name,30, stdin); strcpy(user_name, name); //멀티채팅용 이름 user_name[strlen(user_name)-1] = ']'; name[strlen(name)-1] = '\0'; memset(msg, '\0', sizeof(msg)); for (temp_index = 0; temp_index < strlen(name); temp_index++) { msg[temp_index] = name[temp_index]; } connect_fd = Socket(AF_INET, SOCK_STREAM, 0); connect_addr.sin_family = AF_INET; connect_addr.sin_port = htons(atoi(argv[2])); connect_addr.sin_addr.s_addr = inet_addr(argv[1]); memset(&(connect_addr.sin_zero), 0, 8); /*서버 접속*/ Connect(connect_fd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)); msgsize = strlen(msg); write(connect_fd, msg, msgsize); memset(msg, '\0', sizeof(msg)); /*채팅 서버에 대한 접속 결과 확인*/ read(connect_fd, msg, sizeof(msg)); printf("########################################\n"); printf("####채팅서버에 접속하셨습니다.##########\n"); printf("########################################\n"); printf("## 방만들기 : .make 방제목 ##\n"); printf("## 방들어가기 : .join 방번호 ##\n"); printf("## 방나가기 : .quit ##\n"); printf("## 접속종료 : .exit ##\n"); printf("## 사용자현황 : .show ##\n"); printf("## 명령어출력 : .help ##\n"); printf("## 귓속말 : .talk 상대방이름 포트번호 ##\n"); printf("########################################\n"); printf("%s\n", msg); /*수신 데이타의 동시 처리*/ FD_ZERO(&readfd); while(1) { FD_SET(0, &readfd); FD_SET(connect_fd, &readfd); select (connect_fd+1, &readfd, NULL, NULL, NULL); //서버에서 데이터를 받은 경우 if (FD_ISSET(connect_fd, &readfd)) { memset(msg, '\0', sizeof(msg)); msgsize = read(connect_fd, msg, sizeof(msg)); if (msgsize <= 0) continue; //받은 메시지 확인 rec_flag = msg_conf(msg); //1:1 채팅 요청인 경우 if(rec_flag == 1) { //앞의 6개 문자를 제외한 후 포트번호로 할당 rec_port = atoi(msg+6); /*멀티 캐스트 수신 및 송신 소켓 생성*/ multicast_recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0); multicast_send_sockfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&multicast_group_addr, 0, sizeof(multicast_group_addr)); /*멀티 캐스트 주소 및 포트 설정*/ multicast_group_addr.sin_family = AF_INET; multicast_group_addr.sin_port = htons(rec_port); //동적인 포트번호(1:1통신을 할수 있게 해줌) multicast_group_addr.sin_addr.s_addr = inet_addr("239.100.150.200"); //임의의 멀티캐스트 주소 /*멀티 캐스트 주소와 수신 IP주소 설정*/ mreq.imr_multiaddr = multicast_group_addr.sin_addr; mreq.imr_interface.s_addr = htonl(INADDR_ANY); multicast_recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0); /*소켓 옵션 설정 멀티캐스트 그룹 추가*/ setsockopt(multicast_recv_sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); /*소켓 재사용*/ setsockopt(multicast_recv_sockfd, SOL_SOCKET, SO_REUSEADDR, &multicast_index, sizeof(multicast_index)); /*TTL설정*/ setsockopt(multicast_recv_sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); send_result = bind(multicast_recv_sockfd, (struct sockaddr*)&multicast_group_addr, sizeof(multicast_group_addr)); if (send_result < 0) { printf("!Bind Error\n"); exit(0); } else { printf("####################################\n"); printf("## Start 1:1 Chatting Program ##\n"); printf("## 종료명령은 .exit입니다. ##\n"); printf("####################################\n"); } /*수신 데이타에 대한 Thread 처리*/ pthread_create(&thread, NULL, thread_process, (void*)multicast_recv_sockfd); while(1) { memset(send_data, '\0', sizeof(send_data)); fgets(send_data, sizeof(send_data), stdin); if(multi_exit(send_data)){ close(multicast_send_sockfd); close(multicast_recv_sockfd); printf("멀티 채팅 종료\n"); break; } else { send_data[strlen(send_data) -1] = '['; strcat(send_data, user_name); send_result = sendto(multicast_send_sockfd, send_data, strlen(send_data), 0, (struct sockaddr*)&multicast_group_addr, sizeof(multicast_group_addr)); } } } //대화문인 경우 else { printf("%s\n", msg); } } if (FD_ISSET(0, &readfd)) { memset(msg, '\0', sizeof(msg)); fgets(msg, 1024, stdin); //보내는 메시지 확인 msg_flag = command_valid(msg, state_flag); switch(msg_flag) { case 0 : //대화문인 경우 if((*msg != '.')){ msg[strlen(msg)-1] = '['; strcat(msg, name); msg[strlen(msg)] = ']'; } msgsize = strlen(msg); write(connect_fd, msg, msgsize); break; case 1 : //에러일 경우 : 데이터를 보내지 않음. break; case 2 : //접속 종료인 경우 msgsize = strlen(msg); write(connect_fd, msg, msgsize); printf("연결을 종료하겠습니다.\n"); close(connect_fd); exit(1); break; case 3 : //명령어 출력 break; case 4 : //명령어인 경우(대기실 -> 방안) msgsize = strlen(msg); write(connect_fd, msg, msgsize); state_flag = 1; break; case 5 : //명령어인 경우(방안 -> 대기실) msgsize = strlen(msg); write(connect_fd, msg, msgsize); state_flag = 0; break; case 6 : //명령어인 경우(위치 변동 없음) msgsize = strlen(msg); write(connect_fd, msg, msgsize); break; case 7 : //멀티 채팅 //서버에 먼저 데이터를 전송한다. msgsize = strlen(msg); write(connect_fd, msg, msgsize); //채팅 포트 분류 strcpy(temp_char, msg+6); printf("%s\n", temp_char); for(i=0; i<30; i++){ if(temp_char[i] == ' '){ break; } } for(j=0; j<30; j++){ if(temp_char[i] == 0){ break; } char_talk_port[j] = temp_char[i]; i++; } char_talk_port[j] = 0; talk_port = atoi(char_talk_port); /*멀티 캐스트 수신 및 송신 소켓 생성*/ multicast_recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0); multicast_send_sockfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&multicast_group_addr, 0, sizeof(multicast_group_addr)); /*멀티 캐스트 주소 및 포트 설정*/ multicast_group_addr.sin_family = AF_INET; multicast_group_addr.sin_port = htons(talk_port); multicast_group_addr.sin_addr.s_addr = inet_addr("239.100.150.200"); /*멀티 캐스트 주소와 수신 IP주소 설정*/ mreq.imr_multiaddr = multicast_group_addr.sin_addr; mreq.imr_interface.s_addr = htonl(INADDR_ANY); multicast_recv_sockfd = socket(AF_INET, SOCK_DGRAM, 0); /*소켓 옵션 설정 멀티캐스트 그룹 추가*/ setsockopt(multicast_recv_sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); /*소켓 재사용*/ setsockopt(multicast_recv_sockfd, SOL_SOCKET, SO_REUSEADDR, &multicast_index, sizeof(multicast_index)); /*TTL설정*/ setsockopt(multicast_recv_sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); send_result = bind(multicast_recv_sockfd, (struct sockaddr*)&multicast_group_addr, sizeof(multicast_group_addr)); if (send_result < 0) { printf("!Bind Error\n"); exit(0); } else { printf("####################################\n"); printf("## Start 1:1 Chatting Program ##\n"); printf("## 종료명령은 .exit입니다. ##\n"); printf("####################################\n"); } /*수신 데이타에 대한 Thread 처리*/ pthread_create(&thread, NULL, thread_process, (void*)multicast_recv_sockfd); while(1) { memset(send_data, '\0', sizeof(send_data)); fgets(send_data, sizeof(send_data), stdin); if(multi_exit(send_data)){ close(multicast_send_sockfd); close(multicast_recv_sockfd); printf("멀티 채팅 종료\n"); break; } else { send_data[strlen(send_data) -1] = '['; strcat(send_data, user_name); send_result = sendto(multicast_send_sockfd, send_data, strlen(send_data), 0, (struct sockaddr*)&multicast_group_addr, sizeof(multicast_group_addr)); } } break; default : break; } } } return 0; } void Connect(int sockfd, const struct sockaddr* servaddr, socklen_t addrlen) { int result = 0; result = connect(sockfd, servaddr, addrlen); if (result == -1) { printf("접속을 할 수 없습니다.\n"); exit(0); } } int Socket(int family, int type, int protocol) { int result = 0; result = socket(family, type, protocol); if (result == -1) { printf("Socket Contructing Error\n"); exit(0); } return result; } int command_valid(char *BUFF, int state_flag){ char temp[5]; int i; for(i = 0; i < 5; i++){ temp[i] = *BUFF; BUFF++; } if((strcmp(temp, ".make")==0) && (state_flag == 1)){ //방만들기 에러 printf("방 접속시에는 방을 만들 수 없습니다.\n"); return 1; } else if((strcmp(temp, ".join")==0) && (state_flag ==1)){ //방조인 에러 printf("방 접속시에는 다른 방에 접속 할 수 없습니다.\n"); return 1; } else if((strcmp(temp, ".quit")==0) && (state_flag == 0)){ //방나가기 에러 printf("대기실에서는 방에서 나갈 수 없습니다.\n"); return 1; } else if(strcmp(temp, ".help")==0){ //명령어 출력 printf("################################################\n"); printf("## 방만들기 : .make 방제목 ##\n"); printf("## 방들어가기 : .join 방번호 ##\n"); printf("## 방나가기 : .quit ##\n"); printf("## 접속종료 : .exit ##\n"); printf("## 사용자현황 : .show ##\n"); printf("## 명령어출력 : .help ##\n"); printf("## 귓속말 : .talk 상대방이름 포트번호 ##\n"); printf("################################################\n"); return 3; } else if((strcmp(temp, ".quit")==0) && (state_flag == 0)){ //접속 종료 return 2; } else if((strcmp(temp, ".make")==0) || (strcmp(temp, ".join")==0)){ //보통 명령어(대기실 -> 방안) return 4; } else if((strcmp(temp, ".quit")==0)){ //보통 명령어(방안 -> 대기실) return 5; } else if((strcmp(temp, ".show")==0)){ //보통 명령어(위치 변동 없음) return 6; } else if((strcmp(temp, ".talk")==0)){ return 7; } return 0; } int multi_exit(char *BUFF){ char temp[5]; int i; for(i = 0; i < 5; i++){ temp[i] = *BUFF; BUFF++; } if(strcmp(temp, ".exit")==0) //멀티채팅 종료 return 1; return 0; } void * thread_process(void * sockfd) { struct sockaddr_in recv_user_addr; char recv_data[1024] = {0}; int recv_result; int addrsize; addrsize = sizeof(struct sockaddr_in); while(1) { memset(recv_data, '\0', sizeof(recv_data)); recv_result = recvfrom((int)sockfd, recv_data, sizeof(recv_data), 0, (struct sockaddr*)&recv_user_addr, &addrsize); if (recv_result <= 0) continue; printf("*From=>%s\n", recv_data); } } int msg_conf(char *BUFF){ char temp[6]; int i; for(i = 0; i < 6; i++){ temp[i] = *BUFF; BUFF++; } if(strcmp(temp, ".multi")==0) //1:1채팅 메시지 일경우 return 1; return 0; }
Forums:
gdb로 디버깅
gdb로 디버깅 해보세요.
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net
댓글 달기