(분산 통신 실습) : 소켓(Sockets) 소켓: 저수준 패킷 스트림 전송 유닉스 소켓 (multi.incheon.ac.kr 117.16.244.157 에서 프로그램) (실습1) Hello 프로그램 inetserver.c inetclient.c 컴파일 & 실행 (실습2) 일대일 채팅 talk 프로그램 talk_server.c talk_client.c 컴파일 & 실행 (실습3) 다대다 채팅 chat 프로그램 chat_server.c chat_client.c 컴파일 & 실행 (과제) 다대다 채팅 프로그램 디버깅 (채팅 참가자가 exit해도 진행되도록) 자바 소켓 (실습1) 시간(Time-of-Day) 서버 소스 코드 분석 (실습2) 유닉스 inettime 클라이언트와 혼합해서 inettime 서비스를 실행해 보세요. (과제) 자바 응용 채팅 프로그램 JavaChatServer.java와 JavaChatClient.java 및 JavaChatClient.html 자바 애플릿 채팅 프로그램을 자바 응용 채팅 프로그램으로 수정하세요. 윈도우 소켓(winsock) (실습1) 윈도우 소켓 chat 프로그램으로 컴파일 & 실행 (과제) 윈도우 소켓 talk 프로그램 유닉스 talk 프로그램의 winsock 버전을 작성하세요. [Sockets 실습 과제] 유닉스 소켓/자바 소켓/윈도우 소켓 과제 중 택 1 http://marvel.incheon.ac.kr/의 Information의 Unix의 Socket Programming 참조
Socket Communication 운영체제
유닉스 소켓 통신: inetserver.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define PORTNUM 5059 main(int argc, char *argv[]) { int serverFd, clientFd, clilen, childpid; struct sockaddr_in cli_addr, serv_addr; // Open a TCP socket (an Internet stream socket). if((serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("server: can't open stream socket"); return -1; } // Bind our local address so that the client can send to us. bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(PORTNUM); if(bind(serverFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) printf("server: can't bind local address"); printf("Server is binded\n");
유닉스 소켓 통신: inetserver.c listen(serverFd, 5); for( ; ; ){ // Wait for a connection from a client process. // This is an example of a concurrent server. clilen = sizeof(cli_addr); clientFd = accept(serverFd, (struct sockaddr *) &cli_addr, &clilen); printf("Server called\n"); if((childpid = fork()) < 0){ printf("server: fork error"); exit(0); } else if(childpid == 0){ /* child process */ /* printf("serverFd = %d, clientFd = %d\n", serverFd, clientFd); */ /* process the request */ write(clientFd,"Hello!",7); close(clientFd); /* close original socket */ return -1; close(clientFd); /* parent process */
유닉스 소켓 통신: inetclient.c #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define PORTNUM 5059 main(int argc, char *argv[]) { int clientFd; char str[10]; char* hostaddress; struct sockaddr_in serv_addr; struct hostent* hostStruct; struct in_addr* hostNode; if(argv[1] == NULL){ printf("Usage: inetclient hostname(or server IP)\n"); printf(" (Ex) inetclient multi.inchon.ac.kr(or 211.119.245.149)\n"); exit(1); }
유닉스 소켓 통신: inetclient.c hostStruct = gethostbyname(argv[1]); if(hostStruct == NULL) return(0); hostNode = (struct in_addr*) hostStruct->h_addr; hostaddress = inet_ntoa(*hostNode); printf("host name is %s, host address is %s\n", argv[1], hostaddress); // Fill in the structure "serv_addr" with the address of the // server that we want to connect with. bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = hostNode->s_addr; serv_addr.sin_port = htons(PORTNUM); // Open a TCP socket (an Internet stream soskcet). if((clientFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) printf("client: can't open stream socket"); // Connect to the server if(connect(clientFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) printf("client: can't connect to server"); /* printf("clientFd = %d\n", clientFd); */ read(clientFd, str, 10); printf("%s\n", str); close(clientFd); exit(0); }
유닉스 소켓 통신: talk & chat 인터넷 talk 프로그램 netprog의 talk_server.c talk_client.c 소스코드 참조 실행 % talk_server 포트번호 % talk_client 서버호스트IP주소 포트번호 인터넷 chat 프로그램 하나의 프로세스가 채팅 참가 신청 처리와 클라이언트들의 통신 처리를 다 할 수 있도록 accept() 또는 read()에서 계속 기다리는 동기(synchronous, blocking) 모드 대신 select() 시스템 호출을 이용하여 소켓을 비동기(asynchronous, non-blocking) 모드로 이용 netprog의 chat_server.c chat_client.c 소스 코드 참조 % chat_server 포트번호 % chat_client 서버호스트IP주소 포트번호 유닉스 네트워크 프로그래밍
select() select() select() 시스템 호출 형식 소켓에서 발생하는 I/O 변화를 기다리다가 지정된 /O 변화가 발생하면 리턴 됨 초기 소켓 s와 참가한 클라이언트들의 소켓의 I/O 변화 감지 select() 시스템 호출 형식 int select ( int maxfdp1, /* chleo 파일(및 소켓) 번호 크기 +1 */ fd_set *readfds, /* 읽기 상태 변화를 감지할 소켓 지정 */ fd_set *writefds, /* 쓰기 상태 변화를 감지할 소켓 지정 */ fd_set *exceptfds, /* 예외 상태 변화를 감지할 소켓 지정 */ struct timeval *tvptr); /*select() 시스템 호출이 기다리는 시간 */ FD_ZERO(fd_set *fdset) 매크로로 모든 비트 지움 FD_SET(int fd, fd_set *fdset) 매크로로 소켓 fd의 fdset 변화를 감지하기 위해 fdset 중 fd에 해당하는 비트를 1로 지정 FD_ISSET(int fd, fd_set *fdset) 매크로는 fdset의 해당 fd 비트가 1로 지정되어 있으면 양수값 리턴하므로 fd에게 fdset 변화가 발생했는지 판단 유닉스 네트워크 프로그래밍
Time-of-Day: Server.java import java.net.*; import java.io.*; public class DateServer { public static void main(String[] args) { try { ServerSocket sock = new ServerSocket(6013); // now listen for connections while (true) { Socket client = sock.accept(); // we have a connection PrintWriter pout = new PrintWriter(client.getOutputStream(), true); // write the Date to the socket pout.println(new java.util.Date().toString()); // close the socket and resume listening for more connections client.close(); } catch (IOException ioe) { System.err.println(ioe);
Time-of-Day: Client.java import java.net.*; import java.io.*; public class DateClient { public static void main(String[] args) { try { // this could be changed to an IP name or address other than the localhost Socket sock = new Socket("127.0.0.1",6013); InputStream in = sock.getInputStream(); BufferedReader bin = new BufferedReader(new InputStreamReader(in)); String line; while( (line = bin.readLine()) != null) System.out.println(line); sock.close(); } catch (IOException ioe) { System.err.println(ioe);
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를 사용, 키보드 입력은 메인에서 처리