[해결] 자바 소켓 프로그래밍 질문입니다.

GunSmoke의 이미지

지난번 질문한 것처럼 윤경구씨의 마이크로소프트웨어 기사로 자바를 공부하고 있습니다.

애플릿으로 만든 클라이언트에서 서버에 접속하는 프로그램 예제입니다.

먼저 소스 코드부터 살펴보시죠.

import java.io.*;
import java.net.*;
import java.util.*;
 
class BroadcastServer {
	final static int PORT = 8001;
	ServerSocket server = null;
	Vector clients = new Vector();
 
	class Client extends Thread {
		Socket socket = null;
		BufferedReader in = null;
		PrintWriter out = null;
 
		Client (Socket socket) throws IOException {
			this.socket = socket;
			this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			this.out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
			start();
		}
 
		public void run() {
			try {
				while (true) {
					String line = in.readLine();
					if (line == null) {
						close();
						break;
					}
 
					System.out.println(getName()+':'+line);
					BroadcastServer.this.broadcast(line);
				}
			} catch (IOException ie) {
				ie.printStackTrace();
				close();
			}
		}
 
		public void close() {
			synchronized (BroadcastServer.this) {
				try {
					if (in != null)
						in.close();
				} catch (Exception e) {}
				if (out != null)
					out.close();
				try {
					if (socket != null)
						socket.close();
				} catch (Exception e) {}
				socket = null;
			}
		}
	}
 
	public BroadcastServer() {
		try {
			server = new ServerSocket(PORT);
		} catch (IOException ie) {
			ie.printStackTrace();
			System.exit(1);
		}
		while (true) {
			try {
				Socket socket = server.accept();
				Client client = new Client(socket);
				synchronized (this) {
					clients.addElement(client);
				}
			} catch (IOException ie) {
				ie.printStackTrace();
			}
		}
	}
 
 
	public static void main(String[] args) {
		new BroadcastServer();
	}
 
	public synchronized void broadcast(String message) {
		for (Enumeration enuma = clients.elements(); enuma.hasMoreElements(); ) {
			Client client = (Client) enuma.nextElement();
			if (client == null)
				continue;
			if (client.socket == null) {
				clients.removeElement(client);
				continue;
			}
			client.out.println(message);
			if (client.out.checkError()) {
				System.err.println("Error while sending message.");
				client.close();
			}
		}
	}
}

다음은 클라이언트 역할을 수행하는 애플릿 코드입니다.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.io.*;
 
public class BroadcastApplet extends Applet implements ActionListener {
	int port;
	String host;
	TextField inputField;
	TextArea outputArea;
	Socket socket;
	BufferedReader in;
	PrintWriter out;
	Thread readingThread;
 
	public void init() {
		inputField = new TextField();
		outputArea = new TextArea();
		setLayout(new BorderLayout());
		add(inputField, "North");
		add(outputArea, "Center");
		String param = getParameter("PORT");
		if (param == null)
			port = 8001;
		else
			port = Integer.parseInt(param);
		host = getParameter("HOST");
		if (host == null)
			host = getCodeBase().getHost();
		inputField.addActionListener(this);
		doLayout();
	}
 
	public void start() {
		if (socket == null)
			connect();
		readingThread = new Thread() {
			public void run() {
				if (socket == null)
					return;
				while (socket != null && readingThread == Thread.currentThread()) {
					try {
						String line = in.readLine();
						appendLine(line);
					} catch (IOException ie) {
						ie.printStackTrace();
						closeSocket();
					}
				}
			}
		};
		readingThread.start();
	}
 
	public void stop() {
		readingThread = null;
		closeSocket();
	}
 
	public void actionPerformed(ActionEvent ae) {
		if (ae.getSource() instanceof TextField) {
			String line = inputField.getText();
			inputField.setText("");
			if (socket == null)
				return;
			try {
				out.println(line);
				if (out.checkError())
					throw new IOException("Print error");
			} catch (IOException ie) { 
				closeSocket();
			}
		}
	}
 
	public void connect() {
		try {
			socket = new Socket(host, port);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
			appendLine("Connected...");
		} catch (UnknownHostException uhe) {
			appendLine("Unknown host");
		} catch (IOException ie) {
			ie.printStackTrace();
		}
	}
 
	public synchronized void closeSocket() {
		try {
			if (in != null)
				in.close();
		} catch (Exception e) {}
		if (out != null)
			out.close();
		try {
			if (socket != null)
				socket.close();
		} catch (Exception e) {
			socket = null;
		}
	}
 
