23
1.1 ( 분분 분분 분분 ) : 분분 (Sockets) 소소 : 소소소 소소 소소소 소소 소소소 소소 (multi.incheon.ac.kr 117.16.244.53 소 117.16.244.59 소소 소소소소 ) ( 소소 1) Hello 소소소소 helloserver.c helloclient.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 소소

(분산 통신 실습) : 소켓( Sockets)

Embed Size (px)

DESCRIPTION

(분산 통신 실습) : 소켓( Sockets). 소켓 : 저수준 패킷 스트림 전송 유닉스 소켓 (multi.incheon.ac.kr 117.16.244.53 및 117.16.244.59 에서 프로그램 ) ( 실습 1) Hello 프로그램 helloserver.c helloclient.c 컴파일 & 실행 ( 실습 2) 일대일 채팅 talk 프로그램 talk_server.c talk_client.c 컴파일 & 실행 - PowerPoint PPT Presentation

Citation preview

Page 1: (분산 통신 실습)  :  소켓( Sockets)

1.1

( 분산 통신 실습 ) : 소켓 (Sockets)

소켓 : 저수준 패킷 스트림 전송

유닉스 소켓 (multi.incheon.ac.kr 117.16.244.53 및 117.16.244.59 에서 프로그램 ) ( 실습 1) Hello 프로그램 helloserver.c helloclient.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 참조

Page 2: (분산 통신 실습)  :  소켓( Sockets)

운영체제

Socket Communication

Page 3: (분산 통신 실습)  :  소켓( Sockets)

유닉스 소켓 통신 : helloserver.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");

1.3

Page 4: (분산 통신 실습)  :  소켓( Sockets)

유닉스 소켓 통신 : helloserver.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 */

}

}

1.4

Page 5: (분산 통신 실습)  :  소켓( Sockets)

유닉스 소켓 통신 : helloclient.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);

}

1.5

Page 6: (분산 통신 실습)  :  소켓( Sockets)

유닉스 소켓 통신 : helloclient.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);

}

1.6

Page 7: (분산 통신 실습)  :  소켓( Sockets)

유닉스 네트워크 프로그래밍 7

유닉스 소켓 통신 : 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 주소 포트번호

Page 8: (분산 통신 실습)  :  소켓( Sockets)

유닉스 네트워크 프로그래밍 8

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 변화가 발생했는지 판단

Page 9: (분산 통신 실습)  :  소켓( Sockets)

1.9

Time-of-Day: Server.javaimport 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);

}

}

}

Page 10: (분산 통신 실습)  :  소켓( Sockets)

1.10

Time-of-Day: Client.javaimport 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);

}

}

}

Page 11: (분산 통신 실습)  :  소켓( Sockets)

EchoServer.java

import java.net.*;

import java.io.*;

public class EchoServer

{

public static final int DEFAULT_PORT = 6007;

public static final int BUFFER_SIZE = 256;

public static void main(String[] args) throws IOException {

ServerSocket sock = null;

byte[] buffer = new byte[BUFFER_SIZE];

InputStream fromClient = null;

OutputStream toClient = null;

try {

// establish the socket

sock = new ServerSocket(DEFAULT_PORT);

while (true) {

/**

* now listen for connections

*/

Socket client = sock.accept();

/**

* get the input and output streams associated with the socket.

*/

fromClient = new BufferedInputStream(client.getInputStream());

toClient = new BufferedOutputStream(client.getOutputStream());

1.11

int numBytes;

/** continually loop until the client closes the connection */

while ( (numBytes = fromClient.read(buffer)) != -1) {

toClient.write(buffer,0,numBytes);

toClient.flush();

}

fromClient.close();

toClient.close();

client.close();

}

}

catch (IOException ioe) { }

finally {

if (sock != null)

sock.close();

}

}}

Page 12: (분산 통신 실습)  :  소켓( Sockets)

1.12

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 를 사용 , 키보드 입력은

메인에서 처리

Page 13: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

/*----------------------------------------------------------------------------------------------

파일명 : chat_server.c

기 능 : 채팅참가자관리 , 채팅메시지수신및방송 컴파일 : VC++ 6.0

LIB : ws2_32.lib

실행예 : chat_server 4001

작성일 : 2003.03.06 made by JAXAL

-----------------------------------------------------------------------------------------------*/

