클라이언트 서버 소켓 - keullaieonteu seobeo sokes

소켓 프로그래밍

1. 네트워크 프로그래밍 개론

소켓 (Socket)

● 프로세스간 상호 양방향 통신 방식

- 각 호스트 간의 통신 시 구축되는 물리적인 연결 종단점

- 파일 처리 방식으로 다룰 수 있는 기술자 (Descriptor) 제공

- 각 종단점으로써 여러 속성을 보유

● 네트워크를 통한 통신 가능

- TCP/IP 에 대한 인터페이스 제공

● 소켓을 통한 프로세스 통신은 클라이언트/서버 모델(client/server model)에 기초

파일기술자와 소켓기술자

소켓 참조

- open(2) 함수를 호출 하여 새로운 파일을 열었을 때, 리눅스 커널에서 파일 기술자를 반환

소켓의 유형

● Stream Socket

- 연결 지향형 (TCP 기반)

- 소켓 간의 연결 후 데이터 전송

- 일상 생활의 전화 개념과 유사

● Datagram Socket

- 비 연결형 (UDP 기반)

- 송수신 시 도착지 주소 필수

- 일상 생활의 편지 개념과 유사

● Raw Socket

- 저 수준 프로토콜 액세스

- ICMP, OSPF 등이 사용

- IP 계층 이용

소켓 연결 과정

1. 서버가 명명된 소켓을 생성

2. 클라이언트가 명명되지 않은 소켓을 생성하고, 연결을 요청

3. 클라이언트가 연결됨. 서버는 원래 명명된 소켓을 유지

소켓의 함수

● socket() : 사용하고자 하는 통신 프로토콜을 지정

- int socket(int domain, int type, int protocol);

● socketpair() : 소켓 연결의 한 쌍을 지정

- int socketpair(int domain, int type, int protocol, int sv[2]);

● close() : 소켓의 연결을 종료

- int close(int fd);

● shutdown() : 선택적 소켓의 연결을 종료

- int shutdown(int fd, int option);

● bind() : 소켓에 이름을 결합

- int bind(int sockfd, sockaddr * myaddr, int addrlen);

● listen() : 서버 프로세스가 통신할 연결기반 소켓 설정

- int listen (int sockfd, int size);

● accept() : 서버 프로세스에서 클라이언트 소켓과 연결을 설정 하기 위해 호출 

- int accept (int sockfd, struct sockaddr *peer, int *addrlen);

● connect() : 클라이언트가 서버에 연결을 요청하기 위해 호출

- int connect (int socfd, struct sockaddr *servaddr, int addrlen);

● write () : 다른 소켓에 메시지 전송

- ssize_t write (int fd, const void *buf, size_t count);

● read() : 다른 소켓에서 메시지 수신

- ssize_t read (int fd, void *buf, size_t count);

예제

Cook.c

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

#include <stdio.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#define DEFAULT_PROTOCOL 0

int main()

{

int clientFd,serverLen,result;

struct sockaddr_un serverUNIXAddress;

struct sockaddr* serverSockAddrPtr;

serverSockAddrPtr=(struct sockaddr*)&serverUNIXAddress;

serverLen=sizeof(serverUNIXAddress);

// 양방향, 디폴트 프로토콜의 유닉스 소켓생성

clientFd = socket(AF_UNIX, SOCK_STREAM, DEFAULT_PROTOCOL);

serverUNIXAddress.sun_family=AF_UNIX; //서버 도메인

strcpy(serverUNIXAddress.sun_path,"recipe"); //서버 이름

do//서버와 연결되기까지 루프

result = connect(clientFd,serverSockAddrPtr,serverLen);

if(result==-1) sleep(1); //대기 후 다시 시도

}while(result==-1);

readRecipe(clientFd); //조리법 읽기

close(clientFd); //소켓 닫기

return 0;

}

void readRecipe(int fd)

{

char str[200];

while(readLine(fd,str)) //입력 끝까지 줄 읽기

printf("%s\n",str); //소켓으로부터 줄 출력

}