	public synchronized void appendLine(String message) {
		outputArea.append(message+"\n");
	}
}

서버를 실행하고 애플릿을 실행하면 다음과 같이 접속에 실패했다는 오류가 발생합니다. 무엇이 문제일까요?

대충 덤프된 내용을 살펴보니 접속에 실패하는 이유가 소켓의 접근권한과 관련된 것이 아닌가 합니다. 이 자료가 99년도에 나온 것이니 만큼 지금과 다른 내용이 있지 않나 생각합니다만 정확한 이유를 알고 싶습니다.

java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:8001 connect,resolve)
	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkConnect(Unknown Source)
	at sun.plugin2.applet.Applet2SecurityManager.checkConnect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at java.net.Socket.connect(Unknown Source)
	at java.net.Socket.<init>(Unknown Source)
	at java.net.Socket.<init>(Unknown Source)
	at BroadcastApplet.connect(BroadcastApplet.java:99)
	at BroadcastApplet.start(BroadcastApplet.java:54)
	at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
예외: java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:8001 connect,resolve)

hansolo의 이미지

구글에서 찾으시면 우르르 나옵니다.

http://forums.devx.com/archive/index.php/t-158395.html

이게 도움이 될거 같네요.

GunSmoke의 이미지

글쎄요.
적어도 첨부해주신 글타래는 도움이 되지 않네요.
밑에 달린 답글들이 모조리 '나도 같은 문제를 겪고 있어요. 누구 해결하신 분?' 이런 내용이라...ㅡ,.ㅡ;;

大逆戰

大逆戰

hansolo의 이미지

예 저도 훌러덩 읽다보니 그런 내용이네요;; 혼란을 일으켜서 죄송합니다.

수정해서 다른 링크 걸었습니다.

그리고 애플릿은 기본적으로 로컬자원에 접근하지 못하도록 되어 있습니다. 아마 보안정책을 편집하거나 signed applet 로 만들어야 문제가 해결되지 싶은데요..

GunSmoke의 이미지

답변 감사합니다.

원인은 알겠는데 정확한 해결책은 좀 더 찾아봐야겠군요.
자바를 처음 배우는 입장이라 어려운 점이 한두개가 아니네요.

보안 정책을 편집하는 방법도 생소하고
signed applet으로 만드는 것도 알지 못합니다.
(적어도 제가 보고 있는 책에는 그런 설명이 나와있지 않은터라...)

책을 보고 나서 홈페이지에 있는 튜토리얼도 새로 봐야할 것 같네요.

大逆戰

大逆戰

bookgekgom의 이미지

애플릿의 개념을 아셔야합니다.

애플릿은 다른 서버로의 접속이 불가능하도록 설정되어 있습니다.

만약 애플릿을 통하여 다른 서버로 접속을 가능하게 하려면

인증키를 받아야합니다.

인증키를 만드는 방법에는 두가지가 있는데

1. sun 사에서 사온다 (비쌈...일년에 얼마더라?)

2. 직접 인증키를 만들어서 애플릿 jar 혹은 class 에 인증키를 씌우면 됩니다.

이것을 적용후 애플릿을 실행하면

"누구 누구의 애플릿이 실행될것입니다. 신용합니까?" 라고 뜨는것을 볼수있습니다.

더욱 자세한것은 구글에 쳐보시구요.

메신저로 파일을 보네드릴수도 있습니다만...

bookgekgom@hotmail.com

제가 접속 안할때가 있음...

---------------------------------------------------------------------------------------------------------------
루비 온 레일즈로 만들고 있는 홈페이지 입니다.

http://jihwankim.co.nr

여러 프로그램 소스들이 있습니다.

필요하신분은 받아가세요.

endofhope의 이미지


Java의 보안 모델에 대해 알고 싶으신게 아닌 것이라 생각하고 security check 만 피해가시려면

grant {
      permission java.security.AllPermission;
};

를 내용으로 가지는 .java.policy 파일을 홈 디렉토리에 넣으시면 됩니다.

테스트가 끝난 후에는 .java.policy 를 되돌려 놓으십시오 (만드셨다면 지우십시오) - 일종의 security hole 이 됩니다.

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

GunSmoke의 이미지

윈도우 환경에서는 .java.policy 파일을 어디에 생성해야하나요?
어떤 문서에서는 C:\Windows 디렉토리에 생성하라고 하고,
어떤 문서에서는 \java\jre6\lib\security에 생성하라고 하는데...

