( 분산통신실습 1) : 소켓 (Sockets) 소켓 : 저수준패킷스트림전송 유닉스소켓 (cseunix.incheon.ac.kr 211.119.245.68 에서프로그램 ) inettime 소스코드참조 ( 실습 ) 시간을 10회반복하여출력하도록프로그램을수정하세요. ( 과제 1-1) 유닉스채팅프로그램채팅서버가임의의클라이언트가채팅에참가하는요청을하면이를채팅참가자리스트에추가하며채팅에참가하고있는클라이언트들이보내오는메시지를모든채팅참가자에게다시방송하는기능을수행해주는 chat_server.c와 chat_client.c 인터넷채팅프로그램을실행하고분석해보고, 이채팅프로그램에채팅참가자목록을보여주는?who 명령을추가하세요. 자바소켓 시간 (Time-of-Day) 서버소스코드참조 ( 실습a) 시간을 10회반복하여출력하도록프로그램을수정하세요. ( 실습b) 유닉스 inettime 클라이언트와혼합해서 inettime 서비스를실행해보세요. ( 과제 1-2) 자바응용채팅프로그램 JavaChatServer.java와 JavaChatClient.java 및 JavaChatClient.html 자바애플릿채팅프로그램을 inettime과같은자바응용채팅프로그램으로수정하세요. 윈도우소켓 (winsock) ( 실습 ) 유닉스소켓 chat 프로그램을윈도우소켓 chat 프로그램으로변경하세요. ( 과제1-3) 윈도우소켓talk프로그램유닉스 talk 프로그램의 winsock 버전을작성하세요. http://marvel.incheon.ac.kr/ 의 Information의 Unix의 Socket Programming 참조 1.1
Sockets host X (146.86.5.20) socket (146.86.5.2/1625) web server (161.25.19.8) socket (161.25.19.8/80) 1.2
inettime.c: 인터네트시간청취 #include <stdio.h> #include <signal.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> /* For AFINET sockets */ #include <arpa/inet.h> #include <netdb.h> #define DAYTIME_PORT 13 /* Standard port no */ #define DEFAULT_PROTOCOL 0 unsigned long promptforinetaddress (); unsigned long nametoaddr (); main () int clientfd; /* Client socket file descriptor */ int serverlen; /* Length of server address structure */ int result; /* From connect () call */ struct sockaddr_in serverinetaddress; /* Server address */ struct sockaddr* serversockaddrptr; /* Pointer to address */ unsigned long inetaddress; /* 32-bit IP address */ /* Set the two server variables */ serversockaddrptr = (struct sockaddr*) &serverinetaddress; 1.3
inettime.c: 인터네트시간청취 (cont.) serverlen = sizeof (serverinetaddress); /* Length of address */ while (1) /* Loop until break */ inetaddress = promptforinetaddress (); /* Get 32-bit IP */ if (inetaddress == 0) break; /* Done */ /* Start by zeroing out the entire address structure */ bzero ((char*)&serverinetaddress,sizeof(serverinetaddress)); serverinetaddress.sin_family = AF_INET; /* Use Internet */ serverinetaddress.sin_addr.s_addr = inetaddress; /* IP */ serverinetaddress.sin_port = htons (DAYTIME_PORT); /* Now create the client socket */ clientfd = socket (AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL); do /* Loop until a connection is made with the server */ result = connect (clientfd,serversockaddrptr,serverlen); if (result == -1) sleep (1); /* Try again in 1 second */ while (result == -1); readtime (clientfd); /* Read the time from the server */ close (clientfd); /* Close the socket */ exit (/* EXIT_SUCCESS */ 0); 1.4
inettime.c: 인터네트시간청취 (cont.) unsigned long promptforinetaddress () char hostname [100]; /* Name from user: numeric or symbolic */ unsigned long inetaddress; /* 32-bit IP format */ /* Loop until quit or a legal name is entered */ /* If quit, return 0 else return host's IP address */ do printf ("Host name (q = quit, s = self): "); scanf ("%s", hostname); /* Get name from keyboard */ if (strcmp (hostname, "q") == 0) return (0); /* Quit */ inetaddress = nametoaddr (hostname); /* Convert to IP */ if (inetaddress == 0) printf ("Host name not found n"); while (inetaddress == 0); unsigned long nametoaddr (name) char* name; char hostname [100]; struct hostent* hoststruct; /* /usr/include/netdb.h */ struct in_addr* hostnode; /* Convert name into a 32-bit IP address */ /* If name begins with a digit, assume it's a valid numeric */ /* Internet address of the form A.B.C.D and convert directly */ if (isdigit (name[0])) return (inet_addr (name)); 1.5
inettime.c: 인터네트시간청취 (cont.) if (strcmp (name, "s") == 0) /* Get host name from database */ gethostname (hostname,100); printf ("Self host name is %s n", hostname); else /* Assume name is a valid symbolic host name */ strcpy (hostname, name); /* Now obtain address information from database */ hoststruct = gethostbyname (hostname); if (hoststruct == NULL) return (0); /* Not Found */ /* Extract the IP Address from the hostent structure */ hostnode = (struct in_addr*) hoststruct->h_addr; /* Display a readable version for fun */ printf ("Internet Address = %s n", inet_ntoa (*hostnode)); return (hostnode->s_addr); /* Return IP address */ readtime (fd) int fd; char str [200]; /* Line buffer */ printf ("The time on the target port is "); while (readline (fd, str)) /* Read lines until end-of-input */ printf ("%s n", str); /* Echo line from server to user */ 1.6
inettime.c: 인터네트시간청취 (cont.) readline (fd, str) int fd; char* str; /* Read a single NEWLINE-terminated line */ int n; do /* Read characters until NULL or end-of-input */ n = read (fd, str, 1); /* Read one character */ while (n > 0 && *str++!= ' n'); return (n > 0); /* Return false if end-of-input */ 1.7
Time-of-Day: Server.java import java.net.*; public class Server public Server() // create the socket the server will listen to try s = new ServerSocket(5155); catch (java.io.ioexception e) System.out.println(e); System.exit(1); // OK, now listen for connections System.out.println("Server is listening..."); try while (true) client = s.accept(); // create a separate thread // to service the request c = new Connection(client); c.start(); catch (java.io.ioexception e) System.out.println(e); public static void main(string args[]) Server timeofdayserver = new Server(); private ServerSocket s; private Socket client; private Connection c; 1.8
Time-of-Day: Connection.java import java.net.*; import java.io.*; public class Connection extends Thread public Connection(Socket s) outputline = s; public void run() // getoutputstream returns an OutputStream object // allowing ordinary file IO over the socket. try // create a new PrintWriter with automatic flushing PrintWriter pout = new PrintWriter(outputLine.getOutputStream(), true); // now send a message to the client pout.println("the Date and Time is " + new java.util.date().tostring()); try Thread.sleep(1500); catch (Exception e) private Socket // now close the socket outputline.close(); catch (java.io.ioexception e) System.out.println(e); outputline; 1.9
Time-of-Day: Client.java import java.net.*; import java.io.*; public class Client public Client() try Socket s = new Socket("127.0.0.1",5155); InputStream in = s.getinputstream(); BufferedReader bin = new BufferedReader(new InputStreamReader(in)); System.out.println(bin.readLine()); s.close(); catch (java.io.ioexception e) System.out.println(e); System.exit(1); public static void main(string args[]) Client client = new Client(); 1.10
talk & chat Winsock versions 윈도우소켓 (Window socket) 은유닉스에서사용되는 BSD 소켓을계승하기때문에윈속에서사용되는대부분의함수와구조체는유닉스버전과동일하다. 그러나윈속을사용하기전에유닉스와달리윈속라이브러리를초기화해주고사용이끝나면해제를시켜줘야한다. 초기화 : WSAStartup, 해제 : WSACleanup talk_client, talk_server 유닉스버전 : 키보드입력과데이터수신처리를 fork 를이용해서분기 윈도우버전 : 키보드입력은메인에서, 데이터수신처리는쓰레드를이용 chat_client, chat_server 유닉스버전 : select 를사용하여데이터 I/O 를비동기적으로처리, 키보드입력은 fork 를이용 윈도우버전 : I/O 방식은쓰레드에서 select 를사용, 키보드입력은메인에서처리 1.11
( 분산통신실습 2) RMI RMI 익히기 1. 분산환경에서동작하는 message-passing 을이용한 boundedbuffer 해법프로그램을실행해보세요. 소스코드 : ftp://211.119.245.153 -> os -> OSJavaSources -> ch15 -> rmi http://marvel el.incheon.ac.kr 의 Information Unix RMI 참조 2. 또, 이예제가웹상에서수행될수있도록수정해보세요. 즉클라이언트프로그램에서이예제의 Producer 와 Consumer 의동작을모니터링하는 Java applet 을작성해보는것입니다. Appletviewer 또는넷스케이프커뮤니케이터로실행 3. BONUS: Java synchronization 을이용한 bounded-buffer 해법 ( 운영체제교재 Applied Operating System Concepts 7 장 p209 참조 ) 이분산환경에서도동작할수있도록 RMI 를이용하여수정해보세요. 실습방법 cseblade.incheon.ac.kr(211.119.245.68) 의 /mysung/2003osreport 디렉토리에자기학번디렉토리를만들고소스프로그램과실행파일을옮겨놓으세요. 1.12
RMI (Remote Method Invocation) RPC 의 Java 버전 저수준 (low-level) 소켓을이용하지않고원격객체의메소드를호출할수있는방법을제공하는객체지향언어인 Java 기반의분산컴퓨팅환경 ( 클라이언트 / 서버지원 ) 을위한미들웨어 (RPC 와유사 ) 스레드 (thread) 가원격객체 (Remote Object) 의메소드 (method) 호출 다른 Java Virtual Machine 상에있는객체는 원격 객체 RPC 보다좋은점 객체지향적이다. 프로그램작성및사용이쉽다. 안전하고보안성이있다. 기존시스템과통합해서사용할수있다. 작성절차 원격인터페이스를정의한다. 원격인터페이스를구현 (implement) 하는원격객체 ( 서버 ) 를작성한다. 원격객체를이용하는프로그램 ( 클라이언트 ) 을작성한다. stub 와 skeleton 클래스를생성한다. rmiregistry 를실행시킨다. 서버와클라이언트를실행시킨다. 1.13
RMI (Remote Method Invocation) 1.14
RMI (Remote Method Invocation) RPC versus RMI RPC : Procedural Programming Style RMI : Object-Oriented Programming Style RPC 의매개변수 : Ordinary Data Structures RMI 의매개변수 : Objects Stubs and Skeletons Stub 클라이언트에상주하는원격객체의대리인 (proxy) 매개변수들을 Marshalls ( 메소드이름과인자들의꾸러미생성 ) 해서서버로보냄 Skeleton 서버에상주 매개변수를 Unmarshalls 해서서버에전달함 매개변수 Marshall 된매개변수가 Local (Non-Remote) Objects 이면객체를바이트스트림으로기록해주는객체순서화 (Object Serialization) 기법을이용해서복사에의해 (by Value) 전달 Marshall 된매개변수가 Remote Objects 이면참조에의해 (by Reference) 전달 : RMI 의장점 Remote objects java.rmi.remote 를확장한 Interface 로선언되어야함 extends java.rmi.remote 모든메소드는 java.rmi.remoteexception 을발생시켜야함 throws java.rmi.remoteexception 1.15
Marshalling Parameters 1.16
RMI 프로그램예제 원격인터페이스구현 MessageQueueImpl.java MessageQueue.java javac server MessageQueueImpl.class MessageQueueImpl_skel.class rmic MessageQueueImpl_stub.class Factory.java Producer.java Consumer.java javac Factory.class client 1.17
구성 RMI 프로그램예제 원격인터페이스 : MessageQueue.java 서버프로그램 : MessageQueueImpl.java 클라이언트프로그램 : Factory.java, Producer.java, Consumer.java Policy File : New with Java 2 grant ; permission java.net.socketpermission "*:1024-65535","connect,accept"; 1.18
RMI 프로그램예제 실행순서 1. 모든소스파일컴파일 # javac MessageQueue.java MessageQueueImpl.java Factory.java Producer.java Consumer.java 2. rmic 로 stub 와 skeleton class 파일생성 # rmic MessageQueueImpl 3. 레지스트리서비스시작 (rmiregistry) osagent 또는 rpcbind 디몬에해당 # rmiregistry & (Unix) 또는 C: > start rmiregistry (Windows) 4. 원격서버객체의인스턴스생성 (JDK 1.2 이상버전에서는인증해주어야함 ) # java -Djava.security.policy=java.policy MessageQueueImpl (JDK 1.2 이상 ) 또는 # java MessgeQueueImpl (JDK 1.1) 5. 클라이언트에서원격객체실행시작 # java -Djava.security.policy=java.policy Factory (JDK.2 이상 ) 또는 # java Factory (JDK 1.1) 1.19
RMI 프로그램예제 서버 : MessageQueue interface import java.util.*; import java.rmi.*; public interface MessageQueue extends java.rmi.remote /* * This implements a non-blocking send */ public void send(object item) throws java.rmi.remoteexception; /* * This implements a non-blocking receive */ public Object receive() throws java.rmi.remoteexception; 1.20
RMI 프로그램예제 서버 : MessageQueueImpl.java (1) import java.util.*; import java.rmi.*; public class MessageQueueImpl extends java.rmi.server.unicastremoteobject implements MessageQueue public MessageQueueImpl() throws RemoteException queue = new Vector(); // This implements a non-blocking send public synchronized void send(object item) throws RemoteException queue.addelement(item); System.out.println("Producer entered " + item + " size = " + queue.size()); 1.21
RMI 프로그램예제 서버 : MessageQueueImpl.java (2) // This implements a non-blocking receive public synchronized Object receive() throws RemoteException Object item; if (queue.size() == 0) return null; else item = queue.firstelement(); queue.removeelementat(0); System.out.println("Consumer removed " + item + " size = " + queue.size()); return item; 1.22
RMI 프로그램예제 서버 : MessageQueueImpl.java (3) public static void main(string args[]) System.setSecurityManager(new RMISecurityManager()); try MessageQueue server = new MessageQueueImpl(); Naming.rebind("//127.0.0.1/MessageServer", server); //Naming.rebind("rmi://media.inchon.ac.kr/MessageServer", server); System.out.println("Server Bound"); catch(exception e) System.err.println(e); private Vector queue; 1.23
RMI 프로그램예제 클라이언트 : Factory.java (1) import java.util.*; import java.rmi.*; public class Factory public Factory() // remote object MessageQueue mailbox; System.setSecurityManager(new RMISecurityManager()); // install a security manager try //get a reference to the remote object mailbox = (MessageQueue)Naming.lookup( //127.0.0.1/MessageServer"); //(MessageQueue)Naming.lookup("rmi://media.inchon.ac.kr/MessageServer"); // now create the producer and consumer threads Producer producerthread = new Producer(mailBox); Consumer consumerthread = new Consumer(mailBox); producerthread.start(); consumerthread.start(); catch (Exception e) System.err.println(e); 1.24
RMI 프로그램예제 클라이언트 : Factory.java (2) // producer and consumer will call this to nap public static void napping() int sleeptime = (int) (NAP_TIME * Math.random() ); try Thread.sleep(sleepTime*1000); catch(interruptedexception e) public static void main(string args[]) Factory client = new Factory(); private static final int NAP_TIME = 5; 1.25
RMI 프로그램예제 클라이언트 : Producer.java import java.util.*; class Producer extends Thread public Producer(MessageQueue m) mbox = m; public void run() Date message; while (true) Factory.napping(); // produce an item & enter it into the buffer message = new Date(); try mbox.send(message); System.out.println( Producer Produced + message); catch (Exception e) System.err.println(e); private MessageQueue mbox; 1.26
RMI 프로그램예제 클라이언트 : Consumer.java import java.util.*; class Consumer extends Thread public Consumer(MessageQueue m) mbox = m; public void run() Date message; while (true) Factory.napping(); // consume an item from the buffer try message = (Date)mbox.receive(); if (message!= null) // Consume the item System.out.println( Consumer Consumed + message); catch (Exception e) System.err.println(e); private MessageQueue mbox; 1.27