소켓 프로그램 종료시에 발생하는 문제 질문 드립니다~

alsrud의 이미지

연결리스트에 저장된 정보를 가져와
입력, 삭제, 검색 등을 하고 종료하는
서버 - 클라이언트 구조의 소스를 작성했습니다.

소스가 장황항게 길긴하지만..
궁금한 것은 End부분 입니다.

처음 서버를 실행시켜놓고 클라이언트로 접속했다가
서버는 죽이지 않고 클라이언트만 종료한 후
같은 포트넘버로 클라이언트를 다시 connect 한 후 종료를 하면
*** Error in `./server1': double free or corruption (!prev): 0x0000000001cb2010 ***
중지됨 (core dumped)
이런 에러가 출력됩니다~~

서버는 죽지 않고 계속 돌아가야 한다고 생각해서
클라이언트만 종료되게 코드를 만들었는데,,
어떤 부분이 잘못되서 저런 메세지가 출력되는지 궁금합니다~
조언 부탁드립니다 :)

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> //인터넷 정의에 관한 헤더
#include <sys/types.h> //기본 시스템 자료 형식들, 시스템 콜에 필요한 상수 선언
#include <sys/socket.h> // 소켓 인터페이스, 소켓 시스템 콜 선언
 
#define PART_SIZE 25	//24까지 저장
#define NAME_SIZE 25
#define POS_SIZE 25
#define ID_SIZE 25
#define TEL_SIZE 25
#define PHO_SIZE 25
#define EXTEN_SIZE 25
#define EMAIL_SIZE 25
 
struct addr
{
	char part[PART_SIZE];
	char name[NAME_SIZE];
	char position[POS_SIZE];
	char id[ID_SIZE];
	char tel[TEL_SIZE];
	char phone[PHO_SIZE];
	char extension[EXTEN_SIZE];
	char email[EMAIL_SIZE];
	struct addr *next;
};
 
struct addr* load_addr(struct addr *head)
{
	struct addr *t = head;
	struct addr *p = (struct addr*)malloc(sizeof(struct addr));
	p->next = t;
	FILE *fp = fopen("address.csv", "r");
 
	char buf[500];
	char *temp = NULL;
	char *delim = ",\n";
	int i = 0;
 
	if(fp == NULL) { 
		printf("파일이 존재하지 않습니다.");
		return NULL;
	}
 
	while(fgets(buf, 500, fp) != NULL) {
		t->next = (struct addr*)malloc(sizeof(struct addr));
 
		temp = strtok(buf, delim);
		if(i++ == 0)
			strncpy(t->part, temp, sizeof(t->part));
		while(temp != NULL) {
			temp = strtok(NULL, delim);
			if(i == 1) {
				strncpy(t->name, temp, sizeof(t->name));
				i++;
			}else if(i == 2) {
				strncpy(t->position, temp, sizeof(t->position));
				i++;
			}else if(i == 3) {
				strncpy(t->id, temp, sizeof(t->id));
				i++;
			}else if(i == 4) {
				strncpy(t->tel, temp, sizeof(t->tel));
				i++;
			}else if(i == 5) {
				strncpy(t->phone, temp, sizeof(t->phone));
				i++;
			}else if(i == 6) {
				strncpy(t->extension, temp, sizeof(t->extension));
				i++;
			}else if(i == 7) {
				strncpy(t->email, temp, sizeof(t->email));
				i = 0;
			}
		}
		p = p->next;
		t = t->next;
		t->next = NULL;
	}
	free(p->next);
	p->next = NULL;
	fclose(fp);
	return t;
}
 
int delete_addr(char *buf, struct addr *head)
{
	struct addr *t = head;
	struct addr *prev = NULL;
 
	if(strcmp(buf, t->id) == 0) {
		printf("%s\n", t->id);
		head = t->next;
		free(t);
		return 1;
	}else {
		while(t != NULL) {
			if(strcmp(buf, t->id) == 0) {
				prev->next = t->next;
				free(t);
				break;
			}
			prev = t;
			t = t->next;
		}
		if(t == NULL) 
			return 0;
 
		return 1;
	}
}
 
void free_addr(struct addr *head)
{
	struct addr *t;
 
	while(head != NULL) {
		t = head;
		head = head->next;
		free(t);
	}
	t = NULL;
}
 
.
.
생략
.
.
int main(int argc, char **argv)
{
	int serv_sock; //새로운 소켓에 대한 파일 디스크립터를 받을 변수
	int client_sock; 
 
	struct sockaddr_in serv_addr;
	/*인터넷 전용 소켓 구조체
	 * sin_family: 주소체계
	 * sint_port: 16bit의 포트번호
	 * in_addr구조체: address family, sa_data
	 * sin_zefo: 전체 구조체 크기를 16Byte로 맞추기 위한 dummy변수
	 */
	struct sockaddr_in client_addr;
	int client_len;
 
	//FILE *fp;
	char buf[255];
	char line[255];
 
	char part[PART_SIZE];
	char name[NAME_SIZE];
	char position[POS_SIZE];
	char id[ID_SIZE];
	char tel[TEL_SIZE];
	char phone[PHO_SIZE];
	char extension[EXTEN_SIZE];
	char email[EMAIL_SIZE];
 
	struct addr* t;
	struct addr* head = (struct addr*)malloc(sizeof(struct addr));
 
	if(argc != 2)
	{
		printf("Usage: %s <port>\n", argv[0]);
		exit(1);
	}
 
	load_addr(head);
 
	client_len = sizeof(client_addr);
 
	/*
	if((fp = fopen("address.csv", "r")) == NULL) {
		printf("file open error");
		exit(1);
	}
	*/
 
	/*서버 소켓 생성
	 * socket함수
	 * int domain: 인터넷을 통해 통신할 지 같은 시스템 내에서 통신할지 결정
	 * int type: 데이터 전송 형태 지정
	 * int protocol: 통신에 있어 특정 프로토몰 사용을 지정하기 위한 변수
	 */
	serv_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(serv_sock == -1)
		error_handling("socket() error");
 
	/*주소 세팅*/
	memset(&serv_addr, 0, sizeof(serv_addr));
 
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);	//현재 설정된 자신의 IP주소를 사용
	serv_addr.sin_port = htons(atoi(argv[1]));	//htons:16비트HBO-> 16비트NBO
 
	/*소켓에 주소 할당
	 *클라이언트가 서버 프로그램의 특정 소i켓으로 접속하려면
	 서버는 자신의 소켓 번호와 클라이언트가 알고있는 자신의 IP주소, 포트번호를
	 미르 연결해 두어야 함
	 */
	if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		error_handling("bind() error");
 
	/*연결 요청 대기 상태로 진입*/
	if(listen(serv_sock, 1) == -1)
		error_handling("listen() error");
 
	printf("Waiting.....\n");
 
	while(1) {
		/*연결 요청 수락
		 *연결을 요청한 클라이언트와 송수신용 소켓을 생성하고 
		 connect가 들어올때까지 대기함*/
		client_sock = accept(serv_sock, (struct sockaddr*)&client_addr, (socklen_t*)&client_len);
		if(client_sock == -1) {
			error_handling("accept() error");
			break;
		}
 
		while(1) {
			//rewind(fp);	//파일의 읽기/쓰기 위치를 파일의 처음 위치로 초기화
			memset(buf, '0', 255);
 
			if(recv(client_sock, buf, 255, 0) <= 0) {
				error_handling("recv() error");
				close(client_sock);
				break;
			}
 
			if(strncmp(buf, "End", 3) == 0) {
				free_addr(head);
				printf("클라이언트 프로그램의 연결이 종료되었습니다.\n");
				close(client_sock);
 
				break;
			}
 
			while(1) {
				if(strncmp(buf, "Input", 5) == 0) {
					send(client_sock, "Input", sizeof("Input"), 0);
					//recv(client_sock, buf, 255, 0);
					//strcpy(part, buf);
					//printf("%s\n", part);	//지울거
					//send(client_sock, "이름: ", sizeof("이름: "), 0);
					trans_form(client_sock, buf, part, "이름: ");
					trans_form(client_sock, buf, name, "직급: ");
					trans_form(client_sock, buf, position, "아이디: ");
					trans_form(client_sock, buf, id, "휴대전화: ");
					trans_form(client_sock, buf, tel, "직통전화: ");
					trans_form(client_sock, buf, phone, "내선번호: ");
					trans_form(client_sock, buf, extension, "이메일: ");
 
					recv(client_sock, buf, 255, 0);
					strcpy(email, buf);
					printf("%s\n", email);
 
					input_addr(head, part, name, position, id, tel, phone, extension, email);
					break;
				}else if(strncmp(buf, "Modify", 6) == 0) {
					send(client_sock, "Modify", 6, 0);
					recv(client_sock, buf, 255, 0); //클라이언트로부터 id받음
					if((t = search_id(buf, head)) == NULL) {
						sprintf(line, "아이디 %s가 존재하지 않습니다.", buf);
						send(client_sock, line, 255, 0);
						break;
					}else {
						sprintf(line, "아이디 %s의 정보수정을 시작합니다.", buf);
						send(client_sock, line, 255, 0);
					}
 
					trans_form(client_sock, buf, t->part, "이름: ");
					//recv(client_sock, buf, 255, 0); //부서
					//strcpy(t->part, buf);
					//printf("%s\n", t->part);
					//send(client_sock, "이름: ", sizeof("이름: "), 0);
 
					trans_form(client_sock, buf, t->name, "직급: ");
					trans_form(client_sock, buf, t->position, "휴대전화: ");
					trans_form(client_sock, buf, t->tel, "직통전화: ");
					trans_form(client_sock, buf, t->phone, "내선번호: ");
					trans_form(client_sock, buf, t->extension, "이메일: ");
 
					recv(client_sock, buf, 255, 0);
					strcpy(t->email, buf);
					printf("%s\n", t->email);
 
					break;
				}else if(strncmp(buf, "Delete", 6) == 0) {
					send(client_sock, "Delete", 6, 0);
					recv(client_sock, buf, 255, 0);
					if(delete_addr(buf, head) == 1) {
						sprintf(line, "아이디 %s삭제에 성공했습니다.", buf);
						send(client_sock, line, 255, 0);
					}else {
						sprintf(line, "아이디 %s가 존재하지 않습니다.", buf);
						send(client_sock, line, 255, 0);
					}
					break;
				}else if(strncmp(buf, "Save", 4) == 0) {
					send(client_sock, "Save", 4, 0);
					save_addr(head);
					send(client_sock, "Success", sizeof("Success"), 0);
					break;
				}else if(strncmp(buf, "List", 4) == 0) {
					send(client_sock, "List", 4, 0);
 
					for(t = head; t != NULL; t= t->next) {
						sprint_addr(t, line);	//line에 t의 정보 출력
						send(client_sock, line, 255, 0);
					}
					if(t == NULL)
						send(client_sock, "Last", 4, 0);
					break;
				}else if(strncmp(buf, "Search" , 6) == 0) {
					send(client_sock, "Search", 6, 0);
					recv(client_sock, buf, 255, 0); //검색할 데이터 종류를 받음
 
					if(strcmp(buf, "Name") == 0) {
						send(client_sock, "이름: ", sizeof("이름: "), 0);
						recv(client_sock, buf, 255, 0); //이름을 받음
 
						for(t = head; t != NULL; t = t->next) {
							if(strcmp(buf, t->name) == 0){
								sprint_addr(t, line);
								send(client_sock, line, 255, 0);
							}
						}
						if(t == NULL)
							send(client_sock, "Last", 4, 0);
						//break;
					}else if(strcmp(buf, "Position") == 0) {
						send(client_sock, "직급: ", sizeof("직급: "), 0);
						recv(client_sock, buf, 255, 0); //직급받음
 
						for(t = head; t != NULL; t = t->next) {
							if(strcmp(buf, t->position) == 0) {
								sprint_addr(t, line);
								send(client_sock, line, 255, 0);
							}
						}
						if(t == NULL)
							send(client_sock, "Last", 4, 0);
					}else if(strcmp(buf, "Part") == 0) {
						send(client_sock, "부서: ", sizeof("부서: "), 0);
						recv(client_sock, buf, 255, 0); //부서 받음
 
						for(t=head; t != NULL; t = t->next) {
							if(strcmp(buf, t->part) == 0) {
								sprint_addr(t, line);
								send(client_sock, line, 255, 0);
							}
						}
						if(t == NULL)
							send(client_sock, "Last", 4, 0);
					}else if(strcmp(buf, "Tel") == 0) {
						send(client_sock, "휴대전화: ", sizeof("휴대전화: "), 0);
						recv(client_sock, buf, 255, 0); //부서 받음
						for(t = head; t != NULL; t = t->next) {
							if(strcmp(buf, t->tel) == 0){
								sprint_addr(t, line);
								send(client_sock, line, 255, 0);
							}
						}
						if(t == NULL)
							send(client_sock, "Last", 4, 0);
					}else if(strcmp(buf, "Email") == 0) {
						send(client_sock, "이메일: ", sizeof("이메일: "), 0);
						recv(client_sock, buf, 255, 0); //이메일 받음
						for(t = head; t != NULL; t = t->next) {
							if(strcmp(buf, t->email) == 0){
								sprint_addr(t, line);
								send(client_sock, line, 255, 0);
							}
						}
						if(t == NULL)
							send(client_sock, "Last", 4, 0);
					}
 
					break;
				}
			}
		}
	}
	close(client_sock);
 
	return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
 
void write_char(char buf_in[])
{
	fgets(buf_in, 255, stdin);
	buf_in[strlen(buf_in)-1] = '\0';
}
 
void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
 
void print_header()
{
	printf("부서       "
		"이름       "
		"직급       "
		"사원번호   "
		"휴대전화   "
		"직통번호   "
		"내선번호   "
		"이메일    \n ");
	printf("-----------------------------------------------------------------------------\n");
}
 
void select_menu(int client_sock, char buf_in[])
{
	puts("");
	printf("  OPTION\n");
	printf("----------\n");
	printf("Input\n");
	printf("Delete\n");
	printf("Search\n");
	printf("Modify\n");
	printf("Save\n");
	printf("List\n");
	printf("End\n\n");
 
	printf("Select option -> ");
	write_char(buf_in);
	send(client_sock, buf_in, 255, 0);
}
 
int main(int argc, char **argv)
{
	int client_sock, client_len;
	struct sockaddr_in client_addr;
 
	char buf_in[255];
	char buf_get[255];
 
	if(argc != 2)
	{
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
 
	/* 서버 접속을 위한 소켓 생성 */
	client_sock = socket(PF_INET, SOCK_STREAM, 0);
 
	if(client_sock == -1)
		error_handling("socket() error");
 
	memset(&client_addr, 0, sizeof(client_addr));
 
	client_addr.sin_family = AF_INET;
	client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	client_addr.sin_port = htons(atoi(argv[1]));
 
	client_len = sizeof(client_addr);
 
	/* 서버로 연결 요청 
	 * 3-way 핸드쉐이크가 성공하여 서버와 연결되는 것*/
	if(connect(client_sock, (struct sockaddr*) &client_addr, client_len) == -1)
		error_handling("connect() error");
 
	while(1) {
		select_menu(client_sock, buf_in);
 
		if(strncmp(buf_in, "End", 3) == 0)
		{
			close(client_sock);
			break;
		}
 
		while(1) {
			recv(client_sock, buf_get, 255, 0);
 
			puts("");
 
		/*데이터 송수신
		 *send함수: 소켓번호, 전송할 데이터가 저장된 버퍼, 버퍼크기, flag
		 *recv함수: 소켓번호, 수신된 데이터가 저장된 버퍼, 버퍼크기, flag*/
			if(strncmp(buf_get, "Input", 5) == 0) {
				printf("부서: ");
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0);
 
				recv(client_sock, buf_get, 255, 0); //이름:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0);  //이름입력한것
 
				recv(client_sock, buf_get, 255, 0);//직급:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0);  //직급입력한 것 보내고
 
				recv(client_sock, buf_get, 255, 0); //사원번호:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //사원번호
 
				recv(client_sock, buf_get, 255, 0);//휴대전화:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //휴대전화
 
				recv(client_sock, buf_get, 255, 0);//직통전화:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //직통전화
 
				recv(client_sock, buf_get, 255, 0);//내선번호:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //내선번호
 
				recv(client_sock, buf_get, 255, 0);//이메일:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //이메일
 
				break;
			}else if(strncmp(buf_get, "Save", 4) == 0) {
				recv(client_sock, buf_get, 255, 0);
				printf("%s\n", buf_get);
			}else if(strncmp(buf_get, "Modify", 6) == 0) {
				printf("수정할 아이디: ");
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //아이디 찍어서 보냄
 
				recv(client_sock, buf_get, 255, 0);
				printf("%s\n", buf_get); //정보 수정을 시작합니다 문구를 받음
				printf("부서: ");
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //부서 
 
				recv(client_sock, buf_get, 255, 0); //이름:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //이름
 
				recv(client_sock, buf_get, 255, 0); //직급:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //직급
 
				recv(client_sock, buf_get, 255, 0); //휴대전화:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //휴대전화
 
				recv(client_sock, buf_get, 255, 0); //직통전화:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //직통전화
 
				recv(client_sock, buf_get, 255, 0); //내선번호:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //내선번호
 
				recv(client_sock, buf_get, 255, 0); //이메일:
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //이메일
 
				break;
			}else if(strncmp(buf_get, "Delete", 6) == 0) {
				printf("삭제할 아이디: ");
				write_char(buf_in);
				puts("");
				send(client_sock, buf_in, 255, 0);
 
				recv(client_sock, buf_get, 255, 0);
				printf("%s\n", buf_get);
			}else if(strncmp(buf_get, "List", 4) == 0) {
				print_header();
 
				while(1) {
					recv(client_sock, buf_get, 255, 0);
					if(strncmp(buf_get, "Last", 4) == 0) {
						break;
					}
					printf("%s\n", buf_get);
				}
				//puts("=====================");
				break;
			}else if(strncmp(buf_get, "Search", 6) == 0) {
				printf("검색할 데이터의 종류를 입력하세요.\n\n");
				printf("Name || Part || Position || Tel || Email -> ");
				write_char(buf_in); 
				send(client_sock, buf_in, 255, 0); //데이터 종류를 보냄
 
				recv(client_sock, buf_get, 255, 0); //데이터: 을 받음
				puts("");
				printf("%s", buf_get);
				write_char(buf_in);
				send(client_sock, buf_in, 255, 0); //데이터 보냄
				puts("");
				print_header();
 
				while(1) {
					recv(client_sock, buf_get, 255, 0); //검색된 정보를 받음
					if(strncmp(buf_get, "Last", 4) == 0)
						break;
					printf("%s\n", buf_get);
				}
				break;
			}
			break;
		}
	}
	close(client_sock);
 
	return 0;
}
jick의 이미지

1. 일단 메모리 에러는 valgrind를 써보시면 잡을 수 있을 확률이 매우 높습니다.

2. 그리고 프로그램 전체에 send와 recv를 쓰면서 전혀 리턴값을 체크하지 않고 있는데, send와 recv는 요청한 길이만큼 데이터를 주고받는다는 보장이 절대 안되는 함수이기 때문에, 리턴값을 확인하지 않는 것은 기본적으로 잘못된 코드라고 생각하시면 됩니다.

alsrud의 이미지

조언 감사드립니다~
그렇다면 write와 read함수는 요청한 길이만큼 데이터를 주고받는다는 보장이 있나요????

jick의 이미지

Socket을 이용할 때는 무슨 함수를 쓰든 요청한 길이만큼 읽고 쓴다는 보장이 되지 않습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.