두 군데 다 해봤는데 계속 같은 결과만 나오네요ㅠㅠ

大逆戰

大逆戰

endofhope의 이미지

홈 디렉토리에 놓으시면 해당 사용자에 적용됩니다.
cmd 로 콘솔 창을 띄울때 나오는 디렉토리에 넣으시면 될 듯 합니다.

%jre_home%/lib/security 에 놓으면 해당 jre 를 사용하는 모든 사용자에 대해 적용됩니다.
%jre_home% 은 실행시키시는 jre 의 위치를 의미합니다.

아마도 jre_home 밑에 놓았을 때 안 되었던 것은 아마 코드를 구동시킨 jre 가 달랐던 것 같네요.

(제 window 머신이 수리중이라 테스트해 보진 않았습니다 ^^;; )

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

GunSmoke의 이미지

endofhope님 여러번 도움 주셔서 감사합니다.
하지만
jre_home 디렉토리의 경로를 지정하고(JAVA_HOME 경로 지정하는 것고 동일하게 시스템에 설치된 JRE 디렉토리를 지정했습니다. 제 컴퓨터에서는 C:\Program Files\Java\jre6입니다.) 애플릿을 실행해봤지만 역시 같은 결과네요.

JRE 대해서 조금이라도 알고 있다면 도움이 되겠지만 그러지 못해 혼자만 끙끙대고 있네요.

大逆戰

大逆戰

endofhope의 이미지


윈도 머신에서 테스트 해 보니 굳이 .java.policy 없이도 동작합니다 (약간 어이 없는 결과입니다만 ^^)

저는

C:\tmp\java_test>java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

를 썼으며 테스트한 파일을 묶어서 올려 드립니다.

서버를 띄우기 위해

java BroadcastServer

이후 appletviewr 를 사용하여

appletviewer applet.html

로 실행했습니다.

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

댓글 첨부 파일: 
첨부파일 크기
Package icon java_test.zip10.18 KB

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

GunSmoke의 이미지

보내주신 파일로 테스트한 결과입니다.
제 컴퓨터에서는 역시 동일한 결과가 출력되네요.

大逆戰

댓글 첨부 파일: 
첨부파일 크기
Image icon error.JPG0바이트

大逆戰

GunSmoke의 이미지

혹시 코드에 문제가 있는 것은 아닐까요?

大逆戰

大逆戰

bookgekgom의 이미지

파일은 원래 권한을 모두 넘기도록 위처럼 설정되 있구요....

애플릿을 브라우저로 통해 <= 애플릿 뷰어가 아닙니다...

제 3 자의 서버에 접속을 할때는 반드시 인증키를 씌워줘야 합니다....

저도 애플릿으로 온라인 게임 만들면서 격어 봐서 알아요...

키 만드시고 인증 덮어 씌우면 잘 될겁니다...

---------------------------------------------------------------------------------------------------------------
루비 온 레일즈로 만들고 있는 홈페이지 입니다.

http://jihwankim.co.nr

여러 프로그램 소스들이 있습니다.

필요하신분은 받아가세요.

endofhope의 이미지

Signed Applet 에 대해선 경험이 없어서 이번 기회에 만들어 보았습니다.

서버를 띄우신 후 applet.html 을 (appletviewer 가 아니라) 브라우저에서 열어 보시면 동작할 듯 싶습니다.

급조하기 위해 참조한 url 은 여기 http://shinnara.tistory.com/tag/signed%20applet 입니다.

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

댓글 첨부 파일: 
첨부파일 크기
Package icon java_test.zip13.31 KB

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

GunSmoke의 이미지

드디어 됩니다!!
자바 처음 배우면서 난관이 많네요 ㅠㅠ

도움 주신 endofhope님(ID와 달리 endofhope님만이 제 유일한 희망이었습니다.), bookgekgom님, hansolo님께 감사드립니다.

ps1. 자바애플릿은 요즘에 잘 사용되지 않나요? 오래전에 출판된 책들 중에는 자바애플릿을 다룬 예제가 꽤 많은데 head first java에서는 대부분의 예제가 자바 애플리케이션으로 작성되었더군요. 혹시 자바애플릿이 잘 사용되지 않는 실태를 반영한 것은 아닌지 궁금합니다.