#include<stdio.h>

#include<winsock2.h>

#define MAXLINE 1024

#define MAX_SOCK 512

char *escapechar = "exit\n";

/* ------------------------------- 종료문자확인함수 ----------------------------

exitCheck() 는다음의세개의인자를필요로한다rline: 클라이언트가전송한문자열포인터escapechar: 종료문자포인터len: 종료문자의크기

---------------------------------------------------------------------------------------------*/

1.13

Page 14: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

int exitCheck(char *rline, char *escapechar, int len)

{

int i, max;

char *tmp;

max = strlen(rline);

tmp = rline;

for(i = 0; i<max; i++)

{

if (*tmp == escapechar[0])

{

if(strncmp(tmp, escapechar, len) == 0)

return 1;

}

else

tmp++;

}

return -1;

}

1.14

Page 15: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

int main(int argc, char *argv[])

{

char rline[MAXLINE];

char *start = " 대화방에오신걸환영합니다 ...\n";

int i, j, n;

SOCKET s, client_fd;

int clilen, nfds;/* 최대소켓번호 +1 */

fd_set read_fds; /* 읽기를감지할소켓번호구조체 */

int num_chat = 0; /* 채팅참가자수 */

/* 채팅에참가하는클라이언트들의소켓번호리스트 */

SOCKET client_s[MAX_SOCK];

struct sockaddr_in client_addr, server_addr;

WSADATA wsaBuf;

if(argc < 2)

{

printf(" 실행방법 :%s 포트번호 \n",argv[0]);

return -1;

}

WSAStartup(MAKEWORD(2, 2), &wsaBuf);

printf(" 대화방서버초기화중 ....\n");

/* 초기소켓생성 */

if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

{

printf("Server: Can't open stream socket.");

return -1;

}

1.15

Page 16: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

/* server_addr 구조체의내용세팅 */

memset((char *)&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(atoi(argv[1])); if (bind(s,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)

{ printf("Server: Can't bind local address.\n");

return -1;

}

/* 클라이언트로부터연결요청을기다림 */

listen(s, 5);

nfds = s + 1; /* 최대소켓번호 +1 */

FD_ZERO(&read_fds);

while(1)

{

/* ( 최대소켓번호 +1) 값을갱신 */

if((num_chat-1) >= 0) nfds = client_s[num_chat-1] + 1;

/* 읽기변화를감지할소켓번호를 fd_set 구조체에지정 */

FD_SET(s, &read_fds);

for(i=0; i<num_chat; i++) FD_SET(client_s[i], &read_fds);

1.16

Page 17: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

/*--------------------------------------- select() 호출 ----------------------------------------- */

if (select(0, &read_fds, (fd_set *)0, (fd_set *)0,(struct timeval *)0) == SOCKET_ERROR)

{

printf("select error\n");

return -1;

}

/*------------------------------ 클라이언트연결요청처리 ------------------------------- */

if(FD_ISSET(s, &read_fds))

{

clilen = sizeof(client_addr);

client_fd = accept(s, (struct sockaddr *)&client_addr, &clilen);

if(client_fd != -1)

{

/* 채팅클라이언트목록에추가 */

client_s[num_chat] = client_fd;

num_chat++;

send(client_fd, start, strlen(start), 0);

printf("%d 번째사용자추가 .\n",num_chat);

}

}

1.17

Page 18: (분산 통신 실습)  :  소켓( Sockets)

chat_server.c

/*------ 임의의클라이언트가보낸메시지를모든클라이언트에게방송 ----- */

for(i = 0; i < num_chat; i++)

{

if(FD_ISSET(client_s[i], &read_fds))

{

if((n = recv(client_s[i], rline, MAXLINE,0)) > 0)

{

rline[n] = '\0';

/* 종료문자입력시채팅탈퇴처리 */

if (exitCheck(rline, escapechar, 5) == 1)

{

shutdown(client_s[i], 2);

if(i != num_chat-1) client_s[i] = client_s[num_chat-1];

num_chat--;

continue;

}

/* 모든채팅참가자에게메시지방송 */

for (j = 0; j < num_chat; j++) send(client_s[j], rline, n, 0);

printf("%s\n", rline);

}

}

}

}

closesocket(s);

WSACleanup();

} 1.18

Page 19: (분산 통신 실습)  :  소켓( Sockets)

chat_client.c

/*-----------------------------------------------------------------------------------------

파일명 : chat_client.c

기 능 : 서버에접속한후키보드의입력을서버에전달하고 ,

서버로부터오는메시지를화면에출력한다 .

컴파일 : VC++ 6.0

컴파일옵션 : /MT

LIB : ws2_32.lib

실행예 : chat_client 203.252.65.3 4001 사용자 _ID

작성일 : 2003.03.06 made by JAXAL

-------------------------------------------------------------------------------------------*/

#include<stdio.h>

#include<winsock2.h>

#include<process.h>

#define MAXLINE 1024

#define MAX_SOCK 512

char *escapechar = "exit\n";

SOCKET s; /* 서버와연결된소켓번호 */

struct Name {

char n[20]; /* 대화방에서사용할이름 */

int len; /* 이름의크기 */

} name;

unsigned __stdcall ReceiveThreadFunc(void* pArguments);

1.19

Page 20: (분산 통신 실습)  :  소켓( Sockets)

chat_client.c

int main(int argc, char *argv[])

{

char line[MAXLINE], sendline[MAXLINE+1];

int size;

unsigned int threadID;

struct sockaddr_in server_addr;

WSADATA wsaBuf;

HANDLE hThread;

if( argc < 4 )

{

printf(" 실행방법 : %s 호스트 IP 주소포트번호사용자이름 \n", argv[0]);

return -1;

}

WSAStartup(MAKEWORD(2, 2), &wsaBuf);

/* 채팅참가자이름구조체초기화 */

sprintf(name.n, "[%s]", argv[3]);

name.len = strlen(name.n);

/* 소켓생성 */

if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)

{

printf("Client : Can't open stream socket.\n");

return -1;

}

1.20

Page 21: (분산 통신 실습)  :  소켓( Sockets)

chat_client.c

/* 채팅서버의소켓주소구조체 server_addr 초기화 */

memset((char *)&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = inet_addr(argv[1]);

server_addr.sin_port = htons(atoi(argv[2]));

/* 연결요청 */

if(connect(s, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)

{

printf("Client : Can't connect to server.\n");

return -1;

}

else

{

printf(" 접속에성공했습니다 ..\n");

}

hThread = (HANDLE)_beginthreadex(NULL, 0, &ReceiveThreadFunc, (void*)s, 0, &threadID);

1.21

Page 22: (분산 통신 실습)  :  소켓( Sockets)

chat_client.c

/* ------------------ 키보드입력처리 ----------------------*/

while(1)

{

memset(sendline, 0, sizeof(sendline));

scanf("%s",sendline);

size = strlen(sendline);

sprintf(line, "%s %s", name.n, sendline);

if(send(s, line, size + name.len + 1, 0) != (size+name.len+1))

{

printf("Can't send message\n");

return -1;

}

if (size == 4 && strncmp(sendline, escapechar, 4) == 0)

{

break;

}

}

CloseHandle(hThread);

WSACleanup();

return 0;

}

1.22

Page 23: (분산 통신 실습)  :  소켓( Sockets)

chat_client.cunsigned __stdcall ReceiveThreadFunc(void* pArguments)

{

SOCKET s = (SOCKET)pArguments;

fd_set read_fds;

FD_ZERO(&read_fds);

while(1)

{

/* --------------------------- selelct() 호출 ------------------------------- */

FD_SET(s, &read_fds);

if(select(0, &read_fds, NULL, NULL, NULL) == SOCKET_ERROR)

{

printf("select error\n");

return -1;

}

/*---------------- 서버로부터수신한메시지처리 ---------------*/

if (FD_ISSET(s, &read_fds))

{

char recvline[MAXLINE];

int size;

if ((size = recv(s, recvline, MAXLINE, 0)) != SOCKET_ERROR)

{

recvline[size] = '\0';

printf("%s \n", recvline);

}

}

} /* end of while() */

closesocket(s);

}1.23