자바야놀자 - 활용편 발행일 지은이 발행처 2016 년 4 월 16 일 허진경 퍼플 출판등록제 호 (2012 년 09 월 07 일 ) 주소 서울시종로구종로 1 가 1 번지 대표전화 홈페이지 c

Similar documents
Microsoft PowerPoint - 04-UDP Programming.ppt

제11장 프로세스와 쓰레드

자바-11장N'1-502

<4D F736F F F696E74202D20C1A63235C0E520B3D7C6AEBFF6C5A920C7C1B7CEB1D7B7A1B9D628B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - Supplement-03-TCP Programming.ppt [호환 모드]

Microsoft PowerPoint - 03-TCP Programming.ppt

PowerPoint 프레젠테이션

PowerPoint Presentation

PowerPoint Presentation

9장.key

Cluster management software

Microsoft PowerPoint - 06-Chapter09-Event.ppt

Chap12

쉽게 풀어쓴 C 프로그래밍

C++ Programming

JAVA PROGRAMMING 실습 09. 예외처리

슬라이드 1

PowerPoint Presentation

13-Java Network Programming

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

PowerPoint Presentation

PowerPoint Presentation

제8장 자바 GUI 프로그래밍 II

. 스레드 (Thread) 란? 스레드를설명하기전에이글에서언급되는용어들에대하여알아보도록하겠습니다. - 응용프로그램 ( Application ) 사용자에게특정서비스를제공할목적으로구현된응용프로그램을말합니다. - 컴포넌트 ( component ) 어플리케이션을구성하는기능별요

02 C h a p t e r Java

PowerPoint 프레젠테이션

Java ...

<4D F736F F F696E74202D20C1A63139C0E520B9E8C4A120B0FCB8AEC0DA28B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

JMF3_심빈구.PDF

JAVA PROGRAMMING 실습 08.다형성

Microsoft PowerPoint - Java7.pptx

Windows 8에서 BioStar 1 설치하기

쉽게 풀어쓴 C 프로그래밊

Microsoft PowerPoint - ÀÚ¹Ù08Àå-1.ppt

rmi_박준용_final.PDF

스레드의우선순위 우선순위설정메소드 : void setpriority(int newpriority) newpriority 에설정할수있는등급 : 1( 가장낮은우선순위 ) 부터 10( 가장높은우선순위 ) 가장높은우선순위 : MAX_PRIORITY, 보통우선순위 : NORM_

PowerPoint 프레젠테이션

gnu-lee-oop-kor-lec10-1-chap10

PowerPoint Presentation

PowerPoint Presentation

(Microsoft PowerPoint - LZVNQBAJWGTC.ppt [\310\243\310\257 \270\360\265\345])

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

PowerPoint Presentation

(Microsoft PowerPoint - java1-lecture11.ppt [\310\243\310\257 \270\360\265\345])

PowerPoint 프레젠테이션

<4D F736F F F696E74202D20C1A63234C0E520C0D4C3E2B7C228B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - CSharp-10-예외처리

Network Programming

Spring Boot/JDBC JdbcTemplate/CRUD 예제

q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2

비긴쿡-자바 00앞부속

다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");

<4D F736F F F696E74202D E20B3D7C6AEBFF6C5A920C7C1B7CEB1D7B7A1B9D62E >

스레드를적용하지않은결과와스레드를적용한결과의비교 1) 두개의작업을스레드를사용하지않고수행한예 ) : 순차작업 class ThreadTest2 { System.out.print("-");// 화면에 - 를출력하는작업 System.out.print(" ");// 화면에 를출력

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

오버라이딩 (Overriding)

슬라이드 1

<4D F736F F F696E74202D20B3D7C6AEBFF6C5A9C7C1B7CEB1D7B7A1B9D65F FBCD2C4CF5FC3A4C6C35FBFA1C4DA2E BC8A3C8A

자바GUI실전프로그래밍2_장대원.PDF

PowerPoint Presentation

class InetAddress3{ public static void main(string[] args) throws Exception{ String url = null ; Scanner reader = new Scanner(System.in); System.out.p

Microsoft Word - ntasFrameBuilderInstallGuide2.5.doc

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

학습목표 네트워크개요 TCP PORT URL/InetAddress Socket/TCP 을이용한네트워크 2

The Pocket Guide to TCP/IP Sockets: C Version

gnu-lee-oop-kor-lec06-3-chap7

Java Programing Environment

PowerPoint Presentation

Microsoft PowerPoint - EEL2 Lecture10 -Swing and Event Handling.pptx

ISP and CodeVisionAVR C Compiler.hwp

(Microsoft PowerPoint - java2-lecture6.ppt [\310\243\310\257 \270\360\265\345])

JVM 메모리구조

Microsoft PowerPoint - lec12 [호환 모드]

11장.key

(Microsoft PowerPoint - AUTCHEYREGRG.ppt [\310\243\310\257 \270\360\265\345])

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

2009년 상반기 사업계획

Microsoft PowerPoint - java2-lecture6.ppt [호환 모드]

Microsoft PowerPoint - Lecture_Note_5.ppt [Compatibility Mode]

TEST BANK & SOLUTION

쉽게 풀어쓴 C 프로그래밍

Microsoft PowerPoint - RMI.ppt

Microsoft Word - src.doc

Microsoft PowerPoint - 14주차 강의자료

PowerPoint 프레젠테이션

Connection 8 22 UniSQLConnection / / 9 3 UniSQL OID SET

PowerPoint Presentation

05-class.key

쉽게 풀어쓴 C 프로그래밍

12-file.key

10장.key

PowerPoint 프레젠테이션

파일로입출력하기II - 파일출력클래스중에는데이터를일정한형태로출력하는기능을가지고있다. - PrintWriter와 PrintStream을사용해서원하는형태로출력할수있다. - PrintStream은구버전으로가능하면 PrintWriter 클래스를사용한다. PrintWriter

게시판 스팸 실시간 차단 시스템

제1장 Unix란 무엇인가?

API STORE 키발급및 API 사용가이드 Document Information 문서명 : API STORE 언어별 Client 사용가이드작성자 : 작성일 : 업무영역 : 버전 : 1 st Draft. 서브시스템 : 문서번호 : 단계 : Docum

Windows Server 2012

Cluster management software

The Pocket Guide to TCP/IP Sockets: C Version

Transcription:

자바야놀자 - 활용편

자바야놀자 - 활용편 발행일 지은이 발행처 2016 년 4 월 16 일 허진경 퍼플 출판등록제 300-2012-167 호 (2012 년 09 월 07 일 ) 주소 서울시종로구종로 1 가 1 번지 대표전화 1544-1900 홈페이지 www.kyobobook.co.kr c 허진경 2016 본책내용의전부또는일부를재사용하려면 반드시저작권자의동의를받으셔야합니다.

목차 목 차 1. 스레드프로그래밍 1 1.1. 스레드 (Thread) 실행 2 1.1.1. 스레드와 run() 메서드 2 1.1.2. 스레드상태 6 1.2. 스레드 (Thread) 클래스의메서드 12 1.2.1. getpriority() 와 setpriority() 13 1.2.2. sleep() 14 1.2.3. join() 15 1.2.4. yield() 16 1.3. 공유데이터접근 18 1.3.1. 공유데이터의문제점 18 1.3.2. 공유데이터문제점의해결 (synchronized) 22 1.3.3. wait() 와 notify() 25 1.4. 요점정리 33 2. 네트워크프로그래밍 35 2.1. TCP 네트워크프로그램 36 2.1.1. TCP 서버 37 2.1.2. TCP 클라이언트 39 2.1.3. 간단한채팅 40 2.2. UDP 네트워크프로그램 44 2.2.1. DatagramPacket 44 2.2.2. DatagramSocket 44 2.3. TCP 채팅프로그램 Ⅰ 48 2.3.1. ChatServer.java 49 2.3.2. ChatClient.java 53 2.4. TCP 채팅프로그램 Ⅱ 56

Java 자바야놀자 - 활용편 2.5. TCP 파일서버프로그램 66 2.6. 요점정리 69 3. JDBC 프로그래밍 70 3.1. 데이터베이스개요 71 3.1.1. 데이터베이스용어 71 3.2. Oracle 72 3.2.1. Oracle Database 11g Express Edition 72 3.2.2. HR 스키마활성화 78 3.2.3. SQL Developer 80 3.3. MariaDB 85 3.3.1. MariaDB 85 3.4. SQL 89 3.4.1. SQL 문법의개요 89 3.4.2. 데이터타입 (Oracle과 MySQL) 92 3.4.3. Oracle 기본데이터타입 92 3.4.4. MySQL 기본데이터타입 92 3.4.5. JDBC 환경설정 93 3.5. JDBC API 96 3.5.1. JDBC API 96 3.5.2. JDBC 드라이버타입 97 3.6. JDBC 프로그램구조 99 3.6.1. 드라이버로딩 (Driver Loading) 99 3.6.2. Connection 객체생성 100 3.6.3. Statement 객체생성 101 3.6.4. Statement 객체의메서드를이용한 SQL 실행 101 3.6.5. 질의결과를얻기위한 SELECT문 102 3.6.6. 데이터추출 102 3.7. 실전 JDBC API 103 3.7.1. PreparedStatement 103

목차 3.7.2. CallableStatement 104 3.7.3. ResultSetMetaData 106 3.7.4. DatabaseMetaData 107 3.8. 리소스관리와데이터객체 109 3.9. 요점정리 113 4. 윈도우프로그래밍 115 4.1. AWT 컴포넌트 116 4.1.1. 기본컴포넌트 119 4.1.2. 텍스트컴포넌트 134 4.1.3. 컨테이너컴포넌트 138 4.1.4. 레이아웃관리자 151 4.1.5. FlowLayout 152 4.1.6. BorderLayout 154 4.1.7. GridLayout 156 4.1.8. CardLayout 158 4.1.9. 복합레이아웃 (Complex Layout) 162 4.1.10. 레이아웃관리자를사용하지않는레이아웃 164 4.2. 메뉴 (Menu) 168 4.2.1. MenuComponent 168 4.2.2. MenuBar 169 4.2.3. Menu 169 4.2.4. MenuItem 171 4.2.5. CheckboxMenuItem 173 4.2.6. 팝업메뉴 (PopupMenu) 174 4.2.7. MenuShortcut 177 4.3. 색상 (Color) 과글꼴 (Font) 180 4.3.1. 색상 (Color) 180 4.3.2. 글꼴 (Font) 181 4.4. 요점정리 183 5. 이벤트프로그래밍 185

Java 자바야놀자 - 활용편 5.1. 이벤트와이벤트리스너 186 5.1.1. 이벤트모델 186 5.1.2. 이벤트클래스계층구조 187 5.1.3. 저수준이벤트와고수준이벤트 188 5.1.4. EventListener 189 5.1.5. 리스너인터페이스와메서드 193 5.2. 이벤트프로그래밍 196 5.2.1. 이벤트발생클래스와동일클래스에핸들러구현 196 5.2.2. 별도의클래스로핸들러구현 197 5.2.3. Inner 클래스로핸들러구현 198 5.2.4. Local 클래스로핸들러구현 199 5.2.5. 익명클래스로핸들러구현 200 5.3. Adapter 클래스 202 5.3.1. 이벤트발생클래스와동일클래스에핸들러구현 202 5.3.2. 별도의클래스로핸들러구현 203 5.3.3. Inner 클래스로핸들러구현 204 5.3.4. Local 클래스로핸들러구현 205 5.3.5. 익명클래스로핸들러구현 205 5.4. 주요이벤트클래스 207 5.4.1. ActionEvent 207 5.4.2. AdjustmentEvent 209 5.4.3. ComponentEvent 210 5.4.4. ContainerEvent 211 5.4.5. FocusEvent 213 5.4.6. KeyEvent 215 5.4.7. MouseEvent 218 5.4.8. ItemEvent 222 5.4.9. TextEvent 224 5.4.10. WindowEvent 225 5.4.11. MouseWheelEvent 230 5.5. 요점정리 233 6. Swing 235

목차 6.1. 스윙의기본적인이해 236 6.1.1. JFC 236 6.1.2. 룩앤필 (Look and Feel) 236 6.2. 스윙컴포넌트 238 6.2.1. JFrame 238 6.2.2. JPanel 241 6.2.3. JButton 241 6.2.4. 아이콘 242 6.2.5. JLabel 244 6.2.6. JCheckBox 245 6.2.7. JRadioButton 247 6.2.8. JToggleButton 248 6.2.9. JScrollPane 250 6.2.10. JTextComponents 251 6.2.11. JScrollBar 256 6.2.12. JSlider 257 6.2.13. JComboBox 260 6.2.14. JList 262 6.2.15. Borders 263 6.2.16. JApplet 267 6.2.17. 툴팁 (tool tip) 268 6.2.18. JTabbedPane 269 6.2.19. JSplitPane 271 6.3. 메뉴와도구상자컴포넌트 273 6.3.1. 주메뉴 273 6.3.2. 팝업메뉴 276 6.3.3. JToolBar 277 6.4. 스윙의레이아웃관리자 279 6.4.1. BoxLayout 279 6.4.2. ScrollPaneLayout 281 6.4.3. ViewportLayout 281 7. 프로그래밍워크샵 283 7.1. Stock Market 284

Java 자바야놀자 - 활용편 7.1.1. Stock Market 개요 284 7.1.2. Eclipse에서프로젝트생성방법 285 7.1.3. SotckMarket 데이터베이스테이블 286 7.2. 사용된패턴들 288 7.2.1. Design Pattern에대한정의 288 7.2.2. MVC(Model-View-Controller) 패턴 288 7.2.3. Command 패턴 (Behavioral Patterns) 288 7.2.4. Data Access Object(DAO) 패턴 289 7.2.5. Value Object(VO) 패턴 290 7.3. 2-Tier application 291 7.3.1. 2-Tier 애플리케이션 291 7.3.2. 이미작성되거나배치 (deploy) 되어있어야하는파일들 292 7.3.3. 작성해야하는파일들 292 7.3.4. [Java응용프로그램-TestDatabase] 실행 292 7.3.5. Value Object 클래스 293 7.3.6. 예외클래스 296 7.3.7. Database 애플리케이션메인 297 7.4. GUI 만들기 304 7.5. Connection Pool 317 7.5.1. 이미작성되거나배치 (deploy) 되어있어야하는파일들 317 7.5.2. 작성해야하는파일들 317 7.5.3. broker.database.connpool.connectionpool.java 318 7.5.4. 예외클래스 332 7.5.5. Database.java 수정 333 7.6. 3-Tier Application 334 7.6.1. 이미작성되거나배치 (deploy) 되어있어야하는파일들 334 7.6.2. 작성해야하는파일들 335 7.6.3. broker.result.java 336 7.6.4. broker.command.java 337 7.6.5. broker.protocol.java 338 7.6.6. broker.jurythread.java 343 7.6.7. ProtocolHandler.java 347 7.6.8. broker.broker.java - 수정 349

목차

이책을보기전에자바에대한개념을익히셔야합니다. 자바야놀자 ( 기본편 ) 에서는자바의주 요개념들을더쉽고정확하게배울수있습니다. 자바야놀자 ( 기본편 ) 은인터넷교보문고 1) 를 통해구매하실수있습니다. 이책의소스코드는 http://javaspecialist.co.kr/board/629 에서다운로드받을수있습니다. 1) http://pod.kyobobook.co.kr/newpodbooklist/newpodbookdetailview.ink?barcode=1400000280836

1. 스레드프로그래밍 이장에서는멀티스레드프로그래밍에대해설명하기로하겠습니다. 스레드는프로그램내에서실행되는흐름의단위입니다. 스레드를이용하면동시에여러개작업을수행시킬수있습니다. 이장에서는스레드의기본적인사용법및스레드와관련된여러메서드들의사용법에대해서설명합니다. 또한멀티스레드와멀티스레드에서주의해야할사항들에대해설명합니다. 주요내용입니다. - 스레드코드작성및실행 - run() 메서드 - 스레드상태 - getpriority() 와 setpriority() - sleep() - join() - yield() - synchronized( 공유데이터접근 ) - wait() 와 notify()

Java 자바야놀자 - 활용편 1.1. 스레드 (Thread) 실행 스레드는프로그램내에서, 특히프로세스내에서실행되는흐름의단위를의미합니다. 일반적으로한프로그램은하나의스레드를가지고실행됩니다. 그러나프로그램환경에따라둘이상의스레드를동시에실행해야할수도있습니다. 이러한프로그램을멀티스레드 (multi-thread) 프로그램이라고합니다. 멀티스레드프로그램의가장쉬운예를떠올린다면채팅을들수있습니다. 채팅은사용자가입력한채팅내용을상대방에게보내기위한스레드와상대방으로부터전송된내용을화면에보이게하는스레드가동시에실행되어사용자가채팅내용을입력하는도중에도상대방으로부터전송된내용이화면에보이는것입니다. 사실멀티스레드프로그램의스레드가동시에실행되는것처럼보이지만 CPU( 코어가 1개일경우 ) 는여러개의스레드가실행되어야할경우시분할방식에따라어느한순간에는한개의스레드만실행시킵니다. 그런데스레드에할당된 CPU 사용시간간격이매우작기때문에사용자는동시에진행되는것처럼느끼는것입니다. 스레드는플랫폼에따라약간씩의차이가있기때문에프로그래머가이를조정해주어야하며, 운영체제에따라서도처리방식의차이가있습니다. 프로세스는각각하나의 CPU 자원을가지지만, 스레드는하나의자원을공유할수있습니다. 멀티프로세스와멀티스레드는양쪽모두여러흐름이동시에진행된다는공통점을가지고있습니다. 하지만멀티프로세스에서각프로세스는독립적으로실행되며각각별개의메모리를차지하고있는것과달리멀티스레드는프로세스내의메모리를공유해사용할수있습니다. 또한프로세스간의전환속도에비하여스레드간의전환속도가더빠릅니다. 멀티스레드의다른장점은 CPU가여러개 2) 일경우에각각의프로세서가스레드하나씩을담당하는방법으로속도를높일수있다는것입니다. 이러한시스템에서는여러스레드가실제시간상으로동시에수행될수있기때문입니다. 그러나멀티스레드프로그램에서는각각의스레드중어떤것이먼저실행될지그순서를알수없기때문에실행결과를예측하기어려운단점이있습니다. 이장에서는용어정의를 스레드 는실행환경을의미하고, 실행환경 (execution context) 은프로그램과데이터에가상 (Virtual) CPU 를함께내장하고있음을나타내기로 하겠습니다. 그리고 "Thread" 는 java.lang.thread 클래스를의미합니다. 1.1.1. 스레드와 run() 메서드 스레드를실행되는흐름의단위라고하였는데, 하나의작업이수행되기위해서는다음그 2) CPU 가하나이더라도코어 (Core) 가둘이상이라면각각의코어가스레드하나씩을담당하여처리합니다.