ps2. 자바는 왜 이렇게 배워야할 분야가 많고 복잡한가요.
j2me, j2ee, 분산객체(rmi, corba), jsp, 서블릿, 자바스크립트, 자바빈즈, 패턴, uml, jdbc 너무너무 복잡합니다. ANT, 이클립스니 jbuilder니 visual cafe, ajax니 자바와 직간접적으로 연관된 것들이 왜 이렇게 많은지... 자바 입문서를 보고 나니 오히려 마치 사막에 떨어진채 길을 잃어버린 느낌입니다... 어디 알기 쉽게 정리되어 있는 것 없을까요?

大逆戰

댓글 첨부 파일: 
첨부파일 크기
Image icon ok.JPG66.37 KB

大逆戰

bookgekgom의 이미지

저도 옛날에는 애플릿으로 게임도 짜고 여러가지 만들었는데 일단

키를 인증해 줘야 하는불편함도 있고 -_)

한국 친구들이 자바를 안까는 경향도있고

로딩도 느리고...

그런 여러 이유로 그만뒀습니다.

전 자바팬이지만 인정할껀 인정해야죠.

애플릿은 죽었습니다...

하.지.만

그렇다고 자바의 애플릿을 완전히 포기한건 아닙니다 후후

이번에 새로나온 JavaFX 를 살펴 주세요.

애플릿 2 라고 할수도 있는데 (정확히는 아니지만...)

플래쉬도 지원하고 아주 좋답니다 <- 중요한점

JavaFX 는 스크립트 언어임...

만들기 아주 쉬워요.

그런데 JavaFX 애플릿도 제 3자 서버를 사용할때는 인증을 씌워야함...

ㅠㅠ

으허허헝

그리고 자바와 관련된 여러 기술들이 복잡하다고 하는데...

결국 그것들은 자바SE 만 튼튼히 알고 있으면 그리 어려운것도 아닙니다.

자바는 자바SE 만 재대로 알면 나머지는 저절로 습득이 된다고 생각하는데...

으해해햏

---------------------------------------------------------------------------------------------------------------
루비 온 레일즈로 만들고 있는 홈페이지 입니다.

http://jihwankim.co.nr

여러 프로그램 소스들이 있습니다.

필요하신분은 받아가세요.

GunSmoke의 이미지

오래된 입문서에서는 애플릿 예제가 빠지지 않는데 비교적 최근에 나온 HeadFirstJava에서는 애플릿이 보이질 않아 혹시나 했습니다. 역시 애플릿이 사양길로 가버렸었군요.
자바 Standard Edition, 자바의 기초에 대해 더 열심히 공부하라는 말씀으로 알겠습니다. 감사합니다.

大逆戰

大逆戰

endofhope의 이미지


축하드립니다.
처음에는 복잡해 보여도 이것만 지나 보내시면 쉬워지리라 생각합니다 :)

애플릿은 JRE 가 예전에는 다운 받기에 버거울 정도로 컸고 (모뎀 사용자에게 20-30메가씩 다운 받아라고 강제하기가 힘들었습나다)
플랫폼 독립적인 UI 를 고수하다 보니 거의 모든 플랫폼에서 예쁘지 않았습니다
이건 애플릿 만의 문제는 아닙니다 "한번 작성하면 어디든 실행된다. (하지만 UI 는 가장 못난 플랫폼에 종속된다)" 라고나 할까요?
() 안은 그냥 제가 붙인 말입니다 ;)
훨씬 작은 실행 엔진에 예쁜 모습을 가진 플래시가 퍼지자 애플릿은 힘을 잃었습니다.

네 사실 복잡합니다.
하지만 target 을 하나 잡으시면 (핸드폰, 카드 등의 임베디드, 은행 보험 등의 Business System, WAS 개발, Web Programming 등등)
무엇부터 해야 되겠다 라는 감을 잡으실 수 있으리라 생각합니다.
뭐든 사람이 만든 것이니 꾸준하게 하시면 끝을 보실 수 있으리라 생각합니다. (저도 그렇게 믿고 계속하고 있습니다 ^^)

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인

GunSmoke의 이미지

endofhope님 다시 한번 감사드립니다.

자바 애플릿이 사양길에 접어든 원인은 플래시 때문이었군요.

php나 jsp 등으로 데이터베이스와 대화할 수 있는 인터페이스 역할을 하던 것이 자바 애플릿에서 플래시로 넘어간 추세라...

자바를 처음 시작하는 제게 해주시는 고무적인 말씀도 감사합니다.

大逆戰

大逆戰

댓글 달기

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