<1> <Contents Delivery Programming> Contents Delivery Programming 2009 년 2 학기 숙명여자대학교정보과학부 멀티미디어과학전공 윤용익 yiyoon@sookmyung.ac.kr
<2> <Contents Delivery Programming> 강의목차 1 주 : 강의소개및 Part 1- Contents Delivery Programming 개요 2 주 ~ 4 주 : Part 2- Internal IPC Programming (Unix 위주 : C) 5주 ~ 7주 : Part 3 - Socket Programming g( (Unix 위주 : C ) 8 주 : 중간프로젝트발표 9 주 ~ 10 주 : Part 4 - Socket Programming (Java) 11 주 : Part 5 - RPC Programming (Unix 위주 ) 12 주 ~ 14 주 : Part 6 - RMI Programming (Java) 15 주 : 기말고사 (Term 프로젝트발표 ) 12 월 8 일 : Term 프로젝트발표 12 월 10 일 : 기말고사
<3> <Contents Delivery Programming> 강의교재 주및부교재 W. R. Stevens, Unix Network Programming, Prentice-Hall, 1999 년이전판 Unix IPC (Ch 3), RPC (Ch 18), Socket programming (Ch 6) W. R. Stevens, Unix Network Programming Vol. 1, Prentice-Hall, 1999. Socket Programming (Part 2 And Part 3) W. R. Stevens, Unix Network Programming Vol. 2, Prentice-Hall, 1999. Unix IPC and RPC programming 최재영외 2 인, 프로그래머를위한 Java 2, 홍릉과학출판사 Java Socket (10 장 ), RMI(12 장 )
<4> <Contents Delivery Programming>
<5> <Contents Delivery Programming> Part 1 Overview of Contents t Delivery Programming
<6> <Contents Delivery Programming> 1. 본과목의이해 Contents Delivery System? Contents Delivery Network? Client / Server Model? Information Infrastructure Internet? TCP/IP Network Programming? TCP/IP Reference Model Contents Delivery Programming?
<7> <Contents Delivery Programming> 1.1 TCP/IP Reference Model 네트워크프로그래밍의계층별분류
<8> <Contents Delivery Programming> 1.1.1 계층별분류와특징 계층 응용계층 예 http CORBA RPC 특징 이미작성된유틸리티활용 개발, 변경, 운영의편리 트랜스포트계층 Socket Winsock 패킷단위의송수신처리 인터넷프로그램의기초 디바이스드라이버계층 Packet Driver NDIS, ODI MAC 프레임단위의송수신 흐름제어, 오류제어가없음
<9> <Contents Delivery Programming> 1.1.2 TCP/IP 내부구조
<10> <Contents Delivery Programming> 1.2 클라이언트 - 서버통신모델 서버 : 서비스제공 클라이언트 : 서버가제공하는서비스를이용하는장비와이에필요한프로그램 서버가먼저실행 클라이언트가요구 (request) 를보내면서버가이에대한응답 (response) 를보내준다
<11> <Contents Delivery Programming> Isolated Single-user Architecture Application 1 Application n Data Base Application 1 Application n Data Base
<12> <Contents Delivery Programming> Client/Server Architecture (1) Server Platform Netw work Service App 1 Service App 2 Service App n Data Base
<13> <Contents Delivery Programming> Client/Server Architecture (2)
<14> <Contents Delivery Programming> Spectrum of Client/Server Definitions Presentation Application i Data management Network Presentation Presentation Processing Logic Business Processing Logic Data Processing Logic DBMS Database
<15> <Contents Delivery Programming> Application Tasks in C/S User Interface what the user actually sees Presentation logic what happens when the user interacts with the form on the screen Application logic Data requests and results acceptance Data integrity such as validation, i security, completeness Physical data management such as update m retrieval, deletion, and addition
<16> <Contents Delivery Programming> Client/Server Components: Role of Client (1) Client Server Presentation logic Application logic. Application Logic. Data Access Logic Presentation logic Application logic
<17> <Contents Delivery Programming> Client/Server Components: Role of Client (2) Definition: The client is any application/function/launcher/requester process The client extends the user s workplace Access to remote functions and data Communication i with other peer processes Resource sharing as required The client allows the user to personalize the workplace Custom interface design Hardware/software rightsized to requirements Sense of ownership The client hides complexity of underlying infrastructure Network, operating system, and data access are hidden User has a common syntax and lexicon across all application s A client may also be a server concurrently
<18> <Contents Delivery Programming> Client/Server Components: Role of Server (1) Client Server Presentation logic Application logic. Application Logic. Data Access Logic Presentation logic Application logic
<19> <Contents Delivery Programming> Client/Server Components: Role of Server (2) Definition: The server is a specialized responder to requests That is, the server is a process The server implements specific functions Access to data, services, custom applications May provide some aspects of presentation Servers can be arranged in a variety of configurations Tiered, star, network New servers can be implemented with minimal impact Multiple servers may exist on the same hardware platform Servers may exist on a variety of hardware/software platforms Not restricted to microcomputers A server may also be a client concurrently
<20> <Contents Delivery Programming> Client/Server Types S E R V E R Network Data 관리 Application Presentation Presentation Data 관리 Application Presentation Data 관리 Application Application Presentation Data 관리 Application Presentation Data 관리 Network Data 관리 Application Presentation C L I E N T Distributed Presentation Remote Presentation Distributed Function Remote Data Management Distributed Data Management
<21> <Contents Delivery Programming> Part 2 Interprocess Communication (Internal IPC in UNIX)
<22> <Contents Delivery Programming> Concurrent Processing Environment Objective of IPC Synchronization between processes Semaphore: allowable waiting queue wait and wakeup function: P & V operation Mutual Exclusion between processes Monitor Region : critical section <-- semaphore Communication between processes Buffer : Mailbox, message queue Signal : Socket
<23> <Contents Delivery Programming> Interprocess Communication 의개념 단일컴퓨터시스템상에서의두프로세스간 IPC 서로다른컴퓨터시스템상에서의두프로세스간 IPC user process user process user process user process kernel kernel kernel Client-Server Model 의예 filename stdin filename file contents or error message stdout Client file contents or error message Server file
<24> <Contents Delivery Programming> Unix Internal IPC Summary of Unix IPC system calls include file system call to create or open system call for control operations system calls for IPC operations Message queue Semaphore Shared memory <sys/msg.h> msgget msgctl msgsnd msgrcv <sys/sem.h> semget semctl semop <sys/shm.h> shmget shmctl shmat shmdt kernel 은각 IPC channel 에대해서도 file 을다루기위한정보와비슷한정보의구조를갖음 <sys/ipc.h> 에정의 struct ipc_perm { ushort uid; /*owner's user id */ 이구조를사용하고변경하기위해서는 ushort gid: /* owner's group id */ 세가지의 ctl system call 을사용 ushort cuid; /* creator's user id */ ushort cgid; /* creator's group id */ 하나의 IPC channel을만들거나열기위해사용 ushort mode; /* access modes */ ushort seq; /* slot usage sequence number */ key_t key; /* key */ };
<25> <Contents Delivery Programming> User Space User 1 User 2 Process I Process j send receive msg msg Kernel (OS) Space IPC Handler IPC channel 1 IPC channel 2 copy MS for IH copy id addr id addr IPC channel i msg id addr id addr IPC channel n IPC channel : means of MQ, SM, Sema, Port
<26> <Contents Delivery Programming> Three get system calls take a key value return integer key value msgget semget shmget IPC_CREAT IPC_EXCL IPC_PRIVATE IPC_PERM
<27> <Contents Delivery Programming> Logic for opening or creating an IPC channel Start here OK: create new entry and return ID yes yes Error return flag == IPC_PRIVATE? PRIVATE? System tables full? errno = ENOSPC no yes no no Does key already exist? IPC_CREAT set? Error return yes errno = ENOENT Are both IPC_CREAT yes Error return and IPC_EXCL set? errno = EEXIST no Is the access permission no Error return OK? errno = EACCESS yes OK: return ID
<28> <Contents Delivery Programming> Message queue structure in kernel msqid_ds() Next Next Type = 200 Length =1 Length =2 msg_first data data Next Type = 300 msgid Key_value Type = 100 msg_last Length =3 data
<29> <Contents Delivery Programming> Message queues(1) system 내의각 message queue 에대해서 kernel 은다음과같은정보구조를유지 #include <sys/types.h> yp #include <sys/ipc.h> /* defines the ipc_perm structure */ struct msqid_ds { struct ipc_perm msg_perm; /* operation permission struct */ struct msg *msg_first; /* ptr to first message on q */ struct msg *msg_last; /* ptr to last message on q */ ushort msg_cbytes; /* current # bytes on q */ ushort msg_qnum; /* current # of messages on q */ ushort msg_qbytes; /* max # of bytes allowed on q */ ushort msg_lspid; /* pid of last msgsnd */ ushort msg_lrpid; /* pid of last msg rcv */ time_t msg_stime; /* time of last msgsnd */ time_t msg_rtime; /* time of last msgrcv */ time_t msg_ctime; /* time of last msgctl (that changed the above) */ };
<30> <Contents Delivery Programming> Message queues(2) msgget system call - 새로운 message queue 을만들거나기존의 message queue 에접근 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflag); - msgflag : 다음상수들의조합 Numeric Symbolic Description 0400 0200 0040 0020 0004 0002 MSG_R MSG_W MSG_R >> 3 MSG_W >> 3 MSG_R >> 6 MSG_W >> 6 IPC_CREAT IPC_EXCL Read by owner Write by owner Read by group Write by group Read by world Write by world
<31> <Contents Delivery Programming> Message queues(3) msgsnd system call - message queue에 message 하나를넣음 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid,, struct msgbuf *ptr,, int length,, int flag); - ptr : struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[1]; /* message data */ }; - length : message 의길이 (byte 단위 ) - flag : IPC_NOWAIT나 0으로지정 * IPC_NOWAIT : message queue에새로운 message를위한여유공간이없을경우에즉시 system call에서돌아오도록함
<32> <Contents Delivery Programming> Message queues(4) msgrcv system call - message queue에서 message를읽음 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgrcv(int msqid,, struct msgbuf *ptr,, int length,, long msgtype, gyp, int flag); - ptr : msgsnd와에서와비슷하며받은 message를저장할장소를명시 - length : ptr이지시하는구조의 data부분의크기를명시 - msgtype : queue 로부터어떤 message 를요구하는지를명시 * msgtype = 0, queue의첫번째 message를받음 * msgtype > 0, msgtype과동일한 type을갖는첫번째 message를받음 * msgtype < 0, msgtype 의절대치보다같거나작은 type 중에서가장작은 type을갖는첫번째 message를받음 - flag : 요구된 type의 message가 queue에없을경우에어떻게할것인지를명시 * MSG_NOERROR 설정시, 받은 message의 data 부분이 length보다크다면즉시 data 부분을자르고 error없이복귀함
<33> <Contents Delivery Programming> Message queues(5) msgctl system call - message queue 에대한다양한제어기능을제공 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> * cmd : IPC_RMID는 message queue를제거하는것으로여기서는이것만사용 int msgctl(int msqid, int cmd, struct msqid_ds *buff); Multiplexing Messages - 각 message마다관련된 type을갖는목적 : 다수의 process들이하나의 queue에서 message들을다중화할수있도록하기위해서 client 1 pid = 123 client 2 pid = 456 client 3 pid = 789 type = 1 type = 123 type = 1 type = 456 type = 1 type = 789 message queue type = 1 type = 123 or 456 or 789 server
<34> <Contents Delivery Programming> Msgget(KEY) --> msg_id Client Y Msg 생성 : msg.type, msg.content msgsnd(msg_id, msg, length) Msg.type = x Msg.type =y MQ: Uniq_ID -> KEY(msg_id) Msg type #x msg msg Msg type #y msg Msg type #z msg Msg.type = x Msg.type =z Client Z Msg.type = x server Msg.type =y Msg.type =z Msgget(KEY) --> msg_id Msg 공간확보 msgrcv(msg_id, &msg, type, length)
<35> <Contents Delivery Programming> client Msg_type = x Sending module MQ : msg_id <-- uniq_key Msg.type = #x msg msg Msg.type = #y Msg.type = #z msg msg Msg_id = msgget(key) msg 생성 : - msg 의공간 ( 영역 ) 할당 - 보낼내용을작성 -> msg 복사 -msg type을정의 - msg 길이 Msgsnd(msg_id, msg.type, msg.content, length) Msg_type = x server Receiving module msg_id = msgget(key) msg 를받을공간확보받을 msg 의 type 설정, 길이설정 Msgrcv(msg_id, &mbuf, length, type, flag)
<36> <Contents Delivery Programming> Client i Sending module... Receiving module Msg_type = x Msg_type = y MQ : msg_id <-- uniq_key Msg.type = #x msg msg Msg.type = #y msg Msg.type = #z msg server Receiving module... Msg_type = x Msg_type = z Client j Sending module Msg_type = x Msg_type = y or Msg_type = z Receiving Sending module... module
<37> <Contents Delivery Programming> client Sending module... Receiving module Msg_type = x Msg-id1 Msg-id2 MQ : msg_id1 <-- MKEY1 Msg.type = #x msg Msg.type = #y msg Msg.type = #z msg MQ : msg_id2 <-- MKEY2 Msg.type = #x msg Msg.type = #y msg Msg.type = #z msg Msg_type = x server Receiving module Msg-id1... Sending module Msg-id2
<38> <Contents Delivery Programming> For(;;) Sending module KEY For(;;) receiving module receiving module Sending module Client server
<39> <Contents Delivery Programming> For(;;) Sending module receiving module For(;;) receiving module Sending module
<40> <Contents Delivery Programming> 두개의 Message queue를사용하는 client-server의예제 (1) msgq.h Server 를위한 main 함수 #include <sys/types.h> #include "msgq.h" #include <sys/ipc.h> #include <sys/msg.h> main() { #include <sys/errno.h> int extern int errno; #define MKEY1 1234L #define MKEY2 2345L readid, writeid; /* * Create the message queues, if required. */ #define PERMS 0666 if ( (readid = msgget(mkey1, PERMS IPC_CREAT)) < 0) err_sys("server: can't get message queue 1"); if ( (writeid = msgget(mkey2, PERMS IPC_CREAT)) < 0) err_sys("server: can't get message queue 2"); server(readid, writeid); } exit(0);
두개의 Message queue를사용하는 client-server의예제 (2) () <41> <Contents Delivery Programming> Client 를위한 main 함수 #include main() { "msgq.h" int readid, writeid; /* * Open the message queues. The server must have * already created them. */ if ( (writeid = msgget(mkey1, 0)) < 0) err_sys("client: can't msgget message queue 1"); if ( (readid = msgget(mkey2, 0)) < 0) err_sys("client: can't msgget message queue 2"); client(readid, writeid); } /* * Now we can delete the message queues. */ if (msgctl(readid, IPC_RMID, (struct msqid_ds *) 0) < 0) err_sys("client: can't RMID message queue 1"); if (msgctl(writeid, IPC_RMID, (struct msqid_ds *) 0) < 0) err_sys( sys("client: can't RMID message queue 2"); exit(0);
두개의 Message queue를사용하는 client-server의예제 (3) () <42> <Contents Delivery Programming> mesg.h /* * Definition of "our" message. * * You may have to change the 4096 to a smaller value, if message queues * on your system were configured with "msgmax" less than 4096. */ #define MAXMESGDATA (4096-16) /* we don't want sizeof(mesg) > 4096 */ #define MESGHDRSIZE (sizeof(mesg) - MAXMESGDATA) /* length of mesg_len and mesg_type */ typedef struct { int mesg_len; /* #bytes in mesg_data, can be 0 or > 0 */ long mesg_type; /* message type, must be > 0 */ char mesg_data[maxmesgdata]; } Mesg;
두개의 Message queue를사용하는 client-server의예제 (4) () <43> <Contents Delivery Programming> mesg_send 함수 #include "mesg.h" /* * Send a message using the System V message queues. * The mesg_len, mesg_type and mesg_data fields must be filled * in by the caller. */ mesg_send(id, mesgptr) int id; /* really an msqid from msgget() */ Mesg *mesgptr; { /* * Send the message - the type followed by the optional data. */ } if (msgsnd(id, (char *) &(mesgptr->mesg_type), mesgptr->mesg_len, 0)!= 0) err_sys("msgsnd error");
두개의 Message queue를사용하는 client-server의예제 (5) () <44> <Contents Delivery Programming> mesg_rcv 함수 #include "mesg.h" /* * Receive a message from a System V message queue. * The caller must fill in the mesg_type field with the desired type. * Return the number of bytes in the data portion of the message. * A 0-length data message implies end-of-file. */ int mesg_recv(id, mesgptr) int id; /* really an msqid from msgget() */ Mesg *mesgptr; { int n; } /* * Read the first message on the queue of the specified type. */ n = msgrcv(id, (char *) &(mesgptr->mesg_type), MAXMESGDATA, mesgptr->mesg_type, 0); if ( (mesgptr->mesg_len = n) < 0) err_dump("msgrcv error"); return(n); /* n will be 0 at end of file */
하나의 Message queue를사용하는 client-server의예제 (1) () <45> <Contents Delivery Programming> Server program #include #include #include Mesg main() { <stdio.h> "mesg.h" "msgq.h" mesg; int id; } /* * Create the message queue, if required. */ if ( (id = msgget(mkey1, PERMS IPC_CREAT)) < 0) err_sys("server: can't get message queue 1"); server(id); exit(0);
하나의 Message queue를사용하는 client-server의예제 (2) () <46> <Contents Delivery Programming> server(id) int { id; int n, filefd; char errmesg[256], *sys_err_str(); str(); /* * Read the filename message from the IPC descriptor. */ mesg.mesg_type = 1L; /* receive messages of this type */ if ( (n = mesg_recv(id, &mesg)) <= 0) err_sys("server: filename read error"); mesg.mesg_data[n] = ' 0'; /* null terminate filename */ mesg.mesg_type = 2L; /* send messages of this type */ if ( (filefd = open(mesg.mesg_data, 0)) < 0) { /* * Error. Format an error message and send it back * to the client. */ sprintf(errmesg, ": can't open, %s n", sys_err_str()); strcat(mesg.mesg_data, errmesg); mesg.mesg_len = strlen(mesg.mesg_data); mesg_send(id, &mesg);
하나의 Message queue를사용하는 client-server의예제 (3) () <47> <Contents Delivery Programming> } else { } /* * Read the data from the file and send a message to * the IPC descriptor. */ while ( (n = read(filefd, mesg.mesg_data, MAXMESGDATA)) > 0) { mesg.mesg_len = n; mesg_send(id, send(id &mesg); } close(filefd); if (n < 0) err_sys("server: read error"); } /* * Send a message with a length of 0 to signify the end. */ mesg.mesg_len = 0; mesg_send(id, &mesg);
하나의 Message queue를사용하는 client-server의예제 (4) () <48> <Contents Delivery Programming> Client program #include <stdio.h> #include "mesg.h" #include "msgq.h" Mesg main() { mesg; int id; /* * Open the single message queue. The server must have * already created it. */ if ( (id = msgget(mkey1, 0)) < 0) err_sys("client: can't msgget message queue 1"); client(id); } /* * Now we can delete the message queue. */ if (msgctl(id, IPC_RMID, (struct msqid_ds ds *) 0)< 0) err_sys("client: can't RMID message queue 1"); exit(0);
하나의 Message queue를사용하는 client-server의예제 (5) () <49> <Contents Delivery Programming> client(id) int { } id; int n; /* * Read the filename from standard input, write it as * a message to the IPC descriptor. */ if (fgets(mesg.mesg_data, MAXMESGDATA, stdin) == NULL) err_sys( sys("filename read error"); n = strlen(mesg.mesg_data); if (mesg.mesg_data[n-1] == ' n') n--; /* ignore the newline from fgets() */ mesg.mesg_data[n] = ' 0'; /* overwrite newline at end */ mesg.mesg_len = n; mesg.mesg_type = 1L; /* send messages of this type */ mesg_send(id, &mesg); /* * Receive the message from the IPC descriptor and write * the data to the standard output. */ mesg.mesg_type = 2L; /* receive messages of this type */ while( (n = mesg_recv(id, &mesg)) > 0) if (write(1, mesg.mesg_data, n)!= n) err_sys( sys("data write error"); if (n < 0) err_sys("data read error");
<50> <Contents Delivery Programming> Semaphores(1) semaphore - 동기화의기본 - 다수의 process들의작업을동기화하기위해서사용 - 주로사용하는곳은 shared memory segment 에의접근을동기화하기위함 시스템내의모든 semaphore의집합에대해 kernel은다음과같은구조를유지 #include <sys/types.h> #include <sys/ipc.h> /* defines the ipc_perm structure */ struct semid_ds { struct ipc_perm sem_perm; /* operation permission struct */ struct sem *sem_base; /* ptr to first semaphore in set */ ushort sem_nsems; /* # of semaphores in semop */ time_t sem_otime; /* time of last semop */ time_t sem_ctime; /* time of last change */ }; * struct sem { ushort semval; /* semaphore value, nonnegative */ short sempid; /* pid of last operation */ ushort semncnt; /* # awaiting semval > cval */ ushort semzcnt; /* # awaiting semval = 0 */ };
<51> <Contents Delivery Programming> Semaphores(2) semget system call - semaphore 를만들거나기존의 semaphore 에접근 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflag); - nsems : semaphore 의수 - semflag : 다음상수들의조합 Numeric Symbolic Description 0400 0200 0040 0020 0 0004 0002 SEM_R SEM_W SEM_R >> 3 SEM SM_W >> 3 SEM_R >> 6 SEM_W >> 6 IPC_CREAT IPC_EXCL Read by owner Write by owner Read by group Write by group Read by world Write by world
<52> <Contents Delivery Programming> Semaphores(3) semop system call - 집합내의하나또는그이상의 semaphore 값들에대해연산을수행 - opsptr : #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf **opsptr, unsigned int nops); struct sembuf { ushort sem_num; /* semapore # */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }; - sem_op : sem_op > 0 : sem_val 의값이 semaphore 의현재값에더해짐이것은 semaphore 가제어하는자원들의해제에해당 sem_op = 0 : 호출한 process 는 semaphore 의값이 0 이될때까지기다리기를원함 sem_op < 0 : 호출한 process 는 semaphore 의값이 sem_op 의절대값보다크거나같아질때까지기다린다. 이것은자원의할당에해당
<53> <Contents Delivery Programming> Semaphores(4) semctl system call - semaphore 에대한다양한제어연산들을제공 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, union semun arg); union semun { int val; /* used for SETVAL only */ struct semid_ds *buff; /* used for IPC_STAT and IPC_SET */ ushort *array; /* used for IPC_GETALL & IPC_SETALL */ } arg; - cmd : IPC RMID 는 semaphore 를제거하기위해사용 cmd : IPC_RMID 는 semaphore 를제거하기위해사용 GETVAL 은 semaphore 값을가져오기위해사용 SETVAL 은명시된 semaphore 값으로바꾸기위해사용
<54> <Contents Delivery Programming> Semaphores 를사용한예제 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define SEMKEY 123456L /* key value for semget() */ #define PERMS 0666 static struct sembuf op_lock[2] = { 0, 0, 0, /* wait for sem#0 to become 0 */ 0, 1, 0 /* then increment sem#0 by 1 */ }; static struct sembuf op_unlock[1] = { 0, -1, IPC_NOWAIT /* decrement sem#0 by 1 (sets it to 0) */ }; int semid = -1; /* semaphore */ my_lock(fd) int fd; { if (semid < 0) } if ( (semid = semget(semkey, 1, IPC_CREAT PERMS)) < 0) err_sys("semget error"); if (semop(semid, &op_lock[0], 2) < 0) err_sys("semop _y( lock error"); my_unlock(fd) int fd; { if (semop(semid, &op_unlock[0], 1)< 0) err_sys("semop unlock error); }
<55> <Contents Delivery Programming> Shared Memory(1) Client-Server 화일복제프로그램에사용되는통상적인몇가지단계를고려해보자. server가입력화일에서읽는다. 이러한동작은보통 kernel이데이타를자신의내부 block buffer 중의하나로읽어들이고, 이것을 server 의 buffer 로복제하는두가지동작으로이루어진다. server는 pipe, FIFO, message queue 등의기법중에하나를사용하여이러한 data 를 message 안에쓸수있다. 이러한세가지 IPC 형태의어느것이나데이타가 user의 buffer로복제하여야한다. client는 IPC channel에서데이타를읽는데이때, 다시데이타를 kernel의 IPC buffer 에서 client 의 buffer 로복제하여야한다. 마지막으로데이타는 system call write 의두번째독립변수인 client 의 buffer 에서출력화일로복제된다. 전체적으로데이타를네번복제하는것이필요 이러한네번의복제는 kernel 과사용자 process 간에서행해진다. - 이러한복제를 intercontext copy 라고한다.
<56> <Contents Delivery Programming> Shared Memory(2) client 와 server 사이에서의전형적인데이타이동 client server output file FIFO, pipe or message input file kernel 이러한 IPC 형태 (pipe, FIFO, message queue) 와관련된문제 - 두프로세스가가정보를교환하기위해서정보가 kernel e 을거쳐가야한다. shared memory - 두개이상의프로세스가기억장소의일부를공유하도록해서이러한문제를해결
<57> <Contents Delivery Programming> Shared Memory(3) shared memory 를이용한 Client-Server 화일복제프로그램에서의몇가지단계 server 는 semaphore 를사용하여 shared memory segment 로접근한다. server 는입력화일을 shared memory segment 로읽어들인다. 읽어들일주소는 shared memory 를가리킨다. 읽기가완료되면일꾼은다시 semaphore 를사용하여 client에게알린다. client 는 shared memory segment 에서출력화일로데이타를쓴다. shared memory 를이용한 client와 server간의데이타이동 client shared memory server output file input file kernel
<58> <Contents Delivery Programming> Shared Memory(4) 모든 shared memory segment 에대해서 kernel 은다음과같은정보구조를유지 #include <sys/types.h> yp #include <sys/ipc.h> /* defines the ipc_perm structure */ struct shmid_ds { struct ipc_perm shm_perm; /* operation permission struct */ int shm_segsz; /* segment size */ struct XXX shm_yyy; /* implementation dependent info */ ushort shm_lpid; /* pid of last operation */ ushort shm_cpid; /* creator pid */ ushort shm_nattch; /* current # attached */ ushort shm_cnattch; /* in-core # attached */ time_t shm_atime; /* last attach time */ time_t shm_dtime; /* last detach time */ time_t shm_ctime; /* last change time */ };
<59> <Contents Delivery Programming> Shared Memory(5) shmget system call - shared memory segment 를생성하거나기존의것에접근 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, int size, int shmflag); - return value : shared memory 식별자 shmid - nsems : semaphore 의수 - semflag : 다음상수들의조합 Numeric Symbolic Description 0400 0200 0040 0020 0004 0002 SHM_R SHM_W SHM_R >> 3 SHM_W >> 3 SHM_R >> 6 SHM_W >> 6 IPC_CREAT IPC_EXCL Read by owner Write by owner Read by group Write by group Read by world Write by world
<60> <Contents Delivery Programming> Shared Memory(6) shmat system call - shared memory segment 를 attach 시킴 #include <sys/types.h> y/yp #include <sys/ipc.h> #include <sys/shm.h> int shmat(int shmid, char *shmaddr, int shmflag); - return value :shared memory segment의 address -shared memory의 address를결정하는규칙 : shmaddr = 0 : system은호출한프로세스를위한주소를선정 shmaddr <> 0 : 돌려주는주소는호출프로세스가 shmflag 독립변수로 shmdt system call - shared memory segment 를 detach 시킴 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmdt(char *shmaddr); SHM_RND 값을명시했는지여부에따라다르다.
<61> <Contents Delivery Programming> Shared Memory(7) shmctl system call - shared memory segment 를제거시킴 (cmd 값으로 IPC_RMID 를명시 ) #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); shm.h #include "mesg.h" #define NBUFF 4 /* number of buffers in shared memory */ /* (for multiple buffer version */ #define SHMKEY ((key_t) 7890) /* base value for shmem key */ #define SEMKEY1 ((key_t) 7891) /* client semaphore key */ #define SEMKEY2 ((key_t) 7892) /* server semaphore key */ #define PERMS 0666
<62> <Contents Delivery Programming>
<63> <Contents Delivery Programming> Part 3 Socket Programming (Unix 기반 )
<64> <Contents Delivery Programming> 유닉스소켓시스템콜 BSD 소켓 API 의소개 IP 주소변환설명 소켓을이용한클라이언트및서버프로그램작성방법 소개 유닉스시스템콜 signal() 과 fork() 소개 토크프로그램작성
<65> <Contents Delivery Programming> 소켓의정의 TCP/IP 를이용하는 API 1982 년 BSD(Berkeley Software Distribution) 유닉스 4.1 윈도우소켓 ( 윈속 ), 자바소켓등도 TCP/IP 를이용하기 위한 API 를제공
<66> <Contents Delivery Programming> 소켓 소켓소개 IP 어드레스와포트, 소켓의관계
<67> <Contents Delivery Programming> Berkeley socket UNIX system 을위하여가장많이보급되고있는두가지통신 API - Berkeley socket - System V TLI(Transport Layer Interface) -C programming g language g 를위하여개발 Network I/O 는 File I/O 보다더욱상세하고많은선택사항들을필요로한다. - 망연결을초기화하기위해서프로그램은자신의역할이어떤것인지알아야 한다. - 망연결은연결지향형또는비연결형이될수있다. - 이름은화일운용에대해서보다망에있어서더욱중요하다. - 망연결에필요한매개변수들은 file I/O 보다많다. { 규약, 지역주소, 지역프로세스, 상대주소, 상대프로세스 } - 몇몇통신규약에서레코드경계는중요하다. - 망접속은다수의통신규약을지원해야한다.
<68> <Contents Delivery Programming> Berkeley Socket( 계속 ) socket, TLI, Messages, FIFOs Server: allocate space t_alloc() Sockets TLI Messages FIFOs create endpoint socket() t_open() msgget() mknod() bind address bind() t_bind() specify queue listen() wait for connection accept() t_listen() get new fd t_open() Client: allocate space t_alloc() open() create endpoint socket() t_open() msgget() open() bind address bind() t_bind() connect to server connect() t_connect() transfer data datagrams terminate read() write() recv() send() read() write() t_rcv() t_snd() msgrcv() msgsnd() recvfrom() t_rcvudata( sendto() ) t_sndudata( ) read() write() close() t_close() msgctl() close() shutdown() t_sndrel() t_snddis() unlink()
<69> <Contents Delivery Programming> C 언어에서 TCP 소켓프로그램작성 connection-oriented protocol
<70> <Contents Delivery Programming> Java 에서 TCP 소켓프로그램작성
<71> <Contents Delivery Programming> Berkeley Socket( 계속 ) connectionless protocol 에대한 socket system calls Server (connectionless protocol) socket() bind() recvfrom() blocks until data received from a client data (request) Client socket() bind() sendto() process request write() data (reply) recvfrom()
<72> <Contents Delivery Programming> Java 에서 DatagramSocket 자바 UTP 프로그램작성
<73> <Contents Delivery Programming> 소켓번호 소켓개설시리턴되는값 기술자테이블 (descriptor table) 에위치
<74> <Contents Delivery Programming> 소켓번호 (Cont d)
<75> <Contents Delivery Programming> 소켓의개설 소켓을이용한데이터송수신시필요한정보 1. 프로토콜 (TCP or UDP) 2. 자신의 IP 주소 3. 자신의포트번호 4. 상대방의 IP 주소 5. 상대방의포트번호
<76> <Contents Delivery Programming> 소켓의개설 (Cont d) 소켓시스템콜 #include <sys/socket.h> It Int socket kt( int domain, /* 프로토콜체계 */ int type, /* 서비스타입 */ int protocol ); /* 프로토콜 */
<77> <Contents Delivery Programming> 소켓의개설 (Cont d) Domain PF_INET / AF_INET PF_INET6 / AF_INET6 PF_UNIX / AF_UNIX PF : Protocol Family, AF: Address Family Sockaddr / sockaddr_in의구조체 Type SOCK_STREAM SOCK_DGRAM SOCK_RAW Protocol 0( 자동적으로프로토콜이선택되어진다 )
<78> <Contents Delivery Programming> 1. 소켓구조체 소켓의구조 * 네트워크를통하여다른컴퓨터와통신을하기위해서는위와같은다양한속성의설정이필요하기때문에, 이후등장할여러가지속성간의특징파악이필요
<79> <Contents Delivery Programming> 소켓의구조 2. Family - 지원하는프로토콜그룹중에서사용하려는소켓이적용될프로토콜을선택
<80> <Contents Delivery Programming> 3. Type 소켓의구조 - 연결지향형과비연결형, 저수준프로토콜제어형 - 저수준프로토콜 IP 프로토콜과같은레벨에있는프로토콜을사용시필요 ex) ICMP (Internet Control Message Protocol) TCP/UDP 보다하위계층으로사용이까다로운반면직접적인제어가가능 4. Protocol 여러소켓형태를제공하는경우사용, 기본값은 0
<81> <Contents Delivery Programming> 소켓의타입 1. Stream Socket - 연결지향형 (TCP 기반 ) - 소켓간의연결후데이터전송 - 일상생활의전화개념과유사 2. Datagram Socket - 비연결형 (UDP 기반 ) - 송수신시도착지주소필수 - 일상생활의편지개념과유사 3. Raw Socket - 저수준프로토콜액세스 - ICMP, OSPF 등이사용 -IP 계층이용
<82> <Contents Delivery Programming> 예제 : 소켓생성 open_socket.c 예제 int fd1, sd1; fd1 = open( /etc/passwd, O_RDONLY, 0); sd1 = socket(pf_inet, SOCK_STREAM, 0); printf( File Descriptor %d\n, fd1); printf( Socket Descriptor %d\n, sd1); close(fd1); close(sd1); 실행결과 File Descriptor = 3 Socket Descriptor = 4
<83> <Contents Delivery Programming> 기본자료구조 (1)
<84> <Contents Delivery Programming> 기본자료구조 (2) 1. sockaddr 구조체 - 기본적인소켓주소구조체 - 호환성을위해존재 - 변수 : 구조체의크기, Family Type, 소켓의주소데이터 2. sockaddr_in 구조체 - IPv4 소켓주소구조체 - 주소를담기위해 in_addr 구조체사용 - 변수 : 구조체의크기, Family Type, 소켓의주소및포트번호 3. sockaddr_un 구조체 - 유닉스소켓주소구조체 - 동일호스트에서의통신이일반 TCP 통신보다두배빠름 - 변수 : 소켓상수, 호스트경로
<85> <Contents Delivery Programming> 소켓주소구조체 struct sockaddr { u_short sa_family; /* address family */ char sa_data[14]; /* 주소 */ } struct in_addr { u_long s_addr; /* 32bit IP 주소 */ } struct sockaddr_ in { short sin_family; /* 주소체계 */ u_short sin_port; /* 16bit 포트번호 */ struct in_addr sin_addr; /* 32bit IP 주소 */ char sin_zero[8]; /* dummy */ }
<86> <Contents Delivery Programming> 소켓주소구조체 (Cont d) sockaddr_ in 구조체를사용 sockaddr 과의호환성을위해 dummy 삽입 sin_family AF_INET AF_UNIX AF_NS 인터넷주소체계유닉스파일주소체계 XEROX 주소체계
<87> <Contents Delivery Programming> Socket Address 많은 BSD network system call 은독립변수로서 socket address 구조의지시자를필요로한다. - 이구조의정의는 <sys/socket.h> 에있다. struct sockaddr { u_short sa_family; /* address family: AF_xxx value */ char sa_data[14]; /* up to 14 bytes of protocol-specific address */ }; 14 byte의 protocol-specific address의내용은 address의 type에따라서해석 Internet family 에대하여다음구조가 <netinet/in.h> 에정의 struct in_addr { u_ short s_ addr; /* 32-bit netid/hostid */ }; struct sockaddr_in { short sin_family; /* AF_INET */ u_short sin_port; /* 16-bit port number */ /* network byte ordered */ struct in_addr sin_addr; /* 32-bit netid/hostid */ /* netowrk byte ordered */ char sin_zero[8]; /* unused */ };
<88> <Contents Delivery Programming> Socket Address( 계속 ) <sys/types.h> 에정의된 unsigned data type C Data type 4.3 BSD System V unsigned char unsigned short unsigned int unsigned long u_char u_short u_int u_long unchar ushort uint ulong Internet, XNS, Unix family 에대한 socket address 구조 struct sockaddr_in family 2-byte port 4-byte net ID, host ID (unused) struct sockaddr_ns family 4-byte net ID 6-byte host ID 2-byte port (unused) struct sockaddr_un family pathname (up to 108 bytes)
<89> <Contents Delivery Programming> 네트워크프로그래밍을위한함수 1. 시스템호출함수의개요 2. 소켓관련함수 3. 소켓옵션관련함수 4. 동시처리를위한함수
<90> <Contents Delivery Programming> 1. 시스템호출함수의개요 - 시스템콜이란개발의편의를위해운영체제의고유기능을호출하는것 - 동작매커니즘 1. 필요에의해시스템함수호출 2. 제어권한이동 ( 어플리케이션 > 시스템호출인터페이스 > 운영체제 ) 3. 운영체제내부모듈이호출에대한처리를진행 4. 제어권한이동 ( 운영체제 > 시스템호출인터페이스 > 어플리케이션 )
<91> <Contents Delivery Programming> 2. 소켓관련함수 1. 소켓함수를이용한클라이언트 / 서버의구조
<92> <Contents Delivery Programming> 2. 소켓관련함수 socket system call - 원하는통신 protocol(internet TCP, Internet UDP, XNS SPP 등 ) 의 type 을지정 Syntax int socket (int family, int type, int protocol); #include <sys/types.h> #include ld <sys/socket.h> kth> socket system call int socket (int family, int type, int protocol); 1. 네트워크통신을위해사용될새로운소켓생성 2. 파일기술자테이블에새로생성된소켓의인덱스를파일기술자번호로변환 return value : sock 지정번호, sockfd 3. 입력인자 family : 프로토콜의부류입력 AF_UNIX UNIX internal protocols AF_INET Internet protocols AF_NS Xerox NS protocols AF_IMPLINK IMP link layer type : 소켓과함께사용할통신형태입력 protocol : TCP/UDP/RAW 입력, 일반적으로 0 socket type -SOCK_STREAM -SOCK_DGRAM -SOCK_RAW -SOCK_SEQPACKET -SOCK_RDM stream socket datagram socket raw socket sequenced packet socket reliably delivered message socket (not implemented yet)
<93> <Contents Delivery Programming> Elementary Socket System call socket family 와 type 에대응하는 protocol AF_UNIX AF_INET AF_NS SOCK_STREAM Yes TCP SPP SOCK_DGRAM Yes UDP IDP SOCK_RAW IP Yes SOCK_SEQPACKET SPP family, type 그리고 protocol 간의조합 family type protocol Actual protocol IPPROTO_xxx AF_INET AF_INET SOCK_DGRAM SOCK_STREAM IPPROTO_UDP IPPROTO_TCP UDP TCP - <netinet/in.h> NSPROTO_xxx - <netns/ns.h> AF_INET AF_INET SOCK_RAW SOCK_RAW IPPROTO_ICMPICMP IPPROTO_RAW ICMP (raw) AF_NS AF_NS AF_NS AF_NS SOCK_STREAM SOCK_SEQPACKET SOCK_RAW SOCK_RAW NSPROTO_SPP NSPROTO_SPP NSPROTO_ERROR NSPROTO_RAW SPP SPP Error protocol (raw)
<94> <Contents Delivery Programming> Elementary Socket System call( 계속 ) socket system calls 과연계요소들 connection-oriented server connection-oriented client protocol local-addr, local-process foreign-addr, foreign-process socket() bind() listen(), accept() socket() connect() connectionless server scoket() bind() recvfrom() connectionless client socket() bind() sendto() socketpair system call - 이름없이연결되어있는 sockvec[0] 과 sockvec[1] 이라는두가지 socket 지정번호를돌려줌 #include <sys/types.h> #include <sys/socket.h> int socketpair (int family, int type, int protocol, int sockvec[2]);
<95> <Contents Delivery Programming> 2. 소켓관련함수 bind system call - 이름없는 socket 에이름을부여 - 로컬인터페이스어드레스와포트번호를소켓과서로연관되게묶는함수입니다 Syntax int bind (int sockfd, struct sockaddr * myaddr, int addrlen); #include <sys/types.h> #include <sys/socket.h> int bind (int sockfd, struct sockaddr *myaddr, int addrlen); bind 의용도 1. 서버측에서처음생성된소켓이어떤주소값도갖고있지않음 2. server 는주지된주소를시스템에기록한다. 소켓에지역주소및포트 (Well-Known Port) 를할당하여활성화 3. 입력인자 sockfd : socket() 함수호출로얻은소켓의기술자입력 myaddr : 로컬 IP 및포트에대한정보가담긴 sockaddr_in in 주소입력 addrlen : sockaddr_in 의크기입력 4. client는자신을위한특정주소를기록할수있다. 5. connectionless client는시스템이자신에게유일한주소를부여하였음을확인할필요가있으며, 이로써상대측 server 가응답을보낼유효한반송주소를갖게되는것이다.
<96> <Contents Delivery Programming> Bind 처음만들어질때소켓은그와관련된로컬어드레스를가지지않습니다. 따라서 bind 함수는 connect 나 listen 함수를뒤이어호출하기전에, 접속되지않은소켓에사용됩니다. 이함수는접속지향형소켓 (stream socket : TCP) 이나비접속 (datagram : UDP) 소켓이나모두사용합니다. 소켓이 socket 함수를호출해서생성될때, 소켓은이름공간 (name space) 에존재합니다. 하지만, 할당된이름을가지지는않습니다. 그러므로, 이름지여지지않은소켓과로컬어드레스를연결지우기위해서이함수는사용됩니다. 이함수에의해서할당되어지는이름은세가지부분으로구성됩니다. ( 인터넷주소체계를사용할때 : 주소체계 (address family), 호스트주소 (host address), 어플리케이션에사용되는포트번호 (port number)) WinSock2 에서는 name 매개변수는 SOCKADDR 구조체의포인터로반드시넘겨야한다라는그런규정은없습니다. 그저윈도우즈소켓 1.1 과의호환성때문에남았는산물정도라고생각해두세요. 서비스프로바이더는 namelen 의메모리사이즈블록포인터에대해연관을받지않습니다. 메모리블록에서첫번째 2Byte (SOCKADDR 구조체의 sa_family 에해당되는부분입니다 ) 는소켓을생성하는데사용되는어드레스체계 (address family) 를가지고있어야합니다. 그렇지않다면, WSAEFAULT 에러가발생할것입니다. 만약어플리케이션이어떤로컬어드레스를할당할것인지고려하지않고사용된다면, name 매개변수의 sa_data 멤버를위해 INADDR_ANY 라는상수값을명시해야합니다. 이상수값을사용하면, 적절한네트웍주소를사용하기위해기본이되는서비스프로바이더를적용하게됩니다. 이상수값은한개이상의네트웍인터페이스나주소가있는호스트일경우어플리케이션프로그래밍을간략히하기위해서사용됩니다. 대부분의프로그램은인터페이스어드레스에대해 INADDR_ANY를사용합니다. TCP/IP 에서포트번호가 0 으로명시된경우에는서비스프로바이더가어플리케이션을위한고유한포트번호 (1024~5000 사이의값 ) 를할당합니다. 어플리케이션은주소와포트를알기위해 bind 된후에 getsockname 함수를사용할수있습니다. 만약인터넷주소가 INADDR_ANY 로사용되어있다면, getsockname 함수는접속되기전까지는사용하지못합니다. ( 몇몇주소들은호스트가 multihome 일경우올바를수도있기때문입니다 ) 0번포트가아닌특정한포트번호를바인딩하는것은클라이언트어플리케이션을무용지물이되게합니다. 왜냐하면, 다른소켓에이미그포트번호를사용하고있을경우충돌할수있는위험이있기때문입니다. 따라서, 클라이언트프로그램이포트 0을지정하는반면, 서버프로그램은대개자신의포트번호를지정합니다. connect 함수를호출하기전에는 bind 함수와같이소켓과어드레스를묶는함수가사실상필요치않습니다. 소켓이묶이기전에 connect 함수가호출될경우 bind 함수가 INADDR_ANY 의어드레스와포트번호 0을이용하여소켓에대해호출된것처럼소켓은자동으로묶이게됩니다. 대부분의클라이언트어플리케이션은로컬인터페이스어드레스나특별한포트값을지정할필요가없습니다. 따라서 bind함수를호출하기전에 connect 함수를호출함으로써이들어플리케이션에대한단계를줄일수있습니다. 일반적으로서버어플리케이션은 Well-known 포트와묶인소켓을생성해야합니다. 이를위해 bind 함수는대부분서버에대해명확하게호출되어야합니다.
<97> <Contents Delivery Programming> 2. 소켓관련함수 listen system call - connection 을받아들이겠다는의지를나타내기위하여 connection-oriented server가사용 - socket과 bind system call 후와 accept system call전에수행 Syntax - int listen (int sockfd, int backlog); #include <sys/types.h> #include <sys/socket.h> int listen (int sockfd, int backlog); 1. 서버측의접속대기큐의최대연결가능수설정 2. 입력인자 1. sockfd : socket() 함수호출로획득한소켓의소켓기술자입력 2. backlog : 접속대기큐의최대연결가능수를지정 (TCP 서버에서만사용 )
<98> <Contents Delivery Programming> 2. 소켓관련함수 accept system call - connection-oriented oriented server 가 listen system call 을수행한후, server가 accept system call을수행함으로써어떤 client process로부터실제적 connection을기다린다. Syntax int accept (int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen); #include <sys/types.h> #include <sys/socket.h> int accept (int sockfd, struct sockaddr *peer, int *addrlen); 1. TCP 서버에서호출되고연결이완료된큐의최초에위치한데이터반환 2. 큐가비어있는상태에는클라이언트의접속이이루어질때까지블록됨 3. 정상적으로함수가종료되면새로연결된파일기술자를반환 4. 입력인자 sockfd : listen() 함수호출로설정한소켓의소켓기술자입력 cliaddr : 클라이언트의 IP 주소와로컬포트정도를설정한구조체입력 addrlen : sockaddr 구조체의크기입력
<99> <Contents Delivery Programming> 2. 소켓관련함수 connect system call - local system 과외부 system 사이의실제적인 connection 을설정 Syntax int connect (int( sockfd, const struct sockaddr * servaddr, socklen_t addrlen); #include <sys/types.h> #include <sys/socket.h> int connect (int sockfd, struct sockaddr *servaddr, int addrlen); 1. 클라이언트에서서버로의연결을담당 2. 소켓기술자와상대서버에대한주소정보를를바탕으로서버로접속시도 3. 클라이언트에서 connect() 호출전에 bind() 를호출하지않았다고해도임의의포트와로컬 IP를자동으로설정하여함수호출 4. 3-way handshaking으로서버와연결을설정함 5. 입력인자 sockfd : socket() 함수호출로저장된소켓의소켓기술자입력 servaddr : 접속할서버의주소와포트에관한정보를담은구조체입력 addrlen : sockaddr 구조체의크기입력
<100> <Contents Delivery Programming> 2. 소켓관련함수 read / write / recv / send 1. ssize_t read (int sockfd, void * buffer, size_t len); - 원하는소켓 (sockfd) 에서특정길이 (len) 만큼을사용자버퍼 (buffer) 로읽어들임 2. ssize_t write (int sockfd, void * buffer, size_t len); - 원하는소켓 (sockfd) 에서특정길이 (len) 만큼을사용자버퍼 (buffer) 로보냄 3. ssize_t recv (int sockfd, void * buffer, size_t len, int flags); - read 함수와동일하나 flags 변수의값에따라데이터수신방법이다름 - flags 옵션 MSG_PEEK : 네트워크버퍼에서데이터제거를하지않고버퍼에복사만 함 MSG_OOB : 긴급메시지전달에사용하며 TCP 헤더의 URG bit을 1로변경 MSG_WAITALL : 완전한양의데이터를수신할때만 recv 호출에서복귀 4. ssize_t send (int sockfd, void * buffer, size_t len, int flags); - Write 함수와동일하나 flags 변수의값에따라데이터송신방법이다름 - flags 옵션 MSG_OOB : OOB Data 송신 MSG_DONTROUTE : 데이터를라우팅하지않는다. 즉라우팅조건을무시
<101> <Contents Delivery Programming> Elementary Socket System call send, sendto, recv, recvfrom system calls #include <sys/types.h> #include <sys/socket.h> int send(int sockfd, char *buff, int nbytes, int flags); int sendto(int t sockfd, char *buff, bff it int nbytes, bt int itflags, struct sockaddr *to, int addrlen); int recv(int sockfd, char *buff, int nbytes, int flags); int recvfrom(int sockfd, char *buff, int nbytes, int flags, struct sockaddr *from, int *addrlen); - 표준 read와 write 시스템호출과유사 - flags 독립변수는 0 이거나다음을 OR 연산으로형성한값 MSG_OOB send or recieve out-of-band data MSG_PEEK peek at incoming message(recv or recvfrom) MSG_DONTROUTE bypass routing (send or sendto)
<102> <Contents Delivery Programming> 2. 소켓관련함수 sendto / recvfrom ssize_t recvfrom (int sockfd, void * message, size_t len, int flags, struct sockaddr * send_addr, size_t * add_len); ssize_t sendto (int sockfd, void * message, size_t len, int flags, const struct sockaddr * dest_addr, size_t dest_len); - 두함수도데이터송수신을담당하지만 recvfrom( 수신 ) 과 sendto( 송신 ) 함수는 UDP 통신에서사용 - recv/send와의차이점은목적지에대한정보가추가된다는것으로이는 UDP의특징인비연결성을생각하면송수신에반드시필요한정보임을알수있음 close / shutdown int close (int sockfd); - 소켓종료후에는이전에연결된상대방에게데이터송신불가 - 대기열의데이터에대해서해당데이터수신작업완료후소켓종료 int shutdown (int sockfd, int howto); - TCP 연결에대한종료를담당하고옵션에따라종료방법조절가능 - close() 함수와다르게별다른작업없이바로종료시킨다는차이 - howto 인자에따른옵션 SHUT_RD : Read 불가, Write 가능 SHUT_WR : Read 가능, Write 불가 SHUT RDWR : Read / Write 모두불가
<103> <Contents Delivery Programming> 3. 소켓옵션관련함수 itgetsockopt int (int sockfd, int level, l int optname, void * optval, socklen_t * optlen); - 소켓 (sockfd) 의지정된옵션 (optname) 의값 (optval) 과바이트수 (optlen) 을반환 int setsockopt (int sockfd, int level, int optname, void * optval, socklen_t optlen); - 소켓 (sockfd) 에옵션 (optname) 을지정하고그에따른값 (optval) 과바이트수 (optlen) 을설정 소켓및프로토콜종류와그에따른옵션, 데이터값으로구성 level : 소켓및프로토콜의종류 (IP, ICMP, IPv6, TCP 등 ) optname : 세부옵션 optval : 선택한옵션에대한데이터값 optlen : optval의크기입력
<104> <Contents Delivery Programming> 2. 옵션의주요내용 3. 소켓옵션관련함수
<105> <Contents Delivery Programming> 1. signal() 함수 4. 동시처리를위한함수 1. 시스템에정의된이벤트발생시사용자가정의한처리를하는함수 2. 형태 - void (*signal)(int sig, void (*func)(int))(int); 3. 인자 - func : 시그널이전달될때호출되는함수의주소값입력 - sig : 처리하거나무시할시그널을설정 ( 요약 )
<106> <Contents Delivery Programming> signal() 사용방법 유닉스에서어떤이벤트 (event) 가발생하면이것을프로세스에게알리는수단으로사용 #include <signal.h> main() { }. signal(sigint, sigint_func); /* 시그널처리함수지정 */. int sigint_func() { /* SIGINT 시그널발생시처리내용 */ }
<107> <Contents Delivery Programming> 2. fork() 함수 4. 동시처리를위한함수 1. 새로운프로세스를생성하고복제된프로세스는현재프로세스와같은속성과코드를소유 2. 부모프로세스는자식프로세스에대한개수에대한제한이있으므로에러발생에대한제어필요 3. 형태 - pid_t fork (void); 4. 동작 5. 특징 코드, 스택,, 파일기술자, 소켓번호등을공유 PID 와변수는공유하지않음
<108> <Contents Delivery Programming> 4. 동시처리를위한함수 3. select () 함수 1. 파일기술자의상태변화감지후해당상태에대한처리 2. 상태변화는읽기 / 쓰기 / 예외처리의 3가지 3. 형태 -int select ( int n, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, const struct timeval * timeout); 4. 입력인자 - n : 상태를살펴볼최대기술자크기 - timeout : 상태를살펴볼주기설정 (0 인경우무한반복 ) - readfds / writefds / exceptfds : 읽기 / 쓰기 / 예외처리관련기술자 5. 상태기술자관리를위한매크로들
<109> <Contents Delivery Programming> select() 시스템콜 int select ( int maxfdp1, /* 최대소켓번호크기 + 1 */ fd_set *readfds, /* 읽기변화를감지할소켓번호 */ fd_set *writefds, /* 쓰기변화를감지할소켓번호 */ fd_set *exceptfds, /* 예외변화를감지할소켓번호 */ struct timeval *tvptr); /* select 시스템콜이기다리는시간 */
<110> <Contents Delivery Programming> select() 시스템콜 (Cont d) 매크로 FD_ZERO(fd_set *fdset) fdset의모든비트를지운다 FD_SET(int fd, fd_set *fdset) fdset 중소켓 fd 에해당하는비트를 1 로한다 FD_CLR(int fd, fd_set *fdset) fdset 중소켓fd에해당하는비트를 0으로한다 FD_ISSET(int fd, fd_set *fdset) fdset 중소켓 fd 에해당하는비트가세트되어있으면양수값을리턴
<111> <Contents Delivery Programming> Select 를이용한예
<112> <Contents Delivery Programming> 4. 동시처리를위한함수 4. poll() 함수 1. select 함수와같은기술자관리방식 2. select 에비하여관리할기술자를선택할수있음 3. select 함수보다빠른응답속도를보이나사용이불편한단점 4. 형태 - Int poll (struct pollfd *ufds, unsigned int nfds, int timeout); 5. 입력인자
<113> <Contents Delivery Programming> 4. 동시처리를위한함수 5. Thread 1. 스레드는프로세스와는다르게메모리공유가능 2. 메모리공유로인하여동기화문제발생 ( 관련도서참고 ) 3. 사용함수 Int pthread_create (pthread_t * thread, pthread_attr_t * attr, void * (* start_routine)(void *), void * arg); void pthread_join (pthread_t th, void ** thread_return); fork 에서자식프로세스를기다리는 wait 함수와같은기능 void pthread exit (void *retval); void pthread_exit (void retval); 스레드를종료시킬때호출
<114> <Contents Delivery Programming> Elementary Socket System call( 예제 ) concurrent server 로가정할경우의전형적인시나리오 int sockfd, newsockfd; if ( (sockfd = socket(...)) < 0) err_sys("socket error"); if (bind(sockfd,...) < 0) err_sys("bind error"); if (listen(sockfd, 5) < <0) err_sys("listen error"); for ( ; ; ) { newsockfd = accept(sockfd,...); /* blocks */ if (newsockfd < 0) err_sys("accept error"); if (fork() == 0) { close(sockfd); /* child */ doit(newsockfd); /* process the request */ exit(0); } } close(newsockfd); /* parent */
<115> <Contents Delivery Programming> Elementary Socket System call( 예제 ) iterative server 로가정할경우의전형적인시나리오 int sockfd, newsockfd; if ( (sockfd = soket(...)) < 0) err_sys( sys("socketsocket error"); if (bind(sockfd,...) < 0) err_sys("bind error"); if (listen(sockfd, 5) < <0) err_sys("listen error"); for ( ; ; ) { newsockfd = accept(sockfd,...); /* blocks */ if (newsockfd < 0) err_sys("accept error"); } doit(newsockfd); /* process the request */ close(newsockfd);
<116> <Contents Delivery Programming> 유닉스소켓프로그래밍을위한유틸리티함수들 1. 바이트순서변환함수 2. 주소변환구조체 3. 인터넷주소변환함수 4. 원격지호스트정보를얻는함수
<117> <Contents Delivery Programming> 1. 바이트순서변환함수 호스트바이트순서 CPU 에따라메모리에저장하는순서가틀림 네트워크바이트순서 CPU 에관계없이 High-order ih 순서로전송 Internet protocol 을위하여설계 htonl(), htons(), ntohl(), ntohs() htonl convert host-to-network, long integer htons convert host-to-network, short integer ntohl convert network-to-host, long integer ntohs convert network-to-host, short integer #include <sys/types.h> #include <netinet/in.h> u_long u_short u_long u_short htol(u_long hostlong); htons(u_short hostshort); ) ntohl(u_long netlong); ntohs(u_short netshort);
<118> <Contents Delivery Programming> 바이트순서 ( 예 ) Big-Endian Little-Endian - 데이터의최상위바이트의내용을저장될메모리의시작주소에저장 - 모토로라마이크로프로세서및 IBM 메인프레임기반 - 데이터의최하위바이트의내용을저장될메모리의시작주소에저장 - DEC VAX 컴퓨터및인텔마이크로프로세서
<119> <Contents Delivery Programming> 바이트순서 ( 예제프로그램 ) byte_order.c 예제 pmyservent = getservbyname("echo", "udp"); printf("port number of 'echo', 'udp' without ntohs() : %d \n", pmyservent->s_port); printf("port number of 'echo', 'udp' with ntohs() : %d \n", ntohs(pmyservent->s >s_port)); 실행결과 (x86 Linux System) Port number of 'echo', 'udp' without ntohs() : 1792 Port number of 'echo', 'udp' with ntohs() : 7 실행결과 (mc68000계열) Port number of 'echo', 'udp' without ntohs() : 7 Port number of 'echo', 'udp' with ntohs() : 7
<120> <Contents Delivery Programming> 2. 주소변환구조체 - 기본적인 IP 주소체계를도메인주소로변환시사용 A. hostent 구조체 - gethostbyaddr(), gethostbyname() 함수에사용 - 변수 : 호스트의공식명칭, 별칭, 호스트주소의종류, 주소체계의바이트수, 도메인에포함된 IP list B. servent 구조체 - getservbyname(), getservbyport() 함수에사용 - 변수 : 서버의공식명칭, 별칭, 서버가제공하는포트번호, 서버가사용하는프로토콜타입의문자열
<121> <Contents Delivery Programming> 원격지호스트정보를위한구조체 (1) * hostent 구조체
<122> <Contents Delivery Programming> hostent 구조체정의 struct hostent { char *h_name; /* 호스트이름 */ char **h_aliases; /* 호스트별명들 */ int h_addrtype; /* 호스트주소의종류 */ int h_length; /* 주소의크기 */ char **h_addr_list; /* IP 주소리스트 */ }; #define h_addr haddr_list[0] /* 첫번째주소 */
<123> <Contents Delivery Programming> 원격지호스트정보를위한구조체 (2) * servtent 구조체
<124> <Contents Delivery Programming> getservbyname() 시스템이현재지원하는 TCP/IP 응용프로그램의정보를알아내는함수로, 서비스이름과프로토콜을인자로주어호출하면서비스관련각종정보를포함하고있는 servent라는구조체의포인터를리턴한다. pmyservent = getservbyname("echo", " "udp"); ") servent 구조체의정의 (netdb.h 파일참조 ). struct servent { char *s_name; /* 서비스이름 */ char **s_aliases; /* 별명목록 */ int s_port; /* 포트번호 */ char *s_proto; /* 사용하는프로토콜 */ }; servent 구조체는네트워크로부터얻은정보이므로그내용이네트워크바이트순서로되어있고이를화면에출력해보려면호스트바이트순서로바꾸어야한다.
<125> <Contents Delivery Programming> 3. 인터넷주소 (IP 주소 ) 변환 인터넷주소를표현하는방식 도메인네임 32bit IP 주소 십진수표시법 (dotted decimal) IP 주소변환함수예 mm.sookmyung.ac.kr kr : : 203.252.201.16 252 201 16 Domain Name : IP 주소 (binary) : dotted decimal gethostbyname() inet_ntoa() ntoa() gethostbyaddr() tb inet_addr()
<126> <Contents Delivery Programming> 주소변환함수 (Address Conversion Routines)-1 unsigned long int inet_addr (const char * strptr); - Dotted Decimal' 문자열형태의주소를네트워크바이트순서를 갖는이진 바이너리로바꾸는함수 - 점으로분리된십진수개념의문자열을 32-비트 Internet 주소로변환 - 입력값이적절치못할경우 INADDR_NONE('-1') NONE(' 을반환 - -1 은 Dotted Decimal 로표현시 255.255.255.255 이므로유효성검사가반 드시필요
<127> <Contents Delivery Programming> Address Conversion Routines (2) int inet_aton (const char * strptr, struct in_addr * addrptr); - 'Dotted Decimal' 형태의문자열을바이너리형태로바꾸는함수 - strptr 로들어온 Dotted Decimal' 형태의문자열은변환되어 'in_addr' 타입의 addrptr 에저장됨 - 주소가올바르다면 0 이아닌값, 그렇지않다면 0 을반환 char * inet_ntoa (struct in_addr inaddr); - 'in_addr' 형의바이너리주소 inaddr 을 Dotted Decimal' 형태의문자열로변경 - 반환되는문자열은정적으로할당된버퍼에저장 - 함수의연속적인호출은버퍼를중복하여덮어쓰므로주의 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -inet_addr > inet_ntoa : 역변환 unsigned long inet_addr(char *ptr);) char *inet_ntoa(struct in_addr inaddr);
<128> <Contents Delivery Programming> IP 주소변환 ( 예제 ) ascii_ip.c 예제 struct in_addr host_ip; haddr = argv[1]; /* dotted decimal 주소 */ host_ip.s_addr = inet_addr(haddr); /* IP 주소 (hexa 4byte) 출력 */ printf( IP Address (hexa) 0x%x\n, host_ip.s_addr); /* dotted decimal 로다시변환하여출력 */ printf( %s\n, inet_ntoa(host_ip));
<129> <Contents Delivery Programming> IP 주소변환 ( 예제 ) get_hostent.c 예제 struct tin_addr host_ip; haddr = argv[1]; /* dotted decimal 주소 */ host_ip.s_addr = inet_addr(haddr); /* IP 주소 (hexa 4byte) 출력 */ printf( IP Address (hexa) 0x%x\n, host_ip.s_addr); /* dotted decimal 로다시변환하여출력 */ printf( %s\n, inet_ntoa(host_ip)); get_hostent.c 실행결과 #> get_hostent mm.sookmyung.ac.kr official host name : mm.sookmyung.ac.kr host address type : 2 length of host address : 4 IP address : 203.252.201.16 dotted decimal => 도메인네임 dotted decimal > 도메인네임 gethostbyaddr() 이용
<130> <Contents Delivery Programming> 4. 원격지호스트정보를얻는함수 1. struct hostent * gethostbyname (const char * hostname); - 전달값으로호스트의이름 ( 도메인 ) 을받아서 hostent 구조체에결과값을돌려주는함수 2. struct thostent t* gethostbyaddr (const char * addr, size_t len, int family); - 호스트의 IP주소 ( 바이너리형태의주소 ) 를이용하여해당호스트에대한정보를저장 - addr은호스트 IP 주소이고 len 은 IP 주소의크기 (IPv4 = 4, IPv6 = 16) 3. int gethostname (char * name, size_t namelen); - 현재의호스트이름을반환 - 전달인자 name 은호스트의이름을저장할곳의주소 - namelen 은 name의바이트길이 - 성공한경우반환값 0, 실패인경우반환값 -1
<131> <Contents Delivery Programming> 4. 원격지호스트정보를얻는함수 4. struct servent * getservbyname (const char * servname, const char * protoname); - 해당호스트에서진행되고있는서비스에대한각정보를서비스에대한이름과해당프로토콜로얻을수있게해주는함수 - 수행중에러발생시에는결과값으로 NULL 반환 5. struct servent * getservbyport (int port, const char * protoname); - 해당호스트에서진행되고있는서비스에대한각정보를포트번호로얻을수있게해주는함수 - 수행중에러발생시에는결과값으로 NULL 반환
<132> <Contents Delivery Programming> 클라이언트 / 서버의작성방법 1. 서버의유형 2. 연결형클라이언트 / 서버의작성 3. 비연결형클라이언트 / 서버의작성
<133> <Contents Delivery Programming> 서버프로그램작성절차 서버프로그램이먼저수행되고있어야한다. 서버는 socket() 을호출하여통신에사용할소켓을개설한다. 소켓번호와자신의소켓주소를 bind() 로서로연결한다. 소켓주소 ( 자신의 IP 주소자신의포트번호 ) 소켓번호는응용프로그램이알고있는통신창구번호이고, 소켓주소는네트워크시스템 ( 즉, TCP/IP) 이알고있는주소이므로이들의관계를묶어두어야한다. listen() 을호출하여클라이언트로부터의연결요청을기다리는수동대기모드로들어간다. 클라이언트로부터연결요청이왔을때이를처리하기위하여 accept() 를호출한다. 클라이언트가 connect() 를호출하여연결요청을해오면이를처리한다. 메시지를송수신한다.
<134> <Contents Delivery Programming> 클라이언트프로그램작성절차 socket() 을호출하여소켓을만든다. 서버에게연결요청을보내기위하여 connect() 를호출한다. 이때서버의소켓주소 (4+5) 구조체를만들어인자로준다. 소켓주소 ( 상대방의 IP 주소상대방의포트번호 ) 상대방 == 서버의 IP 주소및포트번호 대부분의클라이언트는 bind() 를사용하여포트번호를특정한값으로지정할필요가없다 ( 클라이언트는보통시스템이자동으로배정하는포트번호를사용한다 ). connect() 를호출하여연결요청을한다. 메시지를송수신한다.
<135> <Contents Delivery Programming> 소켓의동작모드 blocking 모드 함수를호출했을경우동작완료때까지멈춤 listen(), connect(), accept(), read(), write() 등 non-blocking 모드 시스템콜호출후바로값이리턴 계속루프 (loop) 를돌면서확인 ( 폴링 ) 비동기 (asynchronous) 모드 IO 변화를감지 select() 함수를사용
<136> <Contents Delivery Programming> 1. 서버의유형 1. 서버유형의결정 1. 클라이언트접속빈도 - 얼마만큼의클라이언트가어느정도의빈도로접속하는지에따름 2. 필요한규모와처리량 - 주고받는데이터의크기가어느정도이며필요한대역폭에따름 3. 데이터의안정성 - 클라이언트간혹은서버와클라이언트간의데이터신뢰도 - 요즘의네트워크망은설비가잘되어있어안정성에대한문제는줄어듬 2. 기본적인서버의유형 서버타입 선택사항 클라이언트의요청에대한처리방식동시처리형단순형 서버로의접근방식연결형 (TCP) 비연결형 (UDP)
<137> <Contents Delivery Programming> 연결형클라이언트 socket() 호출시소켓번호와소켓인터페이스의관계
<138> <Contents Delivery Programming> 연결형서버 P/G Iterative 모델의 TCP 서버프로그램작성절차
<139> <Contents Delivery Programming> 비연결형클라이언트 SOCK_DGRAM 으로소켓생성 connect() 없이바로메시지송수신 각패킷마다 IP 주소와포트번호를입력 sendto(int s, char* buf, int length, int flag, sockaddr* to, int tolen) recvfrom(int s, char* buf, int length, int flags, sockaddr* from, int fromlen)
<140> <Contents Delivery Programming> 포트번호배정 클라이언트포트번호배정시기 TCP 소켓의경우 connect() 호출이후에 UDP 소켓의경우 sendto() 호출이후에 getsockname() 을이용확인 getsockname(s, (struct sockaddr *)&clinet_addr, &addr_len); port = clinet_addr.sin_port; printf( client port number : %d\n, port);
<141> <Contents Delivery Programming> 2. 연결형클라이언트 / 서버의작성 1. 단순연결형클라이언트 / 서버 1) 서버와클라이언트의소켓생성 2) 서버는 BIND 작업후대기큐설정 (LISTEN) 3) 서버는클라이언트의접속대기 (ACCEPT) 4) 클라이언트가서버로접속시도 (CONNECT) 5) 접속이완료되면서버와클라이언트간의데이터송수신작업 6) 서버종료작업 7) 서버와클라이언트소켓닫음 (CLOSE)
<142> <Contents Delivery Programming> ( 예 ) 단순연결형서버 socket 생성및수행 /* 서버소켓생성 */ server_socket = socket(af_inet, SOCK_STREAM, 0); /* 서버주소및포트설정 */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(server_port); server_addr.sin_addr.s_addr sin s = htonl(inaddr_any); ANY); memset(&(server_addr.sin_zero), 0, 8); /* 해당주소및포트로바인딩작업 */ bind(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); /* 클라이언트의대기열수설정 */ listen(server_socket, 10); client_socket = accept(server_socket, (struct sockaddr*)&server_addr, &addrsize); msgsize = read(client_socket, BUFF, sizeof(buff)); if (msgsize <= 0) { printf( message receive error\n ); continue; } write(client_socket, BUFF, strlen(buff) );
<143> <Contents Delivery Programming> ( 예 ) 단순 Client socket 생성및수행 /* 소켓생성 TCP이므로 SOCK_STREAM*/ connect_fd fd= socket(af_inet, SOCK_STREAM, STREAM, 0); /* 사용자의서버 IP 및포트에대한입력을받아서 sockaddr_in 구조체를구성 */ connect_addr.sin_family = AF_INET; connect_addr.sin_port = htons(atoi(argv[2])); connect_addr.sin_addr.s_addr = inet_addr(argv[1]); memset(&(connect_addr.sin_zero), 0, 8); /* 서버로의소켓접속 */ connect(connect_fd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)); msgsize = read(connect_fd, msg, sizeof(msg)); if (msgsize <= 0) continue; printf("server Message>>%s", msg); memset(msg, '\0', sizeof(msg)); fgets(msg, 1024, stdin); msgsize = strlen(msg); write(connect_fd, msg, msgsize);
<144> <Contents Delivery Programming> 2. 연결형클라이언트 / 서버의작성 2. 다중연결연결형클라이언트 / 서버 1) 서버와클라이언트의통신초기화 (SELECT 관련 ) 2) 서버와클라이언트소켓의생성 3) 서버는 BIND 작업후대기큐설정 (LISTEN) 4) 서버는클라이언트의접속대기 (ACCEPT) 5) 클라이언트가서버로접속시도 (CONNECT) 6) 서버측의기술자에이벤트가발생 7) 접속처리후클라이언트와데이터송수신 8) 서버종료작업 9) 서버와클라이언트소켓닫음 (CLOSE)
<145> <Contents Delivery Programming> ( 예 ) 다중연결형서버 socket 생성및수행 /* 서버소켓생성 */ server_socket = Socket(AF_INET, SOCK_STREAM, 0); /* 서버주소및포트설정 */.. /* 해당주소및포트로바인딩작업 */ Bind(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); /* 클라이언트의대기열수설정 */ Listen(server_socket, 10); /*fd_set 데이타필드초기화 */ FD_ZERO(&readfd); maxfd = server_socket; socket; client_index = 0; while(1) { /*fd fd_set 를해당소켓기술자로설정 */ FD_SET(server_socket, &readfd); /* 접속된클라이언트의소켓기술자를 fd_set에설정 */ for (start_index = 0; start_index < client_index; index; start_index++) { FD_SET(client_fd[start_index], &readfd); if (client_fd[start_index] > maxfd) maxfd = client_fd[start_index]; } maxfd = maxfd + 1; return 0; 다음페이지계속
<146> <Contents Delivery Programming> select(maxfd, &readfd, NULL, NULL,NULL); /* 해당소켓기술자에변화가생겼는지검사 */ if (FD_ISSET(server_socket, &readfd)) { addrsize = sizeof(struct sockaddr_in); client_socket = Accept(server_socket, socket, (struct sockaddr*)&server_addr, &addrsize); FD_SET(client_socket, &readfd); client_fd[client_index] = client_socket; client_index++; if (client_index == 5) break; } /* 해당소켓기술자에변화가생겼는지검사서버에접속된모든클라이언트의소켓기술자검사 */ for (start_index = 0; start_index < client_index; start_index++) { if (FD_ISSET(client_fd[start_index], &readfd)) { msgsize = read(client_fd[start_index], BUFF, sizeof(buff)); if (msgsize <= 0) continue; printf("client Message>>%s", BUFF); msgsize = strlen(buff); write(client_fd[start_index], BUFF, msgsize); } }
<147> <Contents Delivery Programming> ( 예 ) 다중 Client socket 생성및수행 /* 서버로의소켓접속 */ Connect(connect_fd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)); /*fd_set 데이타필드초기화 */ FD_ZERO(&readfd); while(1) { } /*fd_set 를해당소켓기술자로설정 */ FD_SET(0, &readfd); FD_SET(connect_fd, &readfd); select (connect_fd+1, &readfd, NULL, NULL, NULL); /* 해당소켓기술자에변화가생겼는지검사 */ if (FD_ISSET(connect_fd, &readfd)) { msgsize = read(connect_fd, msg, sizeof(msg)); if (msgsize <= 0) continue; printf("server Message>>%s", msg); } /* 해당입력기술자에변화가생겼는지검사 */ if (FD_ISSET(0, &readfd)) { memset(msg, '\0', sizeof(msg)); fgets(msg, g, 1024, stdin); msgsize = strlen(msg); write(connect_fd, msg, msgsize); }
<148> <Contents Delivery Programming> 3. 비연결형클라이언트 / 서버의작성 1. 단순비연결형클라이언트 / 서버 1) 서버와클라이언트의소켓생성 2) 서버는 BIND 작업후대기 3) 서버와클라이언트간의데이터송수신 4) 서버는단순히클라이언트로데이터전송 5) 서버종료작업 6) 서버소켓닫음 6) 클라이언트소켓닫음 * 양쪽모두상대방의주소를알고있어야지속적인데이터송수신이가능함을기억
<149> <Contents Delivery Programming> ( 예 ) 단순비연결형서버 /*1. 서버소켓생성 */ server_socket = Socket(AF_INET, SOCK_DGRAM, 0); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(server_port); server_addr.sin_addr.s_addr = htonl(inaddr_any); memset(&(server_addr.sin_zero), 0, 8); bind(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); addrsize = sizeof(struct sockaddr_in); while(1) { memset(buff, '\0', sizeof(buff)); msgsize = recvfrom(server_socket, BUFF, sizeof(buff), 0, (struct sockaddr*)&client _ addr, &addrsize); if (msgsize <= 0) continue; } printf("client Message>>%s", BUFF); msgsize = strlen(buff); sendto(server_socket, BUFF, msgsize, 0, (struct sockaddr*)&client_addr, addrsize);
<150> <Contents Delivery Programming> ( 예 ) 단순비연결형클라이언트 memset(msg, '\0', sizeof(msg)); fgets(msg, 1024, stdin); msgsize = strlen(msg); /* 사용자입력데이타에대한처리. 서버전송 * sendto 함수이용 */ msgsize = sendto(connect_fd, msg, msgsize, 0, (struct sockaddr*)&connect_addr, addrsize); printf("message Send>>%s", msg); memset(temp_buff, '\0', sizeof(temp_buff)); /* 서버에서의송신데이타에대한처리 recvfrom 함수이용 */ recvfrom((int)sockfd, temp_buff, sizeof(temp_buff), 0, (struct sockaddr*)&server_addr, &temp_addrsize); printf("message Receive>>%s", temp_buff);
<151> <Contents Delivery Programming> 3. 비연결형클라이언트 / 서버의작성 2. 동시처리비연결형클라이언트 / 서버 1) 서버와클라이언트의소켓생성 2) 서버는 BIND 작업후대기 3) 클라이언트가서버로접속데이터송신 4) 서버는클라이언트의접속시마다클라이언트처리용스레드생성 5) 이후의클라이언트와의통신은각각의스레드가담당 6) 서버종료작업 7) 종료시스레드를통한클라이언트종료 8) 서버와클라이언트소켓닫음 (CLOSE)
<152> <Contents Delivery Programming> ( 예 ) 다중처리용비연결형서버 while(1) { memset(buff, '\0', sizeof(buff)); /* 접속클라이언트에대한수신데이타처리 */ msgsize = recvfrom(server_socket, BUFF, sizeof(buff), 0, (struct sockaddr*)&client_addr, &addrsize); if (msgsize <= 0) continue; memcpy(&curr_addr, &client_addr, sizeof(struct sockaddr_in)); memset(curr_buff, '\0', sizeof(curr_buff)); memcpy(curr _ BUFF, BUFF, strlen(buff)); /* 수신에대한데이타처리는 Thread로처리. 현재의예제에서는실용성이많지않으나실제에서는수신데이타에대한처리는많은작업이있을수있음 */ pthread_create(&thread, NULL, thread_process, (void *)server_socket); } void* thread_process(void * server_socket) { } memset(temp p_ BUFF, '\0', sizeof(temp p_ BUFF)); memcpy(temp_buff, CURR_BUFF, strlen(curr_buff)); printf("client Message>>%s", temp_buff); /*Thread로처리되는클라이언트데이터송신 */ sendto((int)server_socket, t) t temp_buff, strlen(temp_buff), 0, (struct sockaddr*)&temp_addr, sizeof(struct sockaddr));
<153> <Contents Delivery Programming> ( 예 ) 다중처리용비연결형클라이언트 /* 데이타수신에대한 Thread생성 */ pthread_create(&thread, NULL, thread_process, (void*)connect_fd); while(1) { memset(msg, '\0', sizeof(msg)); fgets(msg, 1024, stdin); msgsize = strlen(msg); /* 사용자입력데이타에대한처리. 서버전송 * sendto함수이용 */ msgsize = sendto(connect_fd, msg, msgsize, 0, (struct sockaddr*)&connect_addr, addrsize); printf("message Send>>%s", msg); } void* thread_process(void * sockfd) { while(1) { memset(temp_buff, '\0', sizeof(temp_buff)); /* 서버에서의송신데이타에대한처리 recvfrom함수이용 */ recvfrom((int)sockfd, temp_buff, sizeof(temp_buff), 0, (struct sockaddr*)&server_addr, &temp_addrsize); printf("message Receive>>%s", temp_buff); } }
<154> <Contents Delivery Programming> 채팅을위한클라이언트 / 서버프로그램작성 1. 프로그램개요및구조 2. 채팅프로그램
<155> <Contents Delivery Programming> 1. 프로그램개요및구조 (1) 서버프로그램구조 1) 서버에서사용하는구조체초기화 2) 서버소켓생성및클라이언트대기 3) select를이용한접속상황관리 - 클라이언트가접속하면소켓기술자의상태가변화하여접속여부확인 4) 접속처리 - 접속한클라이언트가넘겨주는정보로서버의각구조체를업데이트함 5) 데이터송수신 - 클라이언트로받은데이터는검색하여같은채팅방안에접속한각각의다른클라이언트에게전송 - 데이터수정작업필요 ( 이름첨가등 ) 6) 서버소켓닫기 - 종료하지않는다면 3) 으로복귀 7) 프로그램종료
<156> <Contents Delivery Programming> 채팅서버구조
<157> <Contents Delivery Programming> 채팅서버구조 (Cont d) 채팅서버와클라이언트와의연결관계
<158> <Contents Delivery Programming> /* 채팅에서의방을 3 개로설정 */ struct room_node roomlist[3]; 서버 : 채팅방설정 /* 각방에대한방이름초기화 */ strcpy(roomlist[0].room_name,"room1"); strcpy(roomlist[2].room_name,"room3"); strcpy(roomlist[1].room_name,"room2"); /* 각방의접속사용사수를초기화 */ roomlist[0].user_count = 0; roomlist[1].user_count = 0; roomlist[2].user_count = 0; /* 서버소켓생성 */ server_socket = socket(af_inet, SOCK_STREAM, 0); /* 서버 IP및포트설정 */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(server_port); server_addr.sin_addr.s_addr sin s = htonl(inaddr_any); ANY); memset(&(server_addr.sin_zero), 0, 8); bind(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); listen(server_socket, 0); FD_ZERO(&readfd);
<159> <Contents Delivery Programming> 서버 : 서버에접속한클라이언트소켓기술자확인 /* 서버에접속한클라이언트소켓기술자 [ 각방의유저구조체포함 ] 를 fd_ set에설정 */ FD_SET(server_socket, &readfd); for (room_index = 0; room_index < 3; room_index++) { for (user_index = 0; user_index < roomlist[room_index].user_count; user_index++) { tempsockfd = roomlist[room _ index].user _ list[user _ index].user _ sockfd; FD_SET(tempsockfd, &readfd); } } maxfd = maxfd + 1; if (tempsockfd > maxfd) maxfd = tempsockfd;
<160> <Contents Delivery Programming> 서버 : 클라이언트접속처리 select(maxfd, &readfd, NULL, NULL,NULL); /* 서버로의접속이있는클라이언트에대한처리 */ if (FD_ISSET(server_socket, socket &readfd)) { addrsize = sizeof(struct sockaddr_in); client_socket = accept(server_socket, (struct sockaddr*)&server_addr, &addrsize); memset(buff, '\0', sizeof(buff)); msgsize = read(client_socket, BUFF, sizeof(buff)); } if (msgsize <=0) { printf("enter user Error\n"); continue; }
<161> <Contents Delivery Programming> 서버 : 각방별로참가자확인및확약 printf("receive Message:%s\n", BUFF); /* 각방이5명으로제한되어있으므로해당유저인원체크 */ if (BUFF[0] == '1') { printf("login Room1 Count:%d\n", roomlist[0].user_count); if (roomlist[0].user_count == 5) { strcpy(buff, "User Count Overflow Error"); write(client_socket, BUFF, strlen(buff)); close(client_socket); continue; /* 인원초과 */ } roomlist[0].user_list[roomlist[0].user_count].user_sockfd = client_socket; roomlist[0].user_count++; strcpy(buff, "ConnectOK"); write(client_socket, BUFF, strlen(buff)); }
<162> <Contents Delivery Programming> 서버 : 참가자에게수신정보전달 for (room_index = 0; room_index < 3; room_index++) { for (user_index = 0; user_index < roomlist[room_index].user_count; user_index++) { if (FD_ISSET(roomlist[room_index].user_list[user_index].user_sockfd,&readfd)){ memset(buff, '\0', sizeof(buff)); tempsockfd = roomlist[room_index].user_list[user_index].user_sockfd; msgsize = read(tempsockfd, BUFF,sizeof(BUFF)); if (msgsize <= 0) { if (user_index == roomlist[room_index].user_count) { close(roomlist[room_index].user_list[user_index].user_sockfd); roomlist[room_index].user_count--; } else if (user_index < roomlist[room_index].user_count) { close(roomlist[room_index].user_list[user_index].user_sockfd); for (temp_user_count = user_index; temp_user_count < roomlist[room_index].user_count; temp_user_count++) { roomlist[room_index].user_list[temp_user_count] = roomlist[room_index].user_list[temp_user_count+1]; roomlist[room_index].user_count--; } } else { printf("receive Message=>%s\n", BUFF, msgsize); for (temp_user_count = 0; temp_user_count < roomlist[room_index].user_count; temp_user_count++) { msgsize = strlen(buff); write(roomlist[room_index].user_list[temp_user_count].user_sockfd, BUFF,msgsize); } } } } }
<163> <Contents Delivery Programming> 1. 프로그램개요및구조 (2) 클라이언트프로그램구조 1) 서버에전달할기본데이터입력 - 사용자의대화명및방번호 2) 서버접속을위한구조체설정 - 서버주소및포트정보입력 3) 소켓생성 4) 서버로접속시도및확인 - Connect 함수이용하여접속 - 접속처리결과를서버로부터받음 5) 데이터수신 - 수신데이터는수정하지않고바로화면에출력함 - 서버에서분류되어전송되었으므로클라이언트는따로처리할필요없음 6) 데이터송신 - 자신의대화명추가후서버로송신 7) 클라이언트프로그램소켓닫기 - 종료하지않는다면 5) 으로복귀 8) 프로그램종료
<164> <Contents Delivery Programming> 클라이언트 : 채팅방요구준비 /* 사용자대화명입력처리 */ fgets(name,30,, stdin); name[strlen(name)-1] = '\0'; while(1) { /* 접속방번호입력 */ printf("#enter Room Number(ex=>1 or 2 or 3)=>"); room_number = (char)fgetc(stdin); fgetc(stdin); if (room_number!= '1' && room_number!='2' && room_number!= '3') { printf("incorrect Room Number\n"); continue; } else break; } memset(msg, '\0', sizeof(msg)); msg[0] = room_number; for (temp_index = 0; temp_index < strlen(name); temp_index++) { msg[temp_index+1] = name[temp_index]; }
<165> <Contents Delivery Programming> 클라이언트 : 채팅방요구 connect_fd = socket(af_inet, SOCK_STREAM, 0); connect_addr.sin_family = AF_INET; connect_addr.sin_port = htons(atoi(argv[2])); connect_addr.sin_addr.s_addr = inet_addr(argv[1]); memset(&(connect_addr.sin_zero), 0, 8); /* 서버접속 */ connect(connect_fd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)); msgsize = strlen(msg); write(connect_fd, msg, msgsize); memset(msg, '\0', sizeof(msg)); /* 채팅서버에대한접속결과확인 */ read(connect_fd, msg, sizeof(msg)); if (!strcmp(msg, "ConnectOK")) { printf("*******server Connection Success********\n"); printf("*******start Chatting Program ********\n"); } if (!strcmp(msg, "User Count Overflow Error")) { printf("%s\n", msg); exit(1); }
<166> <Contents Delivery Programming> 클라이언트 : 채팅 FD_ZERO(&readfd); while(1) { FD_SET(0, &readfd); FD_SET(connect_fd, &readfd); select (connect_fd+1, &readfd, NULL, NULL, NULL); } if (FD_ISSET(connect_fd, &readfd)) { memset(msg, '\0', sizeof(msg)); msgsize = read(connect _ fd, msg, sizeof(msg)); if (msgsize <= 0) continue; printf("*from=>%s\n", msg); } if (FD_ISSET(0, &readfd)) { memset(msg, '\0', sizeof(msg)); fgets(msg, 1024, stdin); msg[strlen(msg)-1] g) = '['; strcat(msg, name); msg[strlen(msg)] = ']'; msgsize = strlen(msg); write(connect_fd, msg, msgsize); }
<167> <Contents Delivery Programming> 멀티캐스트채팅을위한프로그램작성 1. 멀티캐스트방식의특징 2. 멀티캐스트채팅프로그램
<168> <Contents Delivery Programming> 1. Unicast 1. 멀티캐스트방식의특징 1. 송수신자가일대일로대화하는네트워크의가장일반적인통신방식 2. 송신측순서 : UDP 계층 > IP 계층 > Data Link 계층 > 전송 3. 수신측순서 : Data Link 계층에서주소비교후목적지라면송신의반대순서로 읽어들임 4. 데이터를보내는곳에서목표로한하나의주소로만전달됨
<169> <Contents Delivery Programming> 2. Broadcast 1. 멀티캐스트방식의특징
<170> <Contents Delivery Programming> 1. 멀티캐스트방식의특징 3. Multicast 1. 필요성 멀티미디어데이터의등장으로일대다의전송방식이필요하게됨 유니캐스트방식은많은클라이언트들의연결을감당하기힘듬 브로드캐스트방식은같은종속망의모든클라이언트에게전송하는단점 그런이유로 LAN이나 WAN사이에서이루어지는멀티캐스트가필요해짐 2. 가용주소 224000 224.0.0.0 ~ 239.255.255.255 239255255255 에걸쳐사용되는 Class D 가멀티캐스트 Class D 의하위28비트는멀티캐스트그룹 ID, 32비트는그룹주소
<171> <Contents Delivery Programming> 1. 멀티캐스트방식의특징 3. 멀티캐스트의흐름 LAN 수신측은자신의주소로대기하지않고멀티캐스트그룹주소로대기함 해당멀티캐스트그룹주소에포함된주소로만데이터송신작업 송신측은목적지주소와포트를가지고해당호스트로데이터전송
<172> <Contents Delivery Programming> 1. 멀티캐스트방식의특징 3. 멀티캐스트의흐름 WAN 송신측이속한 LAN에대하여우선적으로처리 멀티캐스트라우터사이는 MRP를이용하여데이터전송처리 외부 LAN으로전송시전송데이터의복사본을만들어라우터로전송 * MRP = Multicast Routing Protocol
<173> <Contents Delivery Programming> 멀티캐스트 P/G 멀티캐스트 (Multicast) 하나의패킷을다수의수신자에게전달 class D 주소를사용 중간의라우터들이멀티캐스트를지원해야함 UDP 소켓사용 IGMP를통해그룹에참여또는탈퇴 TTL을통한범위설정 TTL(Time-to-Live) Live) in the DNS context defines the duration in seconds that the record may be cached 멀티캐스트패킷송신 UDP 소켓개설후전송 굳이멀티캐스트그룹에가입할필요가없다 멀티캐스트패킷의 TTL 설정 패킷이전체네트워크로전송되지않도록제한 int ttl = 32; setsockopt(setd_s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
<174> <Contents Delivery Programming> 멀티캐스트 P/G 작성 멀티캐스트구조체 struct ip_mreq { } struct in_addr imr_multiaddr;/* 멀티캐스트그룹주소 */ struct in_addr imr_interface;/ interface;/* 자신의 IP 주소 */ 멀티캐스트패킷수신 setsockopt(recv_s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); setsockopt(recv_s, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)); bind(recv_s, (struct sockaddr*)&mcst_group, sizeof(mcast_group));
<175> <Contents Delivery Programming> 2. 멀티캐스트채팅프로그램 1. 구조 (0) 멀티캐스트는서버 / 클라이언트가동일 (1) 멀티캐스트그룹주소설정작업 struct ip_mreq { struct in_addr imr_multiaddr; /* 멀티캐스트그룹주소 */ struct in_addr imr_interface; /* 자신의 IP주소 */ } (2) 데이터송수신소켓생성 (UDP) (3) 생성한소켓의옵션설정 IP_ADD_MEMBERSHIP : 멀티캐스트그룹가입 IP_DROP_MEMBERSHIP : 멀티캐스트그룹탈퇴 IP_MULTICAST_LOOP : 멀티캐스트패킷루프백여부 IP_MULTICAST_TTL : 멀티캐스트패킷 TTL 값 (4) 설정한소켓연동 (BIND) (5) 데이터송수신 (6) 소켓종료 (CLOSE) (7) 프로그램종료
<176> <Contents Delivery Programming> ( 예 ) 멀티캐스트프로그램 /* 멀티캐스트수신및송신소켓생성 */ multicast_recv_sockfd = socket(af_inet, SOCK_DGRAM, 0); multicast_ send_ sockfd = socket(af _ INET, SOCK_ DGRAM, 0); memset(&multicast_group_addr, 0, sizeof(multicast_group_addr)); /* 멀티캐스트주소및포트설정*/ multicast_group_addr.sin_family = AF_INET; multicast_group_addr.sin_port = htons(atoi(argv[2])); multicast_group_addr.sin_addr.s_addr = inet_addr(argv[1]); /* 멀티캐스트주소와수신 IP 주소설정 */ mreq.imr_multiaddr = multicast_group_addr.sin_addr; mreq.imr_interface.s_addr = htonl(inaddr_any); multicast_recv_sockfd = socket(af_inet, SOCK_DGRAM, 0); /* 소켓옵션설정멀티캐스트그룹추가 */ setsockopt(multicast _ recv_ sockfd, IPPROTO_ IP, IP_ ADD_ MEMBERSHIP, &mreq, sizeof(mreq)); /* 소켓재사용 */ setsockopt(multicast_recv_sockfd, SOL_SOCKET, SO_REUSEADDR, &multicast_index, sizeof(multicast_index)); /*TTL설정*/ setsockopt(multicast _ recv_ sockfd, IPPROTO_ IP, IP_ MULTICAST_ TTL, &ttl, sizeof(ttl)); send_result = bind(multicast_recv_sockfd, (struct sockaddr*)&multicast_group_addr, sizeof(multicast_group_addr));
<177> <Contents Delivery Programming> Part 4 자바네트워크프로그래밍환경소개 1. 입출력스트림클래스의소개 2. 스레드 (Thread) 클래스의소개
<178> <Contents Delivery Programming> ( OutputStream 클래스메소드
<179> <Contents Delivery Programming> OutputStream 클래스메소드의사용 다음은 OutputStream 클래스의메소드를이용하여파일에문자를삽입하는프로그램이다. 절대경로 "i:/" 에 Example.java 파일을생성하고, 그파일에문자 a' 를 100 번기입한다. 1: import java.io.*; 2: 3: public class OutputStreamTest{ 4: public static void main(string[] args) { 5: try{ 6: OutputStream out = new FileOutputStream("i:/Example.java"); 7: int i; 8: for(i=0; i<100 ; i++) 9: { 10: out.write('a'); 11: } 12: out.close(); 13: } catch(ioexception e) { 14: System.out.println(e); 15: } 16: } 17: }
<180> <Contents Delivery Programming> OutputStream 클래스타입의객체참조 out 을선언 절대경로 i:/example.java" 파일에데이터를쓰기위해 FileOutputStream을이용하고, 읽어온데이터를 OutputStream 객체참조 에연결함. OutputStream out = new FileOutputStream("i:/Example.java"); 문자 a 를파일에 100 번출력하도록함. for(i=0; i<100 ; i++) { out.write('a'); }
<181> <Contents Delivery Programming> 문자스트림클래스 문자스트림클래스 2바이트의문자를다룬다는것을제외하고바이트스트림과거의유사함. 메소드역시유사한데, 매개변수로사용되는데이터의타입이 byte가아니라 char라는특징
<182> <Contents Delivery Programming> Reader, Writer 클래스에서도 InputStream, OutputStream 클래스와마 찬가지로기본적인메소드를지원. Reader 클래스의 read 메소드들은 InputStream 클래스의 read() 메소 드와유사함. 차이점 InputStream 에서는 read() 메소드가추상메소드이고, 다른 read() 메소드들은이메소드를바탕으로쓰여짐. Reader 클래스에서는반대로 read(char[] buf, int off, int len) 메소드가추상메소드임. 파일등대부분의스트림에서한두바이트단위로입출력하는것보다는더큰단위로입출력하는것이훨씬효율적이기때문에이런방식으로바뀜.
<183> <Contents Delivery Programming> Reader/Writer 클래스메소드
<184> <Contents Delivery Programming> 바이트스트림에서의문자처리 바이트단위로읽어온문자를 char형으로변환 문자스트림에서의문자처리 16bit 유니코드를사용하는자바에서한글이깨지는문제를해결
<185> <Contents Delivery Programming> 문자스트림클래스의사용 사용자입력을무한정받아들여파일에기술하는프로그램
<186> <Contents Delivery Programming> InputStreamReader 객체는사용자의입력을위해준비 InputStreamReader isr = new InputStreamReader(System.in); 시스템의완충작용즉, 버퍼링을지원하기위해서 InputStreamReader 객체를 BufferedReader 객체의인자로줌. BufferedReader br = new BufferedReader(isr); 사용자입력을파일로생성하기위해 FileOutputStream 을생성했는데, 이때인자로들어오는값은처음자바를실행할때, 넣어주었던 arg[0] 값이됨. FileOutputStream fos = new FileOutputStream(args[0]); 실제사용자입력즉, BufferedReader 스트림을 null 이아닐때까지한라인씩읽어서 BufferedWriter 객체를이용해파일에기술함. while((inputstring = br readline())!= null) { while((inputstring = br.readline())!= null) { bw.write(inputstring + "\n"); }
<187> <Contents Delivery Programming> 스레드 (Thread) 클래스의소개 스레드 한프로그램내에서독립적으로수행되는하나의제어흐름 스레드는어떤변수나파일을각각의스레드들간에공유하기 에편리한방법. 프로세스 완전히독립적으로수행되지만, 시스템자원을사용 자바에서는 C 언어와는다르게스레드를자체적으로지원함으로 C 에서사용하는 fork() 와같은시스템자원을사용하지않는다.
<188> <Contents Delivery Programming> 스레드의상태변이 Thread 생성 스레드를디자인하고 new 연산자를이용하여스레드를생성한것을의미. Runnable 새로운스레드가생성되어그스레드의 start() 메소드를호출하면, 스레드는실행가능한 Runnable 상태가됨. 실행권한을가진후보스레드 실행큐라고하는것에스레드를넣어두고자바런타임스케줄러에의해서처리. 실행큐란 Runnable 상태에있는스레드들을넣어두는자료구조. CPU는한순간에단하나의스레드만을실행함. 실행큐에있는스레드들중에서하나만을골라서실행 Not Runnable 실행중인스레드의 wait(), sleep() 메소드를호출하게되면스레드는 Runnable 상태에서 Not Runnable상태로전환하게된다. 전에말한실행큐에서제거되고대기큐라는곳으로자리를옮기는것이다. Dead 스레드가할일을모두마치면스레드는 Dead 상태가됨. 즉, 스레드의 run 메소드가끝나거나리턴된경우스레드는 Dead 상태가된다.
<189> <Contents Delivery Programming>
<190> <Contents Delivery Programming> 스레드클래스의사용 자바에서스레드를사용하기위한두가지방법 Thread 클래스를상속 interface 클래스인 Runnable 클래스를구현 스레드클래스의사용 다중상속을피하기위해두가지방법을지원
<191> <Contents Delivery Programming> Thread 클래스의상속 다른클래스를상속받지않고, 단지 java.lang.thread 클래스만을상속받을때사용가능. public class Thread_Test extends Thread 스레드클래스를상속받았다면, 실제스레드객체를생성하여스레드를시작하게하여야함. 스레드의시작을알리는메소드는 start() 임. Thread thread = new Thread_Test(); thread.start(); t t()
<192> <Contents Delivery Programming> 프로그램의구현 본프로그램은스레드를이용하여 0.5초간격으로 Thread 번호 를출력하는프로그램이다.