Chapter 스레드프로그래밍 1 림에보는것처럼 3가지요소를필요로합니다. 먼저 Code 에해당하는부분에서개발자는스레드에의해수행될작업내용들을 run() 메서드에구현해야하는데그림에서 Runnable 인터페이스를구현한 HelloRunner 클래스입니다. 이러한클래스들을러너 (runner) 클래스라고부릅니다. 그다음에 Data 부분이있는데스레드에의해수행될 Runner 객체에해당하며그림에서는 HelloRunner 클래스의인스턴스 r에해당합니다. 마지막으로 Cpu 에해당하는부분으로 HelloRunner 클래스의인스턴스 r을인자로하여스레드객체를만드는부분입니다. 이처럼하나의스레드를만들려면 Runner 클래스, Runner 객체, 그리고 Thread 객체가필요합니다. 다음프로그램은스레드를이용하여화면에숫자를출력하는간단한예제입니다. HelloRunner.java 1: public class HelloRunner implements Runnable { int i; 3: 4: public void run() { 5: i = 0; 6: while (true) { 7: System.out.println("Hello : " + i++); 8: if ( i > 10 ) { 9: break; 10: } 11: } 1 }//end run() 13: }//end class HelloRunner 클래스를만들기위해서는 Runnable인터페이스를 implements합니다. HelloRunner 클래스처럼쓰래드가실행할코드를작성한클래스를러너 (Runner) 클래스라고부릅니다. 러너클래스를작성할때반드시 Runnable 인터페이스를구현한클래스가아니어도됩니다. Thread 클래스를직접상속받아구현할수있습니다. 그러나 Runnable 인터페이스를사용하여러너클래스를구현하는것을권장합니다.

Java 자바야놀자 - 활용편 run() 메서드는스레드가수행할부분입니다. run() 메서드는 Runnable 인터페이스의추상 (abstract) 메서드이기때문에 Runnable 인터페이스를구현 (implements) 하는클래스에서는반드시 run() 메서드를만들어줘야합니다. run() 메서드는인자가없다는것과리턴타입이 void 임에주의하세요. 다음코드는스레드를생성하고시작시키는예입니다. ThreadExample.java 1: public class ThreadExample { public static void main(string args[]) { 3: System.out.println("main() 메서드시작 "); 4: HelloRunner r = new HelloRunner(); 5: Thread t = new Thread(r); 6: t.start(); 7: System.out.println("main() 메서드끝 "); 8: } 9: } main 안에서 HelloRunner 클래스의객체를생성하고 Thread 클래스의객체를생성하고있습니다. 이때, Thread 생성자의인자로 HelloRunner 클래스의객체를사용하였습니다. 이부분은스레드에게어떤러너클래스의 run() 메서드를실행시킬것인지를알려줍니다. 생성된스레드를실행시키기위해서는반드시 start() 메서드를호출해야합니다. start() 메서드를호출하면스레드는 HelloRunner 클래스의 run() 메서드를실행합니다. 이예제를실행시키면 7라인의출력문장이 HelloRunner의 run() 메서드보다먼저실행될것입니다. 그이유는 ThreadExample 클래스를실행시키면 main 스레드와 t 스레드가실행되는데 t 스레드를 start() 시키면 t 스레드가바로실행되는것이아입니다. start() 한스레드는먼저실행가능한상태 (Runnable) 가된다음스레드스케줄러로부터프로세서를할당받으면그때실행 (Running) 되기때문입니다. t 스레드가실행가능상상태일때에는아마도 main 스레드는이미실행중일것입니다. 그래서 main스레드가실행시키는 9라인이먼저실행되는것입니다. 일반적으로스레드를만드는방법은 Runnable인터페이스를구현하여사용하는방법과 Thread 클래스를상속받아구현하는방법이있습니다. Thread 클래스를상속받아 run() 메서드를재정의하는방법도가능하지만, 반드시다른클래스를상속받아야하는상황이라면 Thread 클래스를상속받을수는없을것입니다. 앞의예제와같이 Runnable인터페이스를구현하는방법을권장합니다. Thread 클래스는 java.lang 패키지에있는클래스이므로 import문이필요없습니다. 다음프로그램 sleep() 메서드를사용하여 main 스레드의실행을잠시멈추게하여 t 스레 드를먼저 (?) 실행되게하는예입니다. exam/java/chapter06/thread/hellorunner2.java

Chapter 스레드프로그래밍 1 1: package exam.java.chapter06.thread; 3: public class HelloRunner2 implements Runnable { 4: int i; 5: public void run() { 6: i = 0; 7: while (true) { 8: System.out.println(" 숫자 : " + i++); 9: if ( i > 10 ) { 10: break; 11: } 1 } 13: }//end run() 14: }//end class exam/java/chapter06/thread/threadexample2.java 1: package exam.java.chapter06.thread; 3: public class ThreadExample2 { 4: public static void main(string args[]) { 5: System.out.println("main() 의시작 "); 6: HelloRunner2 r = new HelloRunner2(); 7: Thread t = new Thread(r); 8: t.start(); 9: try { 10: Thread.sleep(10); 11: } catch(interruptedexception e) { 1 e.printstacktrace(); 13: } 14: System.out.println("main() 의끝 "); 15: } 16: } 이예제가이전프로그램과다른점은 TestThreadSleep.java 파일의 9라인에서 13라인까지입니다. 7라인에서는스레드를생성합니다. 그리고 8라인에서는 start() 메서드를사용하여스레드를실행시킵니다. 10라인의 Thread.sleep(10) 은현재수행하고있는스레드의수행을잠깐멈추게하고있습니다. Thread.sleep() 메서드는밀리초 (1/1000초) 단위로스레드를지연시킬수있습니다. sleep() 메서드는 InterruptedException이발생할가능성이있는메서드이므로 try~catch블록으로예외처리를해주었습니다. 이때 sleep() 되는스레드는 main 스레드일경우도있고 6라인에서생성한스레드 t 일수도있습니다. 이예제에서는확률적으로 sleep() 메서드에의해스레드수행이잠깐멈추는스레드는 main 스레드일가능성이높습니다. 그러므로 t 스레드를실행시킨다음 main 스레드에의해 14라인에서화면에 "main() 의끝 " 라는문자열을출력합니다.

Java 자바야놀자 - 활용편 1.1.2. 스레드상태 스레드는시작과종료상태만이는것은아닙니다. start() 메서드에의해스레드가실행되기 전에스레드는실행가능상태가됩니다. 다음그림은스레드의기본적인상태도를나타낸 것입니다. 스레드상태도를살펴보면먼저하나의스레드가생성된후 start() 메서드를호출하면곧바로실행되지않고실행가능한상태가되는것을알수있습니다. 스레드는 start() 메서드가호출되면실행가능 (Runnable) 한상태로대기하다가스레드스케줄러에의해프로세서를할당받으면스레드가실행 (Running) 됩니다. 할당받은시간내에 run() 메서드실행이끝난다면스레드는종료되고, 그러지못한다면스레드는다시실행가능 (runnable) 한상태로돌아가스레드스케줄러에의해프로세서를할당받을때까지기다리게된다. 또스레드가실행도중에 sleep(), join(), yield() 등과같은특정한메서드의 Blocking 이벤트가발생하면봉쇄 (Blocked) 상태가될수도있습니다. 앞에서언급했지만스레드를생성하는방법은두가지가있는데첫번째방법은앞에서설 명한것과같이 Runnable 인터페이스를 implements 하는방법이었고, 이제두번째방법 에대해알아보겠습니다. 이방법은스레드클래스를직접상속받아구현하는것입니다. 다음프로그램은앞의예제를스레드클래스를상속받아구현한것입니다. exam/java/chapter06/thread/mythread.java 1: package exam.java.chapter06.thread; 3: public class MyThread extends Thread { 4: public static void main(string args[]) throws Exception { 5: Thread t = new MyThread(); 6: t.start(); 7: try { 8: Thread.sleep(10); 9: } catch(interruptedexception e) { 10: e.printstacktrace(); 11: } 1 System.out.println("main() 의끝 "); 13: }//end main 14: public void run() { 15: int i = 0;

Chapter 스레드프로그래밍 1 16: while (true) { 17: System.out.println(" 숫자 : " + i++); 18: if ( i == 10 ) { 19: break; 20: } 21: } 2 }//end run 23: }//end class Runnable 인터페이스를 implements하지않고 Thread 클래스를상속받아서 run() 메서드를재정의해서스레드를만들었습니다. 스레드를생성할때어떤방식을사용해도되지만일반적으로 Runnable 인터페이스를구현하는방법은더객체지향적이고, 단일상속의문제를해결할수있으며, 반드시 run() 메서드를구현해야하므로일관성을갖는장점이있습니다. 1.1.2.1. 세계시간출력프로그램 다음프로그램은스레드를이용하여시계를만드는예제입니다. 시계는현재시간을 1 초에 한번씩화면에표시하면됩니다. exam/java/chapter06/thread/worldclock.java 1: package exam.java.chapter06.thread; 3: import java.util.*; 4: import java.lang.thread; 5: 6: public class WorldClock implements Runnable { 7: 8: Calendar calendar; 9: String location; 10: 11: public WorldClock(String city) { 1 this.location = city; 13: } 14: 15: public void run() { 16: while (true) { 17: this.displaydate( ); 18: try { 19: Thread.sleep(1000); 20: } catch (InterruptedException e) { 21: }//end try~catch 2 }//end while 23: }//end run() 24: 25: public void displaydate() {

Java 자바야놀자 - 활용편 26: String[] ids; 27: SimpleTimeZone pdt = null; 28: 29: if (this.location == " 서울 ") { 30: ids = TimeZone.getAvailableIDs(9*60*60*1000); 31: if (ids.length == 0) System.exit(0); 3 pdt = new SimpleTimeZone(9*60*60*1000, ids[0]); 33: } else if (this.location == " 도쿄 ") { 34: ids = TimeZone.getAvailableIDs(9*60*60*1000); 35: if (ids.length == 0) System.exit(0); 36: pdt = new SimpleTimeZone(9*60*60*1000, ids[0]); 37: } else if (this.location == "LA") { 38: ids = TimeZone.getAvailableIDs(-8*60*60*1000); 39: if (ids.length == 0) System.exit(0); 40: pdt = new SimpleTimeZone(-8*60*60*1000, ids[0]); 41: } else if (this.location == " 뉴욕 ") { 4 ids = TimeZone.getAvailableIDs(-5*60*60*1000); 43: if (ids.length == 0) System.exit(0); 44: pdt = new SimpleTimeZone(-5*60*60*1000, ids[0]); 45: } 46: 47: calendar = new GregorianCalendar(pdt); 48: calendar.settime(new Date()); 49: System.out.print(" 현재 " + location + " 시각 :"); 50: System.out.print(calendar.get(Calendar.YEAR)+" 년 "); 51: System.out.print((calendar.get(Calendar.MONTH)+1)+" 월 "); 5 System.out.print(calendar.get(Calendar.DATE)+" 일 :"); 53: System.out.print(calendar.get(Calendar.HOUR_OF_DAY)+" 시 "); 54: System.out.print(calendar.get(Calendar.MINUTE)+" 분 "); 55: System.out.print(calendar.get(Calendar.SECOND)+" 초 "); 56: System.out.println(" ZONE_OFFSET: " + (calendar.get(calendar.zone_offset)/(60*60*1000))); 57: } 58: }//end class exam/java/chapter06/thread/threadclockexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadClockExample { 4: public static void main(string args[]) { 5: WorldClock seoul = new WorldClock(" 서울 "); 6: WorldClock tokyo = new WorldClock(" 도쿄 "); 7: WorldClock la = new WorldClock("LA"); 8: WorldClock newyork = new WorldClock(" 뉴욕 "); 9: 10: Thread seoulthread = new Thread(seoul); 11: Thread tokyothread = new Thread(tokyo); 1 Thread lathread = new Thread(la); 13: Thread newyorkthread = new Thread(newyork); 14:

Chapter 스레드프로그래밍 1 15: seoulthread.start(); 16: tokyothread.start(); 17: lathread.start(); 18: newyorkthread.start(); 19: } 20: } 위의코드는 main 에서 seoulthread, tokyothread, lathread, newyorkthread 4 개의 스레드를생성하고각스레드는해당하는지역의시간을출력합니다. 1.1.2.2. 폭탄해체하기프로그램 다음예제는멀티스레드를이용하면무엇을할수있는지보여주는간단한예입니다. 이프로그램은주어진시간안에문제를풀어야합니다. 시간은 30초가주어지며 30초이내에문제를풀어야합니다. 기회는 3번까지주어지며 30초가지나지않더라도 3번의기회를모두사용하면실패합니다. 시간을감소시키는스레드와문제를출제하는스레드가동시에실행됩니다. 코드에서주의해서봐야할부분은스레드를종료시키는부분입니다. 스레드를종료시키기위해플래그값을사용합니다. 스레드를종료시키기위해서는스레드를 stop() 메서드를사용해서강제종료시키지마세요. stop() 메서드는데드락 (Dead Lock) 이발생할가능성이있어서 deprecated 됐습니다. 스레드를종료시키기위해서는플래그값등을이용해서 run() 메서드를자연스럽게종료시키는것이더바람직합니다. FlagData 클래스는플래그값을저장하는클래스입니다. 변수의값을변경시켜 run() 메 서드가자연스럽게종료되도록하기위해사용합니다. exam/java/chapter06/thread/flagdata.java 1: package exam.java.chapter06.thread; 3: public class FlagData { 4: public static boolean isok = false; 5: public static boolean isfail = false; 6: }//end FlagData class CounterRunner 클래스는시간을감소시키면서폭파장치해체여부를확인하는러너클래 스입니다. exam/java/chapter06/thread/counterrunner.java 1: package exam.java.chapter06.thread;

Java 자바야놀자 - 활용편 3: public class CounterRunner implements Runnable { 4: public void run() { 5: for(int i=30; i>0; i--) { 6: // 문제를주어진시간안에풀었는가? 확인 7: // 플래그값으로확인 8: if(flagdata.isok) { 9: System.out.println(" 폭파장치가해제되었습니다."); 10: return; 11: } 1 if(flagdata.isfail) { 13: System.out.println(" 폭파장치를잘못건드렸습니다."); 14: break; 15: } 16: 17: System.out.println(i+" 초남았습니다."); 18: //1초씩 sleep 19: try { 20: Thread.sleep(1000); 21: } catch (InterruptedException e) { 2 //nothing 23: } 24: } 25: System.out.println("Booooooooom!!!!!!!!!!!"); 26: System.exit(0); 27: }//end run 28: }//end CounterRunner class QuestionRunner 클래스는문제를출제하고정답을체크하는 ( 폭탄을해체하는 ) 러너클래 스입니다. exam/java/chapter06/thread/questionrunner.java 1: package exam.java.chapter06.thread; 3: import javax.swing.joptionpane; 4: 5: public class QuestionRunner implements Runnable { 6: String[] question = { "3+5=", 7: "2349*245=", 8: " 대한민국의수도는?", 9: "200-199=", 10: "Runnable 인터페이스의메서드는?", 11: "2의 16승은?" }; 1 String[] answer = { "8", 13: "575505", 14: " 서울 ", 15: "1", 16: "run", 17: "65536" }; 18: public void run() { 19: System.out.println(" 주어진시간안에문제를풀어야합니다.");

Chapter 스레드프로그래밍 1 20: System.out.println(" 기회는 3번까지주어집니다."); 21: int failcount = 3; 2 while(true) { 23: int index = (int)(math.random()*6); 24: 25: System.out.println(failCount +" 번의기회가남았습니다."); 26: String input = JOptionPane.showInputDialog(question[index]); 27: 28: if(answer[index].equals(input)) { 29: System.out.println(" 정답입니다."); 30: FlagData.isOK = true; 31: return; 3 }else { 33: failcount--; 34: if(failcount <= 0) { 35: FlagData.isFail = true; 36: return; 37: } 38: } 39: }//end while 40: }//end run 41: }//end QuestionRunner class 다음코드는메인클래스입니다. 스레드를생성하고실행시키기위한코드입니다. exam/java/chapter06/thread/threadbombexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadBombExample { 4: public static void main(string[] args) { 5: CounterRunner cr = new CounterRunner(); 6: QuestionRunner qr = new QuestionRunner(); 7: 8: Thread t1 = new Thread(cr); 9: Thread t2 = new Thread(qr); 10: 11: t1.start(); 1 t2.start(); 13: } 14: }

Java 자바야놀자 - 활용편 1.2. 스레드 (Thread) 클래스의메서드 다음프로그램은구구단의출력부분을스레드로만들어동시에여러개의스레드가실행된 후출력하는예제입니다. 다음예를통해스레드클래스가제공하는메서드들에대하여설 명하겠습니다. exam/java/chapter06/thread/gugurunner.java 1: package exam.java.chapter06.thread; 3: public class GuGuRunner implements Runnable { 4: private int dan; 5: public GuGuRunner(int init_dan) { 6: dan = init_dan; 7: } 8: 9: public void run() { 10: for(int i=0; i<10; i++) { 11: System.out.println(dan + " 단 : " + dan + "*" + i + "=" + dan*i); 1 } 13: } 14: } exam/java/chapter06/thread/threadguguexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadGuGuExample { 4: public static void main(string[] args) { 5: Thread t2 = new Thread(new GuGuRunner(2)); 6: Thread t3 = new Thread(new GuGuRunner(3)); 7: Thread t4 = new Thread(new GuGuRunner(4)); 8: Thread t5 = new Thread(new GuGuRunner(5)); 9: Thread t6 = new Thread(new GuGuRunner(6)); 10: Thread t7 = new Thread(new GuGuRunner(7)); 11: Thread t8 = new Thread(new GuGuRunner(8)); 1 Thread t9 = new Thread(new GuGuRunner(9)); 13: t2.start(); t3.start(); t4.start(); 14: t5.start(); t6.start(); t7.start(); 15: t8.start(); t9.start(); 16: } 17: } 앞의프로그램을실행시키면스레드 t2부터 t9까지서로경쟁하며실행되는것을알수있습니다. 한순간에는하나의스레드만수행되며할당된시간동안스레드가수행되다가, 다른스레드에게프로세서사용권한이넘어갑니다. 자바에서는우선순위값을각각스레드에배정하고, 우선순위가높은스레드가프로세서사용권한을할당받도록하여더많은프로

Chapter 스레드프로그래밍 1 세스사용시간을갖도록하는선점형 (Preemptive) 방식을사용합니다. 우선순위값의할 당은스레드스케줄러 (Thread Scheduler) 가담당합니다. 1.2.1. getpriority() 와 setpriority() 자바의스레드우선순위는 1 부터 10 까지가질수있습니다. 숫자가클수록우선순위는높 으며기본우선순위는 5 입니다. 다음프로그램은 setpriority() 메서드를이용하여스레드의우선순위를변경하고, getpriority() 메서드를이용하여스레드의우선순위를알아내는예제입니다. exam/java/chapter06/thread/gugurunner.java( 이코드는앞에서작성했던코드입니다.) 1: package exam.java.chapter06.thread; 3: public class GuGuRunner implements Runnable { 4: private int dan; 5: public GuGuRunner(int init_dan) { 6: dan = init_dan; 7: } 8: 9: public void run() { 10: for(int i=0; i<10; i++) { 11: System.out.println(dan + " 단 : " + dan + "*" + i + "=" + dan*i); 1 } 13: } 14: } exam/java/chapter06/thread/threadpriorityexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadPriorityExample { 4: public static void main(string[] args) { 5: Thread t2 = new Thread(new GuGuRunner(2)); 6: Thread t3 = new Thread(new GuGuRunner(3)); 7: Thread t4 = new Thread(new GuGuRunner(4)); 8: Thread t5 = new Thread(new GuGuRunner(5)); 9: 10: t2.setpriority(4); 11: System.out.println( t3.getpriority() ); 1 t2.start(); 13: t3.start(); 14: t4.start(); 15: t5.start(); 16: } 17: }

Java 자바야놀자 - 활용편 자바에서우선순위가높은스레드를먼저실행시키는선점형방식을채택하고있습니다. 그러므로이코드의예상되는실행결과는 t2가실행하는 2단이가장마지막에실행되는것입니다. 그러나예제를실행시키는컴퓨터환경에서 CPU의코어가두개이상이라면결과에서 t2가우선순위가낮더라도다른스레드보다먼저실행될수있습니다. t2가 start된후 t3가 runnable 상태가되기전에 t2가 running될수도있습니다. 1.2.2. sleep() 다음프로그램은 sleep() 메서드를이용하여해당하는스레드를지정한시간 (mille second) 동안정지시키는예제입니다. sleep() 메서드는스레드의실행을지정한시간동안 정지시킵니다. 지정한시간이지나면스레드는다시실행상태로되는것이아니고실행가 능한상태로전이됩니다. exam/java/chapter06/thread/gugusleeprunner.java 1: package exam.java.chapter06.thread; 3: public class GuGuSleepRunner implements Runnable { 4: private int dan; 5: public GuGuSleepRunner(int init_dan) { 6: dan = init_dan; 7: } 8: public void run() { 9: long sleeptime = (long)(math.random() * 500); 10: System.out.println(dan + " 단이 " + sleeptime + " 만큼쉼 "); 11: try{ 1 Thread.sleep(sleepTime); 13: }catch (InterruptedException e) { 14: } 15: for(int i=0; i<10; i++) { 16: System.out.println(dan + " 단 : " + dan + "*" + i + "=" + dan*i); 17: } 18: } 19: } exam/java/chapter06/thread/threadsleepexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadSleepExample { 4: public static void main(string[] args) { 5: Thread t2 = new Thread(new GuGuSleepRunner(2)); 6: Thread t3 = new Thread(new GuGuSleepRunner(3)); 7: Thread t4 = new Thread(new GuGuSleepRunner(4)); 8: Thread t5 = new Thread(new GuGuSleepRunner(5)); 9: Thread t6 = new Thread(new GuGuSleepRunner(6)); 10:

Chapter 스레드프로그래밍 1 11: t2.start(); 1 t3.start(); 13: t4.start(); 14: t5.start(); 15: t6.start(); 16: } 17: } 1.2.3. join() 다음프로그램은 join() 메서드에관한예제입니다. join() 메서드는 join 된스레드이후에 실행 (start) 되는스레드들은 join 된스레드가실행을종료한다음실행됩니다. exam/java/chapter06/thread/gugurunner.java( 이코드는앞에서작성된예제입니다.) 1: package exam.java.chapter06.thread; 3: public class GuGuRunner implements Runnable { 4: private int dan; 5: public GuGuRunner(int init_dan) { 6: dan = init_dan; 7: } 8: public void run() { 9: for(int i=0; i<10; i++) { 10: System.out.println(dan + " 단 : " + dan + "*" + i + "=" + dan*i); 11: } 1 } 13: } exam/java/chapter06/thread/threadjoinexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadJoinEaxmple { 4: public static void main(string[] args) { 5: Thread t2 = new Thread(new GuGuRunner(2)); 6: Thread t3 = new Thread(new GuGuRunner(3)); 7: Thread t4 = new Thread(new GuGuRunner(4)); 8: Thread t5 = new Thread(new GuGuRunner(5)); 9: Thread t6 = new Thread(new GuGuRunner(6)); 10: 11: t2.setpriority(4); 1 t3.setpriority(4); 13: t4.setpriority(4); 14: t5.setpriority(4); 15: t6.setpriority(4); 16: 17: t2.start(); 18: t3.start();

Java 자바야놀자 - 활용편 19: t4.start(); 20: try { 21: t4.join(); //t5 와 t6은 t4의실행이종료돼야실행됨 2 }catch(interruptedexception e) { 23: } 24: t5.start(); 25: t6.start(); 26: } 27: } 1.2.4. yield() 다음프로그램은 yield() 메서드에관한예제로 yield() 는동일순위의스레드에게프로세서 의사용을양보하는기능을가지고있습니다. 우선순위가다른스레드에게는아무런영향 을주지않습니다. exam/java/chapter06/thread/guguyieldrunner.java 1: package exam.java.chapter06.thread; 3: public class GuGuYieldRunner implements Runnable { 4: private int dan; 5: public GuGuYieldRunner(int init_dan) { 6: dan = init_dan; 7: } 8: public void run() { 9: if(dan == 8) { 10: System.out.println("8 단이 9단에게양보 "); 11: Thread.yield(); 1 } 13: for(int i=0; i<10; i++) { 14: System.out.println(dan + " 단 : " + dan + "*" + i + "=" + dan*i); 15: } 16: } 17: } exam/java/chapter06/thread/threadyieldexample.java 1: package exam.java.chapter06.thread; 3: public class ThreadYieldExample { 4: public static void main(string[] args) { 5: 6: Thread t6 = new Thread(new GuGuYieldRunner(6)); 7: Thread t7 = new Thread(new GuGuYieldRunner(7)); 8: Thread t8 = new Thread(new GuGuYieldRunner(8)); 9: Thread t9 = new Thread(new GuGuYieldRunner(9)); 10:

Chapter 스레드프로그래밍 1 11: t6.setpriority(4); 1 t7.setpriority(4); 13: t8.setpriority(5); 14: t9.setpriority(5); 15: 16: t6.start(); 17: t7.start(); 18: t8.start(); 19: t9.start(); 20: } 21: }

Java 자바야놀자 - 활용편 1.3. 공유데이터접근 현시점에서여러스레드중어떤스레드가수행될지알수없고, 선정된스레드가얼마동안수행될지또이스레드가끝난후다음에어떤스레드가수행될지알수가없습니다. 따라서프로그래머가실행되는스레드들을관리할필요가있습니다. 특히, 여러스레드들이공유데이터 (Shared Data) 에접근할때는스레드들의관리가더욱필요합니다. 1.3.1. 공유데이터의문제점 다음예제는반드시이해해야하므로충분한시간을가지고공부하기바랍니다. 먼저이해 를돕기위해다음의그림을설명하겠습니다. 그림에서오른쪽공유데이터클래스를살펴보면 push() 와 pop() 메서드가있습니다. 이메서드들은스택에데이터를넣거 (push) 나빼내 (pop) 는일을합니다. 첫번째스레드 (T1) 에서스택에데이터를넣기위해 push() 메서드를호출합니다. 데이터를받은 push() 메서드는스택에데이터를넣습니다 (1). 그후스택데이터를가리키는포인터를하나증가시켜야하는데, 그전에시간이걸리는작업 (longjob()) 을수행한다고가정하면중요한문제가발생할수있습니다. 그이유는첫번째스레드 (T1) 수행중에스케줄러로부터할당받은프로세서시간을사용하고나면 T1 스레드는 Running상태에서 Runnable 상태로되고, 이때두번째스레드 (T2) 가 Running 상태가될수있습니다. 시간이오래걸리는일 (longjob()) 을수행하는도중에 ( 아직포인터를증가시키지않았음 ), 우선권이다른스레드에게넘어간것입니다. 두번째스레드 (T2) 는첫번째스레드에서포인터가증가하지않았는데도 push() 메서드를호출하게되는데, 이때포인터가가리키는곳에데이터를넣게되므로첫번째스레드 T1이 push한데이터에두번째스레드 T2가

Chapter 스레드프로그래밍 1 push 한데이터가덮어써지게되는것입니다. 지금까지설명한내용을이해할수있도록예제코드를작성하겠습니다. 다음코드는공유데이터에사용되는클래스입니다. 푸시와팝을구현한클래스입니다. 공 유데이터영역에데이터를푸시할때어떤데이터가저장되는지보여주기위해서 push() 메서드에서푸시한데이터를반환하도록구현했습니다. pop() 메서드의 synchronized 블 록은뒤에서자세하게설명됩니다. exam/java/chapter06/thread/shareddata.java 1: package exam.java.chapter06.thread; 3: public class SharedData { 4: 5: int index=0; 6: char[] stack = new char[6]; 7: 8: public char push(char c) { 9: stack[index] = c; 10: longjob(); 11: index++; 1 return c; 13: } 14: 15: public char pop() { 16: synchronized(this) { 17: index--; 18: longjob(); 19: return stack[index]; 20: } 21: } 2 23: public void longjob() { 24: for(int i=0; i<10; i++) { 25: System.out.print("."); 26: } 27: System.out.println(); 28: } 29: } 아래의코드는스레드가공유데이터영역에데이터를푸시합니다. exam/java/chapter06/thread/pushrunner.java 1: package exam.java.chapter06.thread; 3: public class PushRunner implements Runnable { 4: String name; 5: SharedData sd; 6: PushRunner(String name, SharedData sd) {

Java 자바야놀자 - 활용편 7: this.name = name; 8: this.sd = sd; 9: } 10: public void run() { 11: System.out.println(name + sd.push('a')); 1 System.out.println(name + sd.push('b')); 13: System.out.println(name + sd.push('c')); 14: } 15: } 아래의코드는스레드가공유데이터영역에저장되어있는데이터를팝합니다. exam/java/chapter06/thread/poprunner.java 1: package exam.java.chapter06.thread; 3: public class PopRunner implements Runnable { 4: String name; 5: SharedData sd; 6: PopRunner(String name, SharedData sd) { 7: this.name = name; 8: this.sd = sd; 9: } 10: public void run() { 11: System.out.println(name + sd.pop()); 1 System.out.println(name + sd.pop()); 13: System.out.println(name + sd.pop()); 14: } 15: } 아래의코드는푸시스레드와팝스레드를각각두개씩생성하여실행시킵니다. 먼저푸 시스레드가데이터를푸시한후에팝스레드가데이터를팝하도록하기위해 join() 메서 드를사용하였습니다. exam/java/chapter06/thread/shareddataexample.java 1: package exam.java.chapter06.thread; 3: public class SharedDataExample { 4: public static void main(string[] args) { 5: SharedData sd = new SharedData(); 6: 7: PushRunner pushr1 = new PushRunner("Push- 하나 : ", sd); 8: PushRunner pushr2 = new PushRunner("Push- 둘 : ", sd); 9: 10: Thread pusht1 = new Thread(pushr1); 11: Thread pusht2 = new Thread(pushr2); 1 13: pusht1.start(); 14: pusht2.start(); 15:

Chapter 스레드프로그래밍 1 16: try { 17: pusht1.join(); 18: pusht2.join(); 19: } catch (InterruptedException e) { 20: //nothing... 21: } 2 23: System.out.println("\n 스택에저장된데이터는 "); 24: 25: PopRunner popr1 = new PopRunner("Pop- 하나 : ", sd); 26: PopRunner popr2 = new PopRunner("Pop- 둘 : ", sd); 27: 28: Thread popt1 = new Thread(popr1); 29: Thread popt2 = new Thread(popr2); 30: 31: popt1.start(); 3 popt2.start(); 33: 34: } 35: } 예제를실행시키면스택에데이터가정상적으로푸시되지않을가능성이있는것을알수있습니다. 만일불특정다수가사용하는인터넷환경에서멀티스레드로인한공유데이터의손상은매우높은확률을갖게될것입니다. 지금까지의상황에대한결론은공유데이터를가지고작업하는스레드는예측할수없는순간에제어권이다른스레드로양도되어데이터파손이나손상을일으킬수있음을명심해야한다는것입니다. SharedDataExample 클래스를실행시켰을때의결과는항상동일하지는않습니다. pop() 메서드에의해데이터를팝하는부분에서아무것도출력이되지않을수있습니다.

Java 자바야놀자 - 활용편 실행결과... Push- 하나 : A...... Push- 하나 : B Push- 둘 : A...... Push- 하나 : C Push- 둘 : B... Push- 둘 : C 스택에저장된데이터는...... Pop- 하나 : C Pop- 둘 :... Pop- 하나 : B... Pop- 둘 :... Pop- 하나 : B... Pop- 둘 : A 1.3.2. 공유데이터문제점의해결 (synchronized) 이와같은공유데이터문제는매우심각하기때문에해결방안을모색해야하는데문제의심각성에비해그렇게어렵지만은않습니다. 먼저첫번째스레드가 push() 메서드나 pop() 메서드를호출하여수행되는동안두번째스레드로제어권이넘어가지않아야합니다. 또다른방법은제어권이두번째스레드로넘어갔더라도, 첫번째스레드가메서드를완전히수행하지않은상태라면, 제어를첫번째스레드에게다시넘겨주면됩니다. 자바에서는두번째방법을사용하는데이때사용하는키워드가 synchronized 입니다. 다음프로그램은앞의예제프로그램에 synchronized 를추가하여공유데이터의문제점을 해결한것입니다. 앞에서작성된 SharedData 클래스파일을아래코드에서진하게된부 분만수정한다음 SharedDataExample 클래스로실행시키세요. exam/java/chapter06/thread/shareddata.java 1: package exam.java.chapter06.thread; 3: public class SharedData { 4:

Chapter 스레드프로그래밍 1 5: int index=0; 6: char[] stack = new char[6]; 7: 8: public synchronized char push(char c) { 9: stack[index] = c; 10: longjob(); 11: index++; 1 return c; 13: } 14: 15: public char pop() { 16: synchronized(this) { 17: index--; 18: longjob(); 19: return stack[index]; 20: } 21: } 2 23: public void longjob() { 24: for(long i=0; i<20; i++) { 25: System.out.print("."); 26: } 27: System.out.println(); 28: } 29: } 예제코드에서 push() 메서드와 pop() 메서드에서 synchronized를사용했습니다. synchronized 키워드가두메서드에서서로다르게사용되었는데, push() 에서처럼사용하는것을 synchronized method라하고, pop() 메서드처럼사용하는것을 synchronized block이라고합니다. lock flag를필요로하는부분이메서드전체가아니라면필요한부분만블록으로설정해서사용하는것이더바람직합니다. SharedDataExample 클래스를통해서실행시키면실행결과는다르게나타날수있지만중요한것은스택에데이터가모두푸시되고팝된다는것입니다.(pop() 메서드에의해출력되는데이터가모두존재합니다.) synchronized 를설명하기위해 Object Lock Flag 를먼저설명하기로하겠습니다. 생성된 모든객체는 lock flag 를가지고있는데스레드가 synchronized 메서드나블록을수행하 기위해서는반드시 lock flag 를가지고있어야합니다. 다음그림을살펴보세요.

Java 자바야놀자 - 활용편 앞의그림에서처럼 push() 메서드를호출하면스레드는공유객체의 lock flag가있는지확인하고, 있으면 lock flag를가져간후에실행됩니다. 이렇게 lock flag를소유한스레드에의해 push() 메서드가수행되다가다른스레드에게제어권이넘어가면첫번째스레드는대기 (block) 상태가되고, 두번째스레드가활동하기시작할것입니다. 그러나두번째스레드에서도 push() 메서드를호출하면 synchronized 키워드로인해공유객체의 lock flag 를가져와야실행될수있습니다. 그런데, lock flag는이미첫번째스레드에서소유하고있기때문에두번째스레드에의해 push() 메서드는실행될수가없고. 두번째스레드는대기상태가됩니다. 그동안제어권은다시첫번째스레드로넘어오게되고, 멈춰있던 push() 메서드는계속수행하게됩니다. 첫번째스레드에의해 push() 메서드가수행된후에는 lock flag를반납합니다. 그후 lock flag가반납되었기때문에대기하고있던두번째스레드가제어권을넘겨받아수행될수있습니다. 이처럼 synchronized 메서드또는블록은여러스레드에의해공유데이터가사용될때공유데이터가스레드들로부터데이터의일관성을갖도록해줄수있습니다. 다음그림은기본적인스레드상태도에공유데이터처리부분을추가한것입니다.

Chapter 스레드프로그래밍 1 앞의그림을보면스레드 synchronized 메서드를수행하면 lock flag 를받을때까지 Lock pool 에서대기하게되는것을볼수있습니다. 1.3.3. wait() 와 notify() synchronized로스레드의기본적인문제는처리되었지만해결해야할문제가더남아있습니다. 앞에서설명한스택예제프로그램을다시살펴보기로하겠습니다. 만약스택이비어있는상태에서 pop() 메서드가수행된다면어떻게될까요? 이때에는 synchronized로도해결할수가없습니다. 이때사용되는메서드가 wait() 와 notify() 입니다. 앞에서작성된코드를푸시와팝이동시에실행되도록 join() 메서드호출부분을삭제 ( 주 석처리해도됩니다 ) 한다음실행시켜보세요. exam/java/chapter06/thread/shareddataexample.java 1: package exam.java.chapter06.thread; 3: public class SharedDataExample { 4: public static void main(string[] args) { 5: SharedData sd = new SharedData(); 6: 7: PushRunner pushr1 = new PushRunner("Push- 하나 : ", sd); 8: PushRunner pushr2 = new PushRunner("Push- 둘 : ", sd); 9: 10: Thread pusht1 = new Thread(pushr1); 11: Thread pusht2 = new Thread(pushr2); 1 13: pusht1.start(); 14: pusht2.start(); 15: 16: // try { 17: // pusht1.join();

Java 자바야놀자 - 활용편 18: // pusht2.join(); 19: // } catch (InterruptedException e) { 20: // //nothing... 21: // } 2 23: System.out.println("\n 스택에저장된데이터는 "); 24: 25: PopRunner popr1 = new PopRunner("Pop- 하나 : ", sd); 26: PopRunner popr2 = new PopRunner("Pop- 둘 : ", sd); 27: 28: Thread popt1 = new Thread(popr1); 29: Thread popt2 = new Thread(popr2); 30: 31: popt1.start(); 3 popt2.start(); 33: 34: } 35: } 위코드는스레드 4개를실행시킵니다. 두개의스레드는데이터를푸시하고, 두개의스레드는데이터를팝하고있습니다. 16라인부터 21라인까지주석처리한다음코드를실행시키면스레드 4개가경쟁적으로실행될것입니다. 이클래스를실행시키면아주드물게아래와같은예외가발생하는것을볼수있습니다. 아래결과는이클립스에서실행한화면입니다. 위와같은예외가발생하는이유는스택에데이터가존재하지않을때팝스레드에의해 데이터팝이일어날경우입니다. wait() 와 notify() 에대해설명할때에생산자와소비자사이의관계를예로설명하곤합니다. 위의예제를수정하기전에생산자 / 소비자문제에대하여설명하기위해다음그림을보면서설명하겠습니다.

Chapter 스레드프로그래밍 1 생성할스레드의수는모두 6개 ( 생산자 3개, 소비자 3개 ) 입니다. 각각의스레드가공유데이터영역 (BakeStack) 을공유하고있습니다. 생산자가푸시하여데이터를생산하면, 소비자는팝하여데이터를소비합니다. 그런데생산자가데이터를푸시하기전또는팝할데이터가없을때소비자가데이터를팝하려고할경우가있습니다. 소비자팝할데이터가없을때팝을하도록한다면예외가발생할수도있습니다. 그래서팝할데이터가없다면소비자에게생산자가데이터를푸시할때까지기다리도록해야할것입니다 (wait). 그리고생산자는데이터를푸시하면소비자에게데이터가푸시되었음을알려주어야할것입니다 (notify). 이 6개의스레드는서로경쟁하면서실행되는데공유데이터영역인스택을깨뜨리지않고, 푸시된데이터가남아서도안되고모자라서도안됩니다. 다음그림은스레드의상태도에 wait() 와 notify() 메서드를추가한결과를나타낸것입니 다. 다음은앞에서작성된 SharedData 클래스를수정하여푸시와팝스레드가동시에실행되 어도예외가발생하지않도록한코드입니다. exam/java/chapter06/thread/shareddata.java 1: package exam.java.chapter06.thread; 3: public class SharedData { 4: 5: int index=0; 6: char[] stack = new char[6]; 7: 8: public synchronized char push(char c) { 9: notify(); 10: stack[index] = c; 11: longjob(); 1 index++;

Java 자바야놀자 - 활용편 13: return c; 14: } 15: 16: public char pop() { 17: synchronized(this) { 18: if(index==0) { 19: try { 20: wait(); 21: } catch (InterruptedException e) { 2 System.out.println(e.getMessage()); 23: } 24: } else { 25: index--; 26: } 27: longjob(); 28: return stack[index]; 29: } 30: } 31: 3 public void longjob() { 33: for(long i=0; i<20; i++) { 34: System.out.print("."); 35: } 36: System.out.println(); 37: } 38: } SharedData 클래스를수정한다음 SharedDataExample 클래스를실행시켜보세요. 이제스택에데이터가없을때팝을시도하더라도예외가발생하지않습니다. pop() 메서드에서스택에데이터가없을경우 (index가 0일경우 ) wait() 메서드를호출했습니다. 그리고 push() 메서드에서 notify() 메서드에의해데이터가푸시되었음을알려주고있습니다. 그런데 push() 메서드에서는데이터를푸시하기전에 notify 하고있습니다. 데이터를푸시한다음 notify 해야할것같지만 push() 메서는 synchronized 로선언되어있으므로 notify를먼저해도 wait 했던스레드가곧바로실행되지않습니다. 푸시하기전에 notify 하면 wait하는스레드는바로실행이되는것이아니고 Lock flag를다시얻기위해 Lock pool에서대기합니다. API문서에서 Thread 클래스를보면 stop(), resume(), suspend() 등의메서드가 deprecation되어있는것을볼수있습니다. 그이유는이들메서드는 lock flag를가지고있는상태에서봉쇄된후스레드가비정상적으로종료되었을경우 lock flag를반납하지못하고종료되므로 lock flag를필요로하는다른스레드가 lock flag를얻을수없는상태에빠지는데드락 (Deadlock) 이발생할수있기때문입니다. 앞의 wait() 와 nitofy() 를설명하는스레드상태도그림에서 wait() 와 notify() 에의해스레 드의상태를분리하여 Wait pool 로표시한이유는 wait() 메서드에의해스레드가봉쇄될

Chapter 스레드프로그래밍 1 때에는 lock flag 를반납하고봉쇄되기때문입니다. Wait pool 에있던스레드는 notify() 메서드가호출되면반납했던 lock flag 를다시얻기위해 Lock pool 로빠지게됩니다. 다음에설명되는예제들은생산자 / 소비자문제의다른예입니다. 모두 4 개의클래스 (WaitNotifyExample, BakeStack, Baker, Customer) 를작성했습니다. 실행은 WaitNotifyExample 클래스를이용합니다. exam/java/chapter06/thread/waitnotifyexample.java 1: package exam.java.chapter06.thread; 3: public class WaitNotifyExample { 4: public static void main(string[] args) { 5: BakeStack bakestack = new BakeStack(); 6: 7: Baker m1 = new Baker(bakeStack); 8: Thread maker1 = new Thread (m1); 9: maker1.start(); 10: Baker m2 = new Baker(bakeStack); 11: Thread maker2 = new Thread (m2); 1 maker2.start(); 13: Baker m3 = new Baker(bakeStack); 14: Thread maker3 = new Thread (m3); 15: maker3.start(); 16: 17: Customer c1 = new Customer(bakeStack); 18: Thread customer1 = new Thread (c1); 19: customer1.start(); 20: Customer c2 = new Customer(bakeStack); 21: Thread customer2 = new Thread (c2); 2 customer2.start(); 23: Customer c3 = new Customer(bakeStack); 24: Thread customer3 = new Thread (c3); 25: customer3.start(); 26: } 27: } 5라인은공유데이터인 BakeStack 클래스의객체 (instance) 를만듭니다. 7라인부터 15라인은 3개의 Baker 클래스객체를만들고이를스레드화하여실행시킵니다. 이들스레드는생산자스레드입니다. 17라인부터 25라인은 3개의 Customer 클래스객체를만들고이를스레드화하여실행시킵니다. 이들스레드는소비자스레드입니다. 모두 6개의스레드가하나의공유데이터 (BakeStack) 를사용하고있습니다. 이제공유데이터인 BakeStack 을살펴보겠습니다. exam/java/chapter06/thread/bakestack.java 1: package exam.java.chapter06.thread;

Java 자바야놀자 - 활용편 3: import java.util.vector; 4: public class BakeStack { 5: private Vector buff = new Vector(10, 10); 6: 7: public synchronized String pop() { 8: String bread; 9: while (buff.size() == 0) { 10: try { 11: this.wait(); 1 } catch (InterruptedException e) { 13: e.printstacktrace(); 14: } 15: } 16: bread = (String)buff.remove(buff.size() - 1); 17: return bread; 18: } 19: public synchronized void push(string bread) { 20: this.notify(); 21: buff.addelement(bread); 2 } 23: } 5라인에서는스택을좀더쉽게구현하기위해 Vector클래스를사용했습니다. 9라인에서는 buff.size() 가 0 이면 while문을수행하는데이는스택이비어있음을의미합니다. while문안에 wait() 메서드가있는데누군가깨워줄때까지수행을멈추겠다는의미입니다. 여기서 synchronized를사용해서 lock flag를가져왔으나, wait() 가호출되면 lock flag는반납됩니다. 그래야다른스레드가 pop() 를호출할수있기때문입니다. 16라인은스택이비어있지않으면 remove() 메서드를호출해빵을스택에서꺼내넘겨줍니다. 20라인 notify() 메서드를호출합니다. notify() 메서드는대기중인스레드중에서하나를임의로선택하여빵이도착했다는신호를줍니다. 그러면신호를받은스레드는빵을소비하게됩니다. 이때유의할점은 notify() 메서드가대기중인스레드에게신호를보내면곧바로대기중인스레드가동작하지는않는다는것입니다. 물론동작할수도있지만, 결정은스레드 Scheduler에게달려있으므로 push() 가몇번더수행된후에대기중인스레드가수행될수도있습니다. 21라인은 addelement() 메서드를호출하여스택에빵을가져다놓는것입니다. 여기서의의문사항은 addelement() 보다 notify() 를먼저실행하도록했다는것입니다. 즉, 빵을가져다놓기전에빵이왔다는신호를한것입니다. 이의문점은 synchronized와연관시켜생각하면쉽게알수있을것입니다. 이제마지막으로각각의러너클래스들에대해서알아보기로하겠습니다. 먼저 push() 를 수행할 Baker 클래스입니다. exam/java/chapter06/thread/baker.java 1: package exam.java.chapter06.thread;

Chapter 스레드프로그래밍 1 3: public class Baker implements Runnable { 4: private BakeStack bakestack; 5: private int num; 6: private static int counter = 1; 7: public Baker (BakeStack s) { 8: bakestack = s; 9: num = counter++; 10: } 11: public void run() { 1 String bread; 13: for (int i = 0; i < 10; i++) { 14: bread = getbread(); 15: bakestack.push(bread); 16: System.out.println(" 빵집 " + num + " : " + bread); 17: try { 18: Thread.sleep((int)(Math.random()*300)); 19: } catch (InterruptedException e) { 20: e.printstacktrace(); 21: } 2 } 23: } 24: public String getbread() { 25: String bread = null; 26: switch ((int)(math.random() * 3)) { 27: case 0 : 28: bread = " 생크림케잌 "; 29: break; 30: case 1: 31: bread = " 식빵 "; 3 break; 33: case 34: bread = " 고로케 "; 35: break; 36: } 37: return bread; 38: } 39: } Runnable인터페이스를 implements한전형적인클래스이며, 11라인의 run() 메서드가스레드에의해수행됩니다. 14라인에서는 getbread() 메서드를호출하여 3개의빵중하나를반환합니다. 총 10 개의빵을만들어냅니다. 18라인은 sleep() 메서드를이용하여스레드를잠깐정지시켰는데컴퓨터속도가너무빨라순간적으로처리되기때문에일부러다른스레드에게기회를주기위해서잠깐쉬게하는것입니다. 다음은 Customer 클래스입니다. 이클래스도앞의 Baker 클래스와거의유사합니다. exam/java/chapter06/thread/customer.java 1: package exam.java.chapter06.thread;

Java 자바야놀자 - 활용편 3: public class Customer implements Runnable { 4: private BakeStack bakestack; 5: private int num; 6: private static int counter = 1; 7: public Customer (BakeStack s) { 8: bakestack = s; 9: num = counter++; 10: } 11: public void run() { 1 String bread; 13: for (int i = 0; i < 10; i++) { 14: bread = bakestack.pop(); 15: System.out.println(" 손님 " + num + " : " + bread); 16: try { 17: Thread.sleep((int)(Math.random()*300)); 18: } catch (InterruptedException e) { 19: e.printstacktrace(); 20: } 21: } 2 } 23: } 이클래스는공유스택에서빵을 10 번가져와화면에보여줍니다. Baker 클래스와같은내 용이므로설명은생략하겠습니다.

Chapter 스레드프로그래밍 1 1.4. 요점정리 1. 스레드 최소수행단위 Runnable 인터페이스를 implements 한후 run() 메서드에스레드가수행할코드를작성 2. 스레드상태 3. 스레드클래스메서드스레드우선순위 : 1( 가장낮음 )~10( 가장높음 ), 디폴트 5 setpriority(), getpriority() : 우선순위를변경하거나알아보는메서드 sleep(ms) : 스레드의실행을잠시멈추게함 join() : join 이후 start 되는스레드는 join 한스레드가종료해야실행됨 yield() : 같은우선순위를가진다른스레드에게먼저프로세스를점유하도록함 4. 공유데이터

Java 자바야놀자 - 활용편 synchronized, wait() 와 notify()

2. 네트워크프로그래밍 이번장에서는 TCP방식의네트워크프로그래밍과 UDP방식의프로그램에대하여설명합니다. 통신을하기위한기본적인개념과관련클래스들에대해알아보겠습니다. 자실자바로네트워크프로그램을만들일은거의없을지도모릅니다. 왜냐하면자바는 WAS(Web Application Server) 를이용해대부분의서비스를제공하니까요. 그러나최소한의네트워크프로그래밍관련 API는알아두는것이좋습니다. 주요내용입니다. - TCP 네트워크프로그래밍 - UDP 네트워크프로그래밍 - 채팅프로그램샘플 1 - 채팅프로그램샘플 2 - 파일서버프로그램샘플

Java 자바야놀자 - 활용편 네트워크에는소켓 (Socket) 이있는데소켓은다음그림에서처럼어떤프로그래밍모델에 서프로세스사이의통신종단점을의미합니다. 통신이이루어지려면먼저연결설정을하고주소를지정해야합니다. 연결을설정하려면한쪽컴퓨터 ( 서버 ) 는연결을대기하는프로그램을실행해야하고, 다른쪽컴퓨터 ( 클라이언트 ) 는서버로연결을시도해야합니다. 이때클라이언트가서버에연결되려면서버주소와포트번호를알아야합니다 ( 포트 : 하나의서버에서다른네트워크서비스를제공하기위해서사용 ). 포트번호는 TCP/IP시스템에서는 16비트크기를가지며범위는 0 65535 사이의값을가질수있지만 1023번이하의포트 (0 1023) 번호는시스템이미리지정된서비스용 (http : 80, ftp : 21 등 ) 으로사용하기때문에 1023번이하의포트번호는사용하지않는것이좋습니다. 통신방법은여러가지가있지만자바에서는크게 TCP 통신과 UDP통신으로나눌수있습니다. 2.1. TCP 네트워크프로그램 TCP 통신은가장많이이용하는통신방식으로 양방향의스트림통신을제공하는, 신뢰성있는연결지향형통신방식 을의미합니다. 양방향은 클라이언트와서버가동시에존재해야만통신이이루어짐 을의미하고, 신뢰성은 양단에서데이터를주고받을때데이터의손실없이정확히주고받을수있음 을의미합니다. 연결지향형은 클라이언트와서버가상호연결되어야비로소통신이이루어짐 을의미합니다. TCP/IP 소켓연결은 java.net 패키지의클래스를사용하여구현합니다. 다음그림은서버와클라이언트에서어떤일이일어나는지를보여주는그림입니다. 그림에서서버는 java.net 패키지의 ServerSocket클래스를이용하여포트번호를할당합니다. 클라이언트가소켓객체를생성하여연결을요청하면서버는 accept() 메서드를사용하여소켓을열어주고, 클라이언트는서버주소의포트번호로연결을요청합니다.

Chapter 네트워크프로그래밍 2 서버와클라이언트의프로세스가정보를교환할때스트림모델을사용하는데, 이때소켓에는두개의스트림즉, 입력스트림 (InputStream) 과출력스트림 (OutputStream) 이들어있습니다. 임의의프로세스가다른프로세스에게데이터를보내려면소켓과연관된출력스트림에기록하면되고, 상대측프로세서가데이터를읽을때도소켓과연관된입력스트림을읽기만하면됩니다. 2.1.1. TCP 서버 TCP/IP 서버응용프로그램은 ServerSocket과 Socket 네트워크클래스를이용합니다. ServerSocket클래스는서버를설정하는일을합니다. 서버에서는서버소켓을생성한다음클라이언트의접속을대기해야합니다. 그리고클라이언트가접속되면서버에서는임의의소켓을생성하여클라이언트와통신해야합니다. 그러기위해서서버에서는다른두개의소켓을선언해야하는데, 그이유를알아보기위해다음그림을참고로설명하기로하겠습니다. 서버는동시에여러클라이언트를수용할수있어야합니다. 따라서앞의그림처럼여러클라이언트가서버에접속하고이를처리할있도록 ServerSocket를열어둡니다. 이것은일종의 Listener역할을수행합니다.( 접수창구정도로이해하면됩니다.) 1 ServerSocket 은클라이언트의접속을기다리고있고클라이언트는 ServerSocket 으로접속을시도합니다. 2 ServerSocket과클라이언트 Socket의접속이이루어지면, ServerSocket은새로운 Socket을생성해서클라이언트의요청을처리하도록합니다. 그런다음 ServerSocket 은다시다른클라이언트의요청을기다립니다.

Java 자바야놀자 - 활용편 이러한방식을이용하기때문에서버에서는여러클라이언트의요청을처리할수있는것 입니다. 다음코드는통신에필요한서버의역할을작성한예입니다. exam/java/chapter09/tcp/simpleserver.java 1: package exam.java.chapter09.tcp; 3: import java.net.*; 4: import java.io.*; 5: 6: public class SimpleServer { 7: public static void main(string args[]) { 8: String[] messages = { 9: " 누가당신을시비거리에올려놓고있습니다. 강한반발이예상됩니다.", 10: " 새로운일을시작하기는좋으나처음부터무리한계획은자제하세요.", 11: " 주변에누군가가당신을좋아합니다. 주위를천천히돌아보세요.", 1 " 편안한마음으로생활할수있지만, 저녁에사소한고민거리가생깁니다.", 13: " 어려운일에처한다고당황하지마세요. 곧일의실마리를찾을수있습니다." 14: }; 15: 16: ServerSocket serversocket = null; 17: 18: try { 19: serversocket = new ServerSocket(5432); 20: } catch (IOException e) { 21: e.printstacktrace(); 2 }//end try~catch 23: 24: while (true) { 25: int rand = (int)(math.random() * messages.length); 26: try { 27: System.out.println(" 사용자의접속을기다립니다."); 28: Socket newsocket = serversocket.accept(); 29: 30: System.out.println(newSocket.getRemoteSocketAddress() + " 에서 접속."); 31: 3 OutputStream os = newsocket.getoutputstream(); 33: DataOutputStream dos = new DataOutputStream(os); 34: dos.writeutf(messages[rand]); 35: 36: dos.close(); 37: newsocket.close(); 38: System.out.println(" 사용자의접속을종료합니다."); 39: } catch (IOException e) { 40: e.printstacktrace(); 41: }//end try~catch 4 }//end while

Chapter 네트워크프로그래밍 2 43: }//end main() 44: }//end class 이예제는사용자와의접속을지속적으로유지하지않습니다. 클라이언트가접속하면서버에서는메시지를보내주고클라이언트와의연결을닫습니다. 16라인에서서버소켓을선언하고 (ServerSocket) 19라인에서 ServerSocket을만들고, ServerSocket생성자의인자는포트번호를부여합니다. 즉, 서버가 5432번포트를열고클라이언트의접속을기다립니다. 25라인에서는 while 문이무한반복을하는데, 이는서버프로그램을계속수행시키겠다는의미입니다. 28라인에서는 serversocket.accept() 를호출했는데, 이때서버는클라이언트가접속할때까지대기하게됩니다. 클라이언트가접속하면, accept() 메서드는새로운소켓이생성하여반환합니다. 32라인에서는소켓으로부터출력스트림을얻어옵니다. 그리고이를이용해 33라인에서필터스트림인 DataOutputStream을생성하고, 이를통해 34라인에서 writeutf() 메서드를호출해정해진메시지중하나를소켓을통해출력합니다. 이렇게저장한문자열은다음그림의경로를따라클라이언트로전송된다. 2.1.2. TCP 클라이언트 클라이언트프로그램은위의서버처럼복잡하지않습니다. 그리고서버에접속한후전송되는데이터는모두문자열타입으로전송된다는사실을기억하고프로그래밍해야합니다. ( 이를프로토콜이라고하며일종의서버와클라이언트간의통신규약즉, 약속을의미합니다.) 다음프로그램은통신에필요한클라이언트의역할을작성한예입니다. exam/java/chapter09/tcp/simpleclient.java 1: package exam.java.chapter09.tcp;

Java 자바야놀자 - 활용편 3: import java.net.*; 4: import java.io.*; 5: 6: public class SimpleClient { 7: public static void main(string args[]) { 8: try { 9: Socket newsocket = new Socket("127.0.0.1", 5432); 10: InputStream is = newsocket.getinputstream(); 11: DataInputStream dis = new DataInputStream(is); 1 System.out.println(dis.readUTF()); 13: dis.close(); 14: newsocket.close(); 15: } catch (ConnectException connexc) { 16: System.err.println(" 서버연결실패 "); 17: } catch (IOException e) { 18: e.printstacktrace(); 19: } 20: } 21: } 9라인에서는클라이언트도소켓을생성해야하므로 Socket객체를만들었습니다. 이때생성자의인자로서버의 IP 주소와포트번호를지정하고있습니다. 127.0.0.1은루프백 (loopback) 주소를의미하며, 자신컴퓨터의 IP 주소를가리킬때사용합니다 ( 이렇게지정한이유는서버측프로그램도자기컴퓨터에서수행되기때문입니다.). 포트번호 5432를기술한이유는서버에서서버소켓을오픈할때 5432번으로포트를지정했기때문입니다. 만약다른포트로지정한다면서버에연결되지않습니다. 9라인이실행되면서버에연결됩니다. 작성된코드대로라면서버와연결되면연결과동시에서버는문자열을클라이언트소켓으로보냅니다. 즉, 접속하는순간서버는문자열을보내고클라이언트는이문자열을소켓에서읽기만하면됩니다. 10라인에서는소켓에서 InputStream 객체를얻고, DataInputStream을통해문자열을읽을준비를합니다. 12라인의 readutf() 메서드를통해문자열을읽어화면에출력합니다. 앞의예제프로그램을실행시키려면명령프롬프트창에서서버용프로그램을실행시킨다 음다른명령프롬프트창에서클라이언트를실행하면결과를볼수있습니다. java SimpleServer java SimpleClient 2.1.3. 간단한채팅

Chapter 네트워크프로그래밍 2 다음코드는스레드를사용하여 1대1 채팅하는예입니다. 이예제는 3개의클래스 ChatServer, Sender, Receiver로구성되어있습니다. 그중에서 Sender 클래스는입력한내용을보내는클래스이며, Receiver 클래스는상대방으로부터전달된메시지를화면에뿌리는클래스입니다. exam/java/chapter09/tcp/simplechatserver.java 1: package exam.java.chapter09.tcp; 3: import java.io.datainputstream; 4: import java.io.dataoutputstream; 5: import java.io.ioexception; 6: import java.net.serversocket; 7: import java.net.socket; 8: 9: import javax.swing.joptionpane; 10: 11: public class SimpleChatServer { 1 public static void main(string[] args) { 13: ServerSocket server = null; 14: int port = 7777; 15: 16: try { 17: server = new ServerSocket(port); 18: Receiver receiver = new Receiver(server); 19: 20: Sender sender = new Sender(port); 21: 2 Thread rt = new Thread(receiver); 23: Thread st = new Thread(sender); 24: 25: rt.start(); 26: st.start(); 27: }catch(ioexception e) { 28: System.out.println(e.getMessage()); 29: } 30: } 31: } 3 33: class Sender implements Runnable { 34: String ip = "127.0.0.1"; 35: int port; 36: 37: public Sender(int port) { 38: this.port = port; 39: } 40: 41: public void run() { 4 while(true) {

Java 자바야놀자 - 활용편 43: Socket socket = null; 44: DataOutputStream dos = null; 45: try { 46: String message = JOptionPane.showInputDialog(" 메시지를입력하세요."); 47: if(message==null) { 48: System.exit(0); 49: } 50: 51: socket = new Socket(ip, port); 5 dos = new DataOutputStream(socket.getOutputStream()); 53: 54: dos.writeutf(message); 55: System.out.println(" 보낸메시지 : " + message); 56: } catch(exception e) { 57: e.printstacktrace(); 58: } finally { 59: if(socket!=null) try{socket.close();}catch(exception e) {} 60: if(dos!=null) try{dos.close();}catch(exception e) {} 61: } 6 } 63: }//end run() 64: }//end Sender 65: 66: class Receiver implements Runnable { 67: ServerSocket server; 68: public Receiver(ServerSocket server) { 69: this.server = server; 70: } 71: public void run() { 7 while(true) { 73: Socket socket = null; 74: DataInputStream dis = null; 75: try { 76: socket = server.accept(); 77: dis = new DataInputStream(socket.getInputStream()); 78: 79: String message = dis.readutf(); 80: System.out.println(socket.getInetAddress() + ":" + message); 81: } catch(exception e) { 8 e.printstacktrace(); 83: } finally { 84: if(socket!=null) try{socket.close();}catch(exception e) {} 85: if(dis!=null) try{dis.close();}catch(exception e) {} 86: } 87: } 88: }//end run() 89: }//end Receiver

Chapter 네트워크프로그래밍 2 상대방에게전달하고싶은메시지를입력한다음확인버튼을누르세요. 프로그램을종료하고싶으면취소버튼을누르세요. 29라인의아이피를수정하면실제상대방과대화를할수있습니다. 대화내용을콘솔화면에나타납니다. 이클립스에서실행하면 Console 탭에채팅내용이나타납니다.

Java 자바야놀자 - 활용편 2.2. UDP 네트워크프로그램 TCP/IP가연결중심의프로토콜이라면 UDP(User Datagram Protocol) 통신방식은 " 비신뢰적, 비연결지향형통신 " 이라고할수있습니다. TCP 통신과는달리우편과유사합니다. TCP에서는전화를사용하는것처럼메시지를순서대로보내고받을수있지만 UDP는보낸순서와받는순서가다를수있습니다. 또상대방의주소가잘못되면데이터가잘못전달되거나아예데이터를읽지못할수도있습니다. UDP는 DatagramSocket과 DatagramPacket이라는두개의클래스를지원합니다. 패킷은송신자의정보와메시지길이, 메시지등으로구성되는독립적인메시지단위입니다. 2.2.1. DatagramPacket DatagramPacket 에는다음네가지의생성자가있는데, 2 개는데이터를수신하는데사용 하고나머지 2 개는데이터를보내는데사용합니다. DatagramPacket(byte[] buf, int length) DatagramPacket(byte[] buf, int offset, int length) - UDP 패킷을수신할수있도록바이트배열을설정합니다. 생성자로사용되는바이트배열은비워두고, 읽을바이트의크기를설정합니다. 이때배열의크기보다작게지정합니다. DatagramPacket(byte[] buf, int length, InetAddress address, int port) DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) - 전송할수있도록 UDP 패킷을설정하는데사용합니다. 2.2.2. DatagramSocket DatagramSocket 은 UDP 패킷을읽고쓰는데사용합니다. 이클래스에는연결할포트와 인터넷주소를지정하는데사용하는세개의생성자를가지고있습니다. DatagramSocket() - 로컬호스트에서이용할수있는포트로연결합니다. DatagramSocket(int port) - 로컬호스트에서지정된포트로연결합니다. DatagramSocket(int port, InetAddress laddr) - 지정된주소의지정된포트번호로연결합니다.

Chapter 네트워크프로그래밍 2 다음프로그램은 UDP 방식을이용하여메신저프로그램을만든예입니다. exam/java/chapter09/udp/messenger.java 1: package exam.java.chapter09.udp; 3: import java.awt.*; 4: import java.awt.event.*; 5: import java.io.*; 6: import java.net.*; 7: 8: public class Messenger implements Runnable, ActionListener { 9: 10: private Frame f; 11: private TextArea outputarea; 1 private TextField addressfield, inputfield; 13: 14: private DatagramSocket server, client; 15: private DatagramPacket sindata, soutdata; 16: 17: private byte[] data = new byte[500]; 18: 19: public Messenger() { 20: try { 21: server = new DatagramSocket(8000); 2 client = new DatagramSocket(7000, InetAddress.getLocalHost()); 23: }catch(ioexception e) { 24: e.printstacktrace(); 25: } 26: } //end of constructor 27: 28: public static void main(string[] args) { 29: Messenger m = new Messenger(); 30: m.go(); 31: Thread t = new Thread(m); 3 t.start(); 33: } //end of main 34: 35: public void go() { 36: try { 37: f = new Frame(InetAddress.getLocalHost().getHostAddress()); 38: }catch(unknownhostexception e) { 39: e.printstacktrace(); 40: } 41: f.addwindowlistener(new WindowAdapter() { 4 public void windowclosing(windowevent e) { 43: System.exit(0); 44: } 45: }); 46: 47: outputarea = new TextArea();

Java 자바야놀자 - 활용편 48: outputarea.seteditable(false); 49: 50: addressfield = new TextField(); 51: inputfield = new TextField(); 5 53: inputfield.addactionlistener(this); 54: 55: Panel p1 = new Panel(); 56: p1.setlayout(new BorderLayout()); 57: p1.add(new Label("Address"), BorderLayout.WEST); 58: p1.add(addressfield, BorderLayout.CENTER); 59: 60: 61: 6 Panel p2 = new Panel(); 63: p2.setlayout(new BorderLayout()); 64: p2.add(new Label("Message"), BorderLayout.WEST); 65: p2.add(inputfield, BorderLayout.CENTER); 66: 67: f.add(p1, BorderLayout.NORTH); 68: f.add(outputarea, BorderLayout.CENTER); 69: f.add(p2, BorderLayout.SOUTH); 70: 71: f.setsize(300,200); 7 f.setvisible(true); 73: } //end of go 74: 75: public void actionperformed(actionevent e) { 76: String mssg = inputfield.gettext(); 77: String ip = addressfield.gettext(); 78: 79: outputarea.append(">> " + mssg+"\n"); 80: 81: InetAddress inet = null; 8 soutdata = null; 83: 84: try { 85: inet = InetAddress.getByName(ip); 86: 87: soutdata = new DatagramPacket(mssg.getBytes(), mssg.getbytes().length, inet, 8000); 88: 89: client.send(soutdata); 90: } catch(exception ex) { 91: ex.printstacktrace(); 9 } 93: 94: inputfield.settext(""); 95: 96: if(ip==null) {

Chapter 네트워크프로그래밍 2 97: try { 98: ip = InetAddress.getLocalHost().getHostName(); 99: }catch(unknownhostexception ex) { 100: ex.printstacktrace(); 101: } 10 } 103: } //end of actionperformed 104: 105: public void run() { 106: while(true) { 107: sindata = new DatagramPacket(data, data.length); 108: 109: try { 110: System.out.println("8000 번포트로대기중..."); 111: server.receive(sindata); 11 }catch(ioexception e) { 113: e.printstacktrace(); 114: } 115: 116: String addr = sindata.getaddress().gethostname(); 117: String rsvdata = new String(sinData.getData(), 0, sindata.getlength()); 118: 119: outputarea.append("[" + addr + "]" + rsvdata + "\n"); 120: } //end of while 121: } //end of run 12} //end of class

Java 자바야놀자 - 활용편 2.3. TCP 채팅프로그램 Ⅰ TCP 를이용하여채팅프로그램을만들어보겠습니다. 먼저채팅프로그램의원리를이해 하기위해다음의그림을설명하기로합니다. 약간복잡한그림으로이내용을프로그램으로옮겨도상당히복잡하기때문에그림을충 분히이해를한후프로그램을이해하시기바랍니다. a의 ChatServer는대화방 (chatting room) 을관리할수있는구조를갖습니다.( 물론이예제에서는단순하게대기실한곳에서 chatting을하도록구현했습니다. 이코드를더발전시키면방을만들수있을것입니다.) RoomManager라는클래스가방을관리하는데이를위해 Vector 클래스를사용하였습니다. 그다음 Room이라는클래스는대화방에속해있는대화자를관리하는데, 역시 Vector 클래스를통해관리합니다. c의 Chatter 클래스는대화자가접속하면인스턴스가서버에자동으로생성되며접속된대화자의모든정보를관리합니다. Chatter 클래스에는소켓을가지고있는데, 실제 ChatterClient(b) 의소켓과연결되어있습니다. ChatterClient가메시지를보내면, Chatter 클래스의소켓에전달되고, 이를기다리던스레드 (1) 는데이터를읽어서대화방에있는다른대화자에게메시지를전달하게되는것입니다. b의의 ChatClient는 2개의스레드가있습니다. 먼저 2의스레드는대화자로부터메시지를입력받습니다. 그런데키보드에서입력받고있는동안다른대화자가메시지를보내는것을수신하기위해스레드를이용해서해결해야합니다. 이는입력하는동안출력을담당하는스레드 (3) 가소켓을감시하면해결할수있습니다. 소켓에메시지가도착하면이를화면에출력하는데스레드를이용하지않는다면글을쓰는도중에상대방이보낸메시지를읽을수없을것입니다.

Chapter 네트워크프로그래밍 2 2.3.1. ChatServer.java 어려운코드는아니지만, 그렇게쉬운코드도아닙니다. 먼저 ChatServer 부터프로그램을 설명하기로하겠습니다. exam/java/chapter09/tcp/chatserver.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.net.*; 5: import java.util.*; 6: 7: public class ChatServer { 8: 9: public static void main(string [] args) { 10: 11: System.out.println("Chatting Server Starting."); 1 13: int portno = 5555; 14: 15: if (args.length == 1 ) { 16: portno = Integer.parseInt(args[0]); 17: } 18: 19: ChatManager cm= new ChatManager(portNo); 20: } 21: 2 } 앞의 ChatServer 프로그램이전부는아닙니다. 이부분은서버를실행시키기위해포트번 호를입력받고, 서버의모든대화를담당할 ChatManager 객체를만듭니다. 그리고 CharManager 의인자로서버의포트번호를명령행인자로받아넘겨줍니다. 이프로그램은다음에있는코드들을모두작성해야실행이가능합니다. 다음프로그램은채팅서버에접속하는채팅사용자클래스입니다. Chatter 클래스는실제 접속한대화자의정보를가지고있습니다. 23: class Chatter { 24: private Socket clientsocket; 25: private BufferedReader br; 26: private PrintWriter pw; 27: private ChatRoom chatroom; 28: private String chatterid; 29:

Java 자바야놀자 - 활용편 30: Chatter(ChatRoom chatroom, 31: Socket clientsocket, String chatterid ) { 3 System.out.println("Chatter 생성 : " + chatterid); 33: try { 34: this.chatroom = chatroom; 35: this.clientsocket = clientsocket; 36: this.chatterid = chatterid; 37: br = new BufferedReader(new InputStreamReader( clientsocket.getinputstream())); 38: pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter( clientsocket.getoutputstream()))); 39: (new readsocketthread()).start(); 40: } catch (Exception e) { 41: System.out.println(e.toString()); 4 } 43: } 44: public void sendmessage(string message) { 45: pw.println(message); 46: pw.flush(); 47: } 48: 49: class readsocketthread extends Thread { 50: String inputstring = null; 51: public void run() { 5 try { 53: while (true) { 54: inputstring = br.readline(); 55: chatroom.chateverychatter(inputstring); 56: } 57: } catch ( Exception e ) { 58: System.out.println(e.toString()); 59: } 60: } 61: } 6 } 49 라인에서는스레드를통해대화자가서버로전달하는메시지를감시합니다. 앞에서설 명한그림의 1 에해당됩니다. 다음프로그램은대화방에해당하는클래스입니다. 63: class ChatRoom { 64: private String roomname; 65: private Vector joinchatters = new Vector(); 66: private Chatter roommaker; 67: 68: ChatRoom(String roomname) { 69: System.out.println(" 채팅방개설 : " + roomname); 70: this.roomname = roomname;

Chapter 네트워크프로그래밍 2 71: this.roommaker = null; 7 } 73: 74: public synchronized void joinchatter(chatter chatter) { 75: joinchatters.add(chatter); 76: } 77: 78: public synchronized String getname() { 79: return roomname; 80: } 81: 8 public synchronized void chateverychatter(string message) { 83: for ( int i=0 ; i < joinchatters.size() ; i++) { 84: ((Chatter)joinChatters.get(i)).sendMessage(message); 85: } 86: } 87: 88: public int size() { 89: return joinchatters.size(); 90: } 91: 9 } 82 라인의 chateverychatter() 메서드는방안에있는모든대화자에게메시지를보낼때 사용합니다. 다음프로그램은대화방을관리하는클래스입니다. ChatRoomManager 클래스는생성과 동시에 " 대기실 " 을만듭니다. 93: class ChatRoomManager { 94: private Vector chatrooms = new Vector(); 95: 96: ChatRoomManager() { 97: System.out.println("ChatRoomManager Starting."); 98: chatrooms.add(new ChatRoom(" 대기실 ")); 99: } 100: 101: public void makeroom(string roomname) { } 10 103: public void deleteroom(string roomname) { } 104: 105: public void enterroom(string roomname, Socket clientsocket) { 106: Chatter chatter = null; 107: ChatRoom temproom = null; 108: boolean exitfor = false; 109: int i; 110: for(i=0; (exitfor == false)&&(i < chatrooms.size()); i++ ) { 111: temproom = (ChatRoom)chatRooms.get(i); 11 if (temproom.getname().equals(roomname)) {

Java 자바야놀자 - 활용편 113: chatter = new Chatter(tempRoom, clientsocket, String.valueOf(tempRoom.size() + 1)); 114: temproom.joinchatter(chatter); 115: exitfor = true; 116: } 117: } 118: } 119: 120: public void exitroom(chatter chatter) { } 121:} 105 라인의 enterroom() 메서드를통해, 현재존재하는모든대화방을찾아서해당대화 방을찾고그곳에 Chatter 를생성합니다. 이클래스는대화방을관리합니다. 다음코드는채팅서버를전체적으로관리하는클래스입니다. 12class ChatManager { 123: private int serverport; 124: private ServerSocket serversocket; 125: private ChatRoomManager chatroommanager; 126: 127: ChatManager(int serverport ) { 128: System.out.println("Chatting Manager Starting"); 129: 130: try { 131: this.serverport = serverport; 13 chatroommanager = new ChatRoomManager(); 133: serversocket = new ServerSocket(serverPort); 134: new listenerthread().start(); 135: } catch (Exception e) { 136: System.out.println(e.toString()); 137: } 138: } 139: 140: class listenerthread extends Thread { 141: private boolean stoplistener = false; 14 Socket clientsocket = null; 143: public void run() { 144: try { 145: while (!stoplistener ) { 146: System.out.println("Watting Client..."); 147: clientsocket = serversocket.accept(); 148: chatroommanager.enterroom(" 대기실 ",clientsocket); 149: System.out.println("Connection Established form:" + clientsocket.getinetaddress().gethostaddress()); 150: } 151: } catch (Exception e ) { 15 System.out.println(e.toString());

Chapter 네트워크프로그래밍 2 153: } 154: } 155: } 156:} 123라인의 ChatManager 클래스는 133라인에서 ServerSocket 객체를만듭니다. 그리고 134라인은 140라인에서선언된 ListenerThread라는내부클래스의객체를생성합니다. 140라인에선언된내부클래스가스레드클래스입니다. 따라서 start() 메서드를통해스레드가시작되면 run() 메서드는루프를돌면서클라이언트의접속을기다리다접속이이루어지면일반소켓을만든후, " 대기실 " 에 Chatter 클래스의객체를생성시키기위해 ChatRoomManager의 enterroom() 메서드를호출합니다. 그리고계속루프를돌면서다른클라이언트의접속을기다립니다. 복잡한내용을간단하게설명했는데이를근거로프로그램을자세히살펴보면서직접이해하기바랍니다. 물론이프로그램에는불필요한부분도있습니다. 그이유는 GUI 버전으로작성하기위해추가된부분이있기때문입니다. 따라서이코드를응용해서 GUI 용채팅애플리케이션을만들수도있습니다. 2.3.2. ChatClient.java 다음프로그램은채팅에필요한 ChatClient 의클래스입니다. exam/java/chapter09/tcp/chatclient.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.net.*; 5: 6: public class ChatClient { 7: 8: public static void main (String [] args) { 9: 10: String addr = "127.0.0.1"; 11: int portno = 5555; 1 13: if (args.length == 2 ) { 14: addr = args[0]; 15: portno = Integer.parseInt(args[1]); 16: } 17: 18: ChatterManager cm = new ChatterManager(addr, portno); 19:

Java 자바야놀자 - 활용편 20: } 21: } 2 클라이언트프로그램은비교적짧습니다. 8 라인의 main() 메서드에서 ChatterManager 의 객체를생성합니다. 이프로그램역시아래이어지는코드를모두작성해야실행이가능합니 다. 다음코드는 ChatterManager 클래스입니다. 이클래스가대부분의클라이언트채팅을담 당합니다. 23: class ChatterManager { 24: 25: private String serverip; 26: private int serverport; 27: private Socket clientsocket; 28: private BufferedReader br; 29: private PrintWriter pw; 30: private BufferedReader keyboard; 31: 3 ChatterManager(String serverip, int serverport) { 33: try { 34: 35: this.serverip = serverip; 36: this.serverport = serverport; 37: clientsocket = new Socket(serverIP, serverport); 38: 39: br = new BufferedReader( new InputStreamReader( clientsocket.getinputstream() )); 40: 41: pw = new PrintWriter(new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream()) )); 4 43: keyboard = new BufferedReader( new InputStreamReader(System.in, "KSC5601")); 44: 45: (new readsocketthread()).start(); 46: (new writesocketthread()).start(); 47: 48: } catch (Exception e) { 49: System.out.println(e.toString()); 50: } 51: } 5 32 라인의생성자에서는첫번째인자에서버의 IP 주소가전달되고, 두번째인자에서버 의포트번호가전달됩니다. 그리고 37 라인에서는서버에접속을시도합니다. 서버와의접

Chapter 네트워크프로그래밍 2 속이이루어지면 45 라인과 46 라인에서는 53 라인과 65 라인에있는스레드클래스의객체 를생성하고실행시킵니다. 다음스레드클래스는대화자가키보드에입력하는문자열을받아들입니다. 53: class readsocketthread extends Thread { 54: public void run() { 55: try { 56: while(true) { 57: System.out.println(br.readLine()); 58: } 59: } catch (Exception e) { 60: System.out.println(e.toString()); 61: } 6 } 63: } 64: 65: class writesocketthread extends Thread { 66: String inputstring = null; 67: public void run() { 68: try{ 69: while ((inputstring = keyboard.readline())!= null) { 70: pw.println(inputstring); 71: pw.flush(); 7 } 73: } catch (Exception e ) { 74: System.out.println(e.toString()); 75: } 76: } 77: } 78: } 65 라인의스레드는대화자가키보드를통해입력하는동안이라도소켓에메시지가도착하 면이를화면에출력하는역할을합니다.

Java 자바야놀자 - 활용편 2.4. TCP 채팅프로그램 Ⅱ 다음프로그램은데이터를이용한채팅예를보인것입니다. 화면인터페이스를 CUI 가아 닌 GUI 로작성했습니다. exam/java/chapter09/tcp/chatserver.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.net.*; 5: import java.util.*; 6: public class ChatServer { 7: Vector buffer; 8: ServerSocket serversocket; 9: Socket socket; 10: ObjectInputStream ois; 11: ObjectOutputStream oos; 1 13: public void service() { 14: try { 15: System.out.println(" 접속준비중 "); 16: serversocket = new ServerSocket(5555); 17: } catch (IOException e) { 18: System.err.println(" 서비스도중 IOException 발생!"); 19: } 20: 21: while(true) { 2 try { 23: socket = serversocket.accept(); 24: System.out.println(socket.getInetAddress()+" 접속!"); 25: ois = new ObjectInputStream(socket.getInputStream()); 26: oos = new ObjectOutputStream(socket.getOutputStream()); 27: Thread t = new Thread(new ChatServerThread(buffer,ois,oos)); 28: t.start(); 29: } catch (IOException e) { 30: System.err.println("IOException 발생!"); 31: } 3 } 33: } 34: public static void main(string args[]) { 35: System.out.println("Start Server Service..."); 36: ChatServer2 cs = new ChatServer2(); 37: cs.buffer = new Vector(5,1); 38: cs.service(); 39: } 40: } 다음프로그램은클라이언트하나에하나씩만들어질스레드입니다. 클라이언트가데이터

Chapter 네트워크프로그래밍 2 객체를보내면 Vector 에저장된 ObjectOutputStream 을이용해서알리게됩니다. 클라이 언트가종료되면스레드도함께종료됩니다. exam/java/chapter09/tcp/chatserverthread.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.util.*; 5: 6: public class ChatServerThread implements Runnable{ 7: Vector buffer; 8: ObjectInputStream ois; 9: ObjectOutputStream oos; 10: Data d; 11: boolean exit; 1 String name; 13: 14: public ChatServerThread(Vector v, ObjectInputStream ois, ObjectOutputStream oos) { 15: this.buffer = v; 16: this.ois = ois; 17: this.oos = oos; 18: exit = false; 19: } 20: 21: public void run() { 2 while(!exit) { 23: try { 24: d = (Data) ois.readobject(); 25: } catch (ClassNotFoundException e) { 26: System.err.println("Data class를찾을수없음!"); 27: } catch (OptionalDataException e1) { 28: System.err.println("OptionalDataException 발생!"); 29: } catch (IOException e3) { 30: System.err.println("IOExcdetion 이발생!"); 31: } 3 int state = d.getstate(); 33: if(state == Data. 접속종료 ) { 34: exit = true; 35: d.setmessage(" 님이종료하셨습니다."); 36: name = d.getname(); 37: broadcasting(); 38: for(int i = 0 ; i <buffer.size() ; i++) { 39: if( ((Data)buffer.elementAt(i)).getName().equals(name)) { 40: buffer.removeelementat(i); 41: break; 4 } 43: } 44: try{ ois.close(); 45: oos.close();

Java 자바야놀자 - 활용편 46: }catch(ioexception ex) {} 47: 48: } else if(state == Data. 처음접속 ) { 49: Vector username = new Vector(5,1); 50: d.setoos(oos); 51: buffer.addelement(d); 5 for(int i=0 ; i < buffer.size() ; i++) { 53: username.addelement(((data)buffer.elementat(i)).getname()); 54: } 55: d.setusername(username); 56: System.out.println("broadCasting 시작 "); 57: broadcasting(); 58: } else { 59: broadcasting(); 60: } 61: } 6 } 63: 64: public void broadcasting() { 65: Vector v = (Vector)buffer.clone(); 66: for(int i = 0 ; i < v.size() ; i++ ) { 67: try { 68: ((Data)v.elementAt(i)).getOOS().writeObject(d); 69: System.out.println("111"); 70: } catch (IOException e) { 71: System.err.println("broadCasting method 에서예외발생!"); 7 e.printstacktrace(); 73: } 74: } 75: } 76: } 다음프로그램은서버와클라이언트사이에정보를주고받기위한클래스의예를보인것 입니다. exam/java/chapter09/tcp/data.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.util.*; 5: 6: public class Data implements Serializable{ 7: private String message; 8: private String name; 9: private int state; 10: private transient ObjectOutputStream oos; 11: private Vector username; 1 public static final int 처음접속 = 0; 13: public static final int 접속종료 = -1; 14: public static final int 대화중 = 1; 15:

Chapter 네트워크프로그래밍 2 16: public Data (String name, String message, int state, ObjectOutputStream o) { 17: this.name = name; 18: this.message = message; 19: this.state = state; 20: this.oos = o; 21: } 2 public Data (String name, String message, int state) { 23: this(name, message, state, null); 24: } 25: public String getmessage() { 26: return message; 27: } 28: public void setmessage(string s) { 29: message = s; 30: } 31: public String getname() { 3 return name; 33: } 34: public void setname(string s) { 35: name = s; 36: } 37: public int getstate() { 38: return state; 39: } 40: public void setstate(int i) { 41: state = i; 4 } 43: public ObjectOutputStream getoos() { 44: return oos; 45: } 46: public void setoos(objectoutputstream o) { 47: oos = o; 48: } 49: public Vector getusername() { 50: return this.username; 51: } 5 public void setusername(vector v) { 53: this.username = v; 54: } 55: } 다음은클라이언트코드입니다. exam/java/chapter09/tcp/chatclient2.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.net.*; 5: import java.awt.*; 6: import java.awt.event.*; 7:

Java 자바야놀자 - 활용편 8: public class ChatClient2 { 9: Socket socket; 10: ObjectInputStream ois; 11: ObjectOutputStream oos; 1 13: Thread t; 14: 15: Frame first, second; 16: Label state, commlabel, userlabel, serverlabel; 17: Label IDLabel, usercount; 18: TextArea commlist; 19: List userlist; 20: Button conn, transmission; 21: TextField statetextfield, transtextfield; 2 TextField servertextfield, IDTextField; 23: 24: String name; 25: ChatClientThread cct; 26: 27: public void connection(string servername, int port) throws IOException{ 28: socket = new Socket(serverName,port); 29: System.out.println(serverName + " 에접속!"); 30: 31: oos = new ObjectOutputStream(socket.getOutputStream()); 3 ois = new ObjectInputStream(socket.getInputStream()); 33: System.out.println("OutputStream 을열었습니다. "); 34: Data d = new Data(IDTextField.getText()," 님이접.", Data. 처음접속 ); 35: System.out.println("Stream 연결에성공하였습니다."); 36: oos.writeobject(d) ; 37: 38: System.out.println("InputStream 을열었습니다. "); 39: 40: cct = new ChatClientThread(ois,this); 41: t = new Thread(cct); 4 t.start(); 43: } 44: 45: 46: /** 47: * 처음보여질 GUI화면 48: * Server 의이름과 User 의 ID를받아들여서, 49: * Connection() 메서드를호출합니다. 50: */ 51: public void firstgo() { 5 first = new Frame("Chat Browser"); 53: first.addwindowlistener( new WindowAdapter() { 54: public void windowclosing(windowevent e) { 55: first.setvisible(false); 56: first.dispose(); 57: System.exit(1);

Chapter 네트워크프로그래밍 2 58: } 59: }); 60: 61: Panel p = new Panel(); 6 p.setlayout(new GridLayout(2,2)); 63: serverlabel = new Label("Server",Label.CENTER); 64: IDLabel = new Label(" I D ",Label.CENTER); 65: servertextfield = new TextField(0); 66: IDTextField = new TextField(0); 67: p.add(serverlabel); 68: p.add(servertextfield); 69: p.add(idlabel); 70: p.add(idtextfield); 71: 7 conn = new Button(" 연결 "); 73: conn.addactionlistener( new ActionHandler()); 74: first.add(p,"center"); 75: first.add(conn,"south"); 76: first.setsize(300,100); 77: 78: /* 79: * 화면의중앙에 GUI가보여질수있도록합니다. 80: * 현재의 Screen Size 을얻어온후중앙에 Dispaly 합니다. 81: */ 8 Dimension d = first.gettoolkit().getscreensize(); 83: first.setlocation(d.width/2 - first.getwidth()/2, d.height/2 - first.getheight()/2); 84: first.setresizable(false); 85: first.setvisible(true); 86: } 87: 88: /** 89: * 두번째로보여질 GUI Chatting 에필요한 TextField 와 90: * 현재접속되어있는사용자의이름, 91: * 그리고대화내용이 Display 될화면입니다. 9 */ 93: public void secondgo() { 94: second = new Frame("Chat v1.0 second"); 95: second.addwindowlistener(new WindowAdapter() { 96: public void windowclosing(windowevent e) { 97: frameclose(e); 98: } 99: }); 100: state = new Label(" 접속중..."); 101: state.setbackground(color.yellow); 10 state.setforeground(color.blue); 103: second.add(state,"north"); 104: 105: Panel p1 = new Panel(); 106: p1.setlayout(new BorderLayout());

Java 자바야놀자 - 활용편 107: commlabel = new Label(" 대화내용 "); 108: commlist = new TextArea(); 109: commlist.seteditable(false); 110: p1.add(commlabel,"north"); 111: p1.add(commlist,"center"); 11 113: Panel p2 = new Panel(); 114: p2.setlayout(new BorderLayout()); 115: userlabel = new Label(" 사용자명 ",Label.CENTER); 116: userlist = new List(); 117: usercount = new Label("",Label.CENTER); 118: p2.add(userlabel,"north"); 119: p2.add(userlist,"center"); 120: p2.add(usercount,"south"); 121: 12 Panel p3 = new Panel(); 123: transtextfield = new TextField(50); 124: //transtextfield.requestfocus(); // TextField 에커서가깜박이게합니다. 125: transtextfield.addactionlistener(new ActionHandler()); 126: transmission = new Button(" 전송 "); 127: transmission.addactionlistener(new ActionHandler()); 128: p3.add(transtextfield); 129: p3.add(transmission); 130: 131: second.add(p3,"south"); 13 second.add(p1,"center"); 133: second.add(p2,"west"); 134: second.setsize(600,500); 135: Dimension d = second.gettoolkit().getscreensize(); 136: second.setlocation(d.width/2 - second.getwidth()/2, d.height/2 - second.getheight()/2); 137: second.setresizable(false); 138: 139: second.setvisible(true); 140: } 141: 14 public void frameclose(windowevent e) { 143: Frame f = (Frame) e.getsource(); 144: f.setvisible(false); 145: f.dispose(); 146: cct.exit = true; 147: try { 148: oos.writeobject(new Data(name," 님이나가셨습니다.", Data. 접속종료 )); 149: oos.close(); 150: } catch (IOException e1) { 151: System.err.println(" 종료중 IOExcpetion 이발생!"); 15 } 153: System.exit(0); 154: } 155:

Chapter 네트워크프로그래밍 2 156: /** 157: * Acrtion Event를처리하는 Inner class입니다. 158: */ 159: public class ActionHandler implements ActionListener{ 160: public void actionperformed(actionevent e) { 161: String actioncommand = e.getactioncommand(); 16 if(actioncommand.equals(" 연결 ")) { 163: String server = servertextfield.gettext(); 164: name = IDTextField.getText(); 165: first.setvisible(false); 166: first.dispose(); 167: secondgo(); 168: try { 169: connection(server,5555); 170: } catch (IOException e1) { 171: System.err.println("Connection 중 Exception 이발생하였습니다."); 17 } 173: state.settext("[ " + server +" ]" + " 에접속됨. UserID : " + name); 174: } else if ( actioncommand.equals(" 전송 ") e.getsource().equals(transtextfield)) { 175: try { 176: oos.writeobject(new Data(name,transTextField.getText(), Data. 대화중 )); 177: } catch (IOException e2) { 178: System.err.println(" 대화중 IOException 이발생하였습니다 "); 179: } 180: transtextfield.settext(""); 181: } 18 } 183: } 184: 185: public static void main(string args[]) { 186: ChatClient2 cc = new ChatClient2(); 187: cc.firstgo(); 188: } 189:}//end class exam/java/chapter09/tcp/chatclientthread.java 1: package exam.java.chapter09.tcp; 3: import java.io.*; 4: import java.util.*; 5: 6: public class ChatClientThread implements Runnable{ 7: ObjectInputStream ois; 8: ChatClient2 cc; 9: Data d; 10: boolean exit = false; 11:

Java 자바야놀자 - 활용편 1 public ChatClientThread(ObjectInputStream ois, ChatClient2 cc) { 13: this.ois = ois; 14: this.cc = cc; 15: } 16: 17: public void run() { 18: while(!exit) { 19: try { 20: d = (Data) ois.readobject(); 21: } catch (IOException e) { 2 System.err.println("run method IOException"); 23: } catch (ClassNotFoundException e1) { 24: System.err.println("Data class NotFound"); 25: } 26: int state = d.getstate(); 27: String name = d.getname(); 28: if(state == Data. 처음접속 ) { 29: Vector username = d.getusername(); 30: cc.userlist.removeall(); 31: for(int i = 0 ; i < username.size() ; i++) { 3 cc.userlist.add((string)username.elementat(i)); 33: } 34: cc.usercount.settext(" 현재 " + cc.userlist.getitemcount() + 35: " 명접속중 "); 36: } else if (state == Data. 접속종료 ) { 37: cc.userlist.remove(name); 38: cc.usercount.settext(" 현재 " + cc.userlist.getitemcount() + 39: " 명접속중 "); 40: } 41: cc.commlist.append("[ " + name + " ]" + d.getmessage() + "\n"); 4 } 43: try { 44: ois.close(); 45: } catch (IOException e) { 46: System.err.println(" ChatClientThread 에의 ObjectOutputStream 을 Close하는중에 IOException 발생!"); 47: } 48: }//end run 49: } 채팅서버에접속하기위한클라이언트시작화면입니다. 서버의아이피와대화자의아이디 를입력합니다.

Chapter 네트워크프로그래밍 2 다음그림은클라이언트대화화면입니다.

Java 자바야놀자 - 활용편 2.5. TCP 파일서버프로그램 다음프로그램은간단한파일서버프로그램의예를보인것입니다. 서버로부터특정파일을 읽어클라이언트화면에서버의파일내용을출력합니다. exam/java/chapter09/tcp/fileserver.java 1: package exam.java.chapter09.tcp; 3: import java.awt.*; 4: import java.net.*; 5: import java.io.*; 6: 7: public class FileServer { 8: 9: public static void main(string[] args) { 10: ServerSocket s = null; 11: Socket s1; 1 byte[] intbuf = new byte[100]; 13: String filename; 14: 15: try { 16: s = new ServerSocket(4321, 1); 17: } catch (IOException e) { 18: System.out.println("\nServer timed out!"); 19: System.exit(-1); 20: } 21: 2 while(true) { 23: try { 24: s1 = s.accept(); 25: filename = getfilename(s1); 26: sendfiletoclient(s1, filename); 27: s1.close(); 28: } catch(ioexception e) { 29: System.out.println("Error - " + e.tostring()); 30: } 31: } 3 } 33: 34: public static String getfilename(socket s1) throws IOException { 35: InputStream s1in; 36: DataInputStream d1in; 37: String sfile; 38: s1in = s1.getinputstream(); 39: d1in = new DataInputStream(s1in); 40: sfile = d1in.readline(); 41: System.out.println("File to open for reading : " + sfile);

Chapter 네트워크프로그래밍 2 4 return(sfile); 43: } 44: 45: public static void sendfiletoclient (Socket s1, String sfile) throws IOException { 46: int c; 47: FileInputStream fis; 48: OutputStream s1out; 49: s1out = s1.getoutputstream(); 50: File f = new File(sfile); 51: 5 if(f.exists()!= true) { 53: String error = new String ("File " + sfile + " 은 ( 는 ) 존재하지않습니다.\n"); 54: int len = error.length(); 55: for(int i=0; i<len; i++) { 56: s1out.write((int)error.charat(i)); 57: } 58: System.out.println(error); 59: return; 60: } 61: 6 if(f.canread()) { 63: fis = new FileInputStream(sfile); 64: System.out.println("Sending : " + sfile); 65: while((c=fis.read())!= -1) { 66: s1out.write(c); 67: } 68: fis.close(); 69: } else { 70: String error = new String ("Can't open " + sfile + "for reading...\n"); 71: int len = error.length(); 7 for(int i=0; i<len ; i++) { 73: s1out.write((int)error.charat(i)); 74: } 75: System.out.println(error); 76: } 77: } 78: } 다음은클라이언트측코드입니다. exam/java/chapter09/tcp/fileclient.java 1: package exam.java.chapter09.tcp; 3: import java.net.*; 4: import java.io.*; 5: 6: import javax.swing.joptionpane; 7:

Java 자바야놀자 - 활용편 8: public class FileClient { 9: 10: public static void main(string[] args) { 11: Socket s; 1 String server = JOptionPane.showInputDialog(" 서버의주소를입력하세요."); 13: String filename = JOptionPane.showInputDialog(" 파일명을입력하세요."); 14: int port = 4321; 15: 16: try{ 17: s = new Socket (server, port); 18: sendfilename (s,filename); 19: receivefile (s); 20: s.close(); 21: } catch (IOException e) { 2 System.out.println("Connection failed"); 23: } 24: } 25: 26: public static void sendfilename (Socket s, String filename) throws IOException { 27: OutputStream sout; 28: DataOutputStream dout; 29: 30: sout = s.getoutputstream(); 31: dout = new DataOutputStream(sOut); 3 String sendstring = new String(fileName + "\n"); 33: dout.writebytes(sendstring); 34: } 35: 36: public static void receivefile(socket s) throws IOException { 37: int c; 38: InputStream sin; 39: sin = s.getinputstream(); 40: 41: while ((c=sin.read())!= -1) { 4 System.out.print((char)c); 43: } 44: } 45: }

Chapter 네트워크프로그래밍 2 2.6. 요점정리 1. TCP 네트워크프로그래밍소켓과소켓사이의입출력서버 serversocket = new ServerSocket(5432); socket = serversocket.accept(); 클라이언트 socket = new Socket("127.0.0.1", 5432);