채팅프로그램 구현중 오류

ch0nn0m의 이미지

리눅스 상에서 채팅프로그램을 구현했는데요...

컴파일까지는 에러없이 잘 진행이 되었는데...

실행을 하게 되면...

서버측에서 세그멘테이션 오류가 나오면서 끊겨버리네요...

어디가 잘못된것인지요??

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;
}
mithrandir의 이미지

gdb로 디버깅 해보세요.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.