void readLine(int fd, char* str)

{

int n;

do{

n=read(fd,str,1);

}

while(n>0 && *str++ != NULL);

return (n>0);

}

http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

Chef.c

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

#include <stdio.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h> // AF_UNIX 소켓용

#include <stdlib.h>

#define DEFAULT_PROTOCOL 0

int main()

{

int serverFd,clientFd,serverLen,clientLen;

struct sockaddr_un serverUNIXAddress; // 서버 주소

struct sockaddr_un clientUNIXAddress; //클라이언트 주소

struct sockaddr* serverSockAddrPtr; //서버 주소에 대한 포인터

struct sockaddr* clientSockAddrPtr; //클라이언트 주소에 대한 포인트

signal(SIGCHLD,SIG_IGN); //좀비를 방지하기 위해 자식-죽음 시그널은 무시

serverSockAddrPtr=(struct sockaddr*)&serverUNIXAddress;

serverLen=sizeof(serverUNIXAddress);

clientSockAddrPtr=(struct sockaddr*)&clientUNIXAddress;

clientLen=sizeof(clientUNIXAddress);

//양방향, 디폴트 프로토콜의 유닉스 소켓 생성

serverFd=socket(AF_UNIX,SOCK_STREAM,DEFAULT_PROTOCOL);

serverUNIXAddress.sun_family=AF_UNIX; //도메인 유형 설정

strcpy(serverUNIXAddress.sun_path,"recipe"); // 이름 설정

unlink("recipe"); //이미 존재한다면, 파일 제거

bind(serverFd,serverSockAddrPtr,serverLen); //파일 생성

listen(serverFd,5); //대기 중인 연결의 최대 길이

while(1){

clientFd=accept(serverFd,clientSockAddrPtr,&clientLen); //클라이어트 연결 받기

printf("Server called!");

if(fork()==0){ //조리법을 전송할 자식 생성

writeRecipe(clientFd); //조리법 전송

close(clientFd); //소켓 닫기

exit(/*EXIT_SUCCES*/0); //종료

}else

close(clientFd); //클라이언트 기술자 닫기

}

return 0;

}

void writeRecipe(int fd)

{

static char* line1="spam,spam,spam,spam,spam,";

static char* line2="spam, and spam.";

write(fd,line1,strlen(line1)+1); //첫째줄 쓰기

write(fd,line2,strlen(line2)+1); //두번째 줄 쓰기

}

http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

2. 서버/클라이언트

클라이언트/서버모델

Server/Client = 단일 프로그램

Server는 Client의 연결 요청 대기 >> 정보 및 서비스 제공

Client는 Server에 정보 및 서비스의 제공을 요청하고 응답을 기다리는 호스트를 의미

서버의 유형

서버 유형의 결정

- 클라이언트 접속 빈도, 얼마만큼의 클라이언트가 어느 정도의 빈도로 접속하는지에 따름

- 필요한 규모와 처리량, 주고 받는 데이터의 크기가 어느 정도이며 필요한 대역폭에 따름

- 데이터의 안정성

클라이언트 간 혹은 서버와 클라이언트 간의 데이터 신뢰도

요즘의 네트어ㅜ크 망은 설비가 잘 되어 있어 안정성에 대한 문제는 줄어 듬

단순 연결형 Client/Server

1. 서버와 클라이언트의 소켓 생성

2. 서버는 BIND 작업 후 대기 큐 설정 (LISTEN)

3. 서버는 클라이언트의 접속 대기 (ACCEPT)

4. 클라이언트가 서버로 접속 시도 (CONNECT)

5. 접속이 완료 되면 서버와 클라이언트 간의 데이터 송수신 작업

6. 서버 종료 작업

7. 서버와 클라이언트 소켓 닫음 (CLOSE)

동서 처리 연결형 Client/Server

1. 서버와 클라이언트의 통신 초기화 (SELECT 관련)

2. 서버와 클라이언트의 소켓 생성

3. 서버는 BIND 작업 후 대기 큐 설정 (LISTEN)

4. 서버는 클라이언트의 접속 대기 (ACCEPT)

5. 클라이언트가 서버로 접속 시도 (CONNECT)

6. 서버 측의 기술자에 이벤트가 발생

7. 접속 처리 후 클라이언트와 데이터 송수신

8. 서버 종료 작업

9. 서버와 클라이언트 소켓 닫음 (CLOSE)

단순 비연결형 Client/Server

1. 서버와 클라이언트의 소켓 생성

2. 서버는 BIND 작업 후 대기

3. 서버와 클라이언트 간의 데이터 송수신

4. 서버는 단순히 클라이언트로 데이터 전송

5. 서버 종료 작업

6. 서버와 클라이언트의 소켓 닫음

양쪽 모두 상대방의 주소를 알고 있어야 지속적인 데이터 송수신이 가능함을 기억

동시 처리 비연결형 Client/Server

1. 서버와 클라이언트의 소켓 생성

2. 서버는 BIND 작업 후 대기

3. 클라이언트가 서버로 접속 데이터 송신

4. 서버는 클라이언트의 접속시 마다 클라이언트 처리용 스레드 생성

5. 이 후의 클라이언트와의 통신은 각각의 스레드가 담당

6. 서버 종료 작업

7. 종료 시 스레드를 통한 클라이언트 종료

8. 서버와 클라이언트 소켓 닫음 (CLOSE)

tcp_client.c

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/types.h>

#include <sys/socket.h>

void error_handling(char *message);

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

{

int sock;

struct sockaddr_in serv_addr;

char message[30];

int str_len=0;

int idx=0, read_len=0;

if(argc!=3){

printf("Usage : %s <IP> <port>\n", argv[0]);

exit(1);

}

sock=socket(PF_INET, SOCK_STREAM, 0);

if(sock == -1)

error_handling("socket() error");

memset(&serv_addr, 0sizeof(serv_addr));

serv_addr.sin_family=AF_INET;

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

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

if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1

error_handling("connect() error!");

while(read_len=read(sock, &message[idx++], 1))

{

if(read_len==-1)

error_handling("read() error!");

str_len+=read_len;

}

printf("Message from server: %s \n", message);

printf("Function read call count: %d \n", str_len);

close(sock);

return 0;

}

void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);

}

http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs

tcp_server.c

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <sys/types.h>

#include <sys/socket.h>

void error_handling(char *message);

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

{

int serv_sock;

int clnt_sock;

struct sockaddr_in serv_addr;

struct sockaddr_in clnt_addr;

socklen_t clnt_addr_size;

char message[]="Hello World!";

if(argc!=2){

printf("Usage : %s <port>\n", argv[0]);

exit(1);

}

serv_sock=socket(PF_INET, SOCK_STREAM, 0);

if(serv_sock == -1)

error_handling("socket() error");

memset(&serv_addr, 0sizeof(serv_addr));

serv_addr.sin_family=AF_INET;

serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

serv_addr.sin_port=htons(atoi(argv[1]));

if(bind(serv_sock, (struct sockaddr*&serv_addr, sizeof(serv_addr))==-1)

error_handling("bind() error"); 

if(listen(serv_sock, 5)==-1)

error_handling("listen() error");

clnt_addr_size=sizeof(clnt_addr);  

while(1)

{//클라이언트가 접속하면 접속을 허용하고 클라이언트 소켓을 생성함

clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);

if(clnt_sock==-1){

error_handling("accept() error");}

printf("Client: %s\n",inet_ntoa(clnt_addr.sin_addr));

if(write(clnt_sock,message,sizeof(message))<=0)

{perror("write error:");}

close(clnt_sock);

}

close(serv_sock);

return 0;

}

void error_handling(char *message)

{

fputs(message, stderr);

fputc('\n', stderr);

exit(1);

}

http://colorscripter.com/info#e" target="_blank" style="text-decoration:none; color:white">cs