2011년6월28일_TCP/IP socket programming (소켓 프로그래밍)
● 어제(6/27) 수업 중 프로토콜에 관해…
1. 프로토콜(Protocol)–종단시스템간어떻게데이터교환을할것인지정한통신규약
2. TCP/IP –호스트들이상호통신하기위한표준화된프로토콜
3. TCP/IP 프로토콜계층구조
소켓은 전송계층을 사용하며 컴퓨터(Server)와 컴퓨터(Client)를 연결해 주는 도구로 아래와 같이,
운영체제와 응용프로그램 사이에 위치하는 운영체제가 만들어 주는 S/W적인 장치를 말한다.
소켓을 생성한다는 것은 시스템 내부적으로 통신에 필요한 리소스를 할당하는 것을 의미한다.
● 소켓통신의 흐름
전화통화는 전화를 걸고 응답을 기다린 뒤에 받으면 회선이 연결되어 통화를 한다.
그 후 통화가 끝났으면 회선을 끊는다.
소켓통신도 전화통화와 비슷하다.
최초 socket()로 소켓을 생성하는 것은 운영체제로 부터 통신을 위한 도구(전화기)를 받는 것과 같다.
그 후 서버측에선 bind()로 IP주소와 port번호를 할당받는다. 다음 listen()로 Client의 요청을 대기하며 기다리게 된다.
Client측에서 connect()로 서버에 연결요청을 하면 서버는 accept()로 연결을 수락하게 되고 서로 통신할 수 있게 된다.
write()로 상대편에게 데이터를 보내고, read()로 수신된 데이터를 메모리(변수)로 읽어 들인다.
데이터통신이 끝났으면 close()로 소켓을 닫아 자원을 운영체제로 돌려준다.
● 파일(장치)을 여는 open( )
1: #include<fcntl.h>
2: #include <sys/types.h>
3: #include <sys/stat.h>
4: //열기 실패시 -1 , 열기 성공시엔 파일디스크립터 반환
5: int open(const char *path, int flag);
● 파일(장치)에 데이터를 기록하는 write( )
1: #include <unistd.h>
2: //반환값은 성공시전달한바이트수, 실패시-1 리턴
3: ssize_t write(int fildes, const void *buf, size_tnbytes);
● 파일(장치)에서 데이터를 읽어오는 read( )
1: //반환값은 성공시수신한바이트수(단EOF 만나면0), 실패시-1 리턴
2: ssize_t read(int fildes, void *buf, size_tnbytes);
● 파일(장치)를 닫는 close( )
1: #include <unistd.h>
2: //fildes : 닫아줄파일의파일디스크립터, 성공시 0, 실패시 -1을 반환
3: int close(int fildes);
상기의 함수들은 모두 일을 수행하지 못 하였을 때 -1을 반환한다.
● 데이터 읽기/쓰기 함수 read( )/write( )
1: #include <unistd.h>
2: //성공시전달한바이트수, 실패시-1 리턴
3: ssize_t write(int fildes, const void *buf, size_tnbytes);
4: //성공시수신한바이트수(단EOF 만나면0), 실패시-1 리턴
5: ssize_t read(int fildes, void *buf, size_tnbytes);
ssize_t는 stdio.h에 unsigned int형으로 정의되어 있다.
//함수들에 대한 자세한 설명은 추후 시간나면;;;
TCP/IP소켓 프로그래밍 예제코드 |
아래 실습에 사용된 예제코드는 모두 통신절차에 따른다.
서버프로그램 실행 후 클라이언트 프로그램을 실행해야 한다.
그리고 한 대의 PC로 실습할 수 있도록 loopback주소를 사용하여 테스트한다.
포트번호는 9190이다.
연결이 되면 서버에서 클라이언트로 단방향 문자열전송을 한 후에 바로 소켓을 닫고 종료된다.
다시 서버프로그램을 실행하면 bind() 에러가 떠서 주소를 할당 받을 수 없는 상태가 되나,
일정 시간(1~2분)이 지나면 다시 서버를 운영할 수 있는 상태가 된다.
이 부분에 대해 알아 보니 운영체제의 자원을 돌려 받아 재활용해야 한다는데 잘 모르겠다.
좀 더 조사해 봐야겠다.
프로그램의 흐름만 알아보면,
서버측에서,
socket( )로 소켓을 만들고,
bind( )로 주소(자원)를 할당받고,
listen( )로 클라이언트의 요청을 기다린다. 클라이언트측에서 connect( )로 연결을 요청하면,
서버측에서,
accept( )로 연결을 수락하고 서로 연결이 된다.
write( )로 “수만: hello world!\n”문자열을 전송하면, 클라이언트측에서 read( )로 수신받아 화면에 출력하고,
close( )로 소켓을 닫음으로써 통신이 종료된다.
● 서버측 문자열송신 예제코드
1: // helloworld_server.c
2:
3: #include <stdio.h>
4: #include <stdlib.h>
5: #include <string.h>
6: #include <unistd.h>
7: #include <arpa/inet.h>
8: #include <sys/types.h>
9: #include <sys/socket.h>
10:
11: void error_handling(char *);
12:
13: int main()
14: {
15: int serv_sock;
16: int clnt_sock;
17: struct sockaddr_in serv_addr;
18: struct sockaddr_in clnt_addr;
19: int clnt_addr_size;
20: char message[] = "수만: Hello World!\n";
21:
22: //서버 소켓 생성
23: serv_sock = socket(PF_INET, SOCK_STREAM, 0);
24:
25: if(-1 == serv_sock)
26: {
27: error_handling("socket() error");
28: }
29:
30: memset(&serv_addr, 0, sizeof(serv_addr));
31: serv_addr.sin_family = AF_INET;
32: serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
33: serv_addr.sin_port = htons(9190);
34:
35: //소켓에 주소 할당
36: if(-1 == bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
37: {
38: error_handling("bind() error");
39: }
40:
41:
42: //연결 요청 대기상태로 진입
43: if(-1 == listen(serv_sock, 5))
44: {
45: error_handling("listen() error");
46: }
47:
48: //연결 요청 수락
49: clnt_addr_size = sizeof(clnt_addr);
50: clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size);
51:
52: if(-1 == clnt_sock)
53: {
54: error_handling("accept() error");
55: }
56:
57: //데이터 전송
58: write(clnt_sock, message, sizeof(message));
59:
60: //연결 종료
61: close(clnt_sock);
62: close(serv_sock);
63:
64: return 0;
65: }
66:
67: void error_handling(char * message)
68: {
69: fputs(message, stderr);
70: fputc('\n', stderr);
71: exit(1);
72: }
73:
74:
75:
● 클라이언트측 문자열 수신 예제코드
1: // helloworld_client.c
2:
3: #include <stdio.h>
4: #include <stdlib.h>
5: #include <string.h>
6: #include <unistd.h>
7: #include <arpa/inet.h>
8: #include <sys/types.h>
9: #include <sys/socket.h>
10:
11: void error_handling(char *);
12:
13: int main()
14: {
15: int sock;
16: struct sockaddr_in serv_addr;
17: char message[30];
18: int str_len;
19:
20: //서버 접속을 위한 소켓 생성
21: sock = socket(PF_INET, SOCK_STREAM, 0);
22: if(-1 == sock)
23: {
24: error_handling("socket() error");
25: }
26:
27: memset(&serv_addr, 0, sizeof(serv_addr));
28: serv_addr.sin_family = AF_INET;
29: serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
30: serv_addr.sin_port = htons(9190);
31:
32: //서버로 연결 요청
33: if(-1 == connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)))
34: {
35: error_handling("connect() error");
36: }
37:
38: //데이터 수신
39: str_len = read(sock, message, sizeof(message) - 1);
40:
41: if(-1 == str_len)
42: {
43: error_handling("read() error");
44: }
45:
46: message[str_len] = 0;
47:
48: printf("Message from server : %s \n", message);
49:
50: //연결 종료
51: close(sock);
52:
53: return 0;
54: }
55:
56: void error_handling(char * message)
57: {
58: fputs(message, stderr);
59: fputc('\n', stderr);
60: exit(1);
61:
62: return ;
63: }
'내장형하드웨어 > 일일보고서' 카테고리의 다른 글
2011년6월29일_소켓통신의 흐름과 TCP/IP통신 예제코드 첫 부분 분석 (0) | 2011.06.30 |
---|---|
2011년6월28일_예제 p11-9.c, file descriptor(=파일핸들러), 버퍼사이즈에 대한 고찰, HexaView로 코드영역/파일들 읽어 보기, 매직넘버, ELF/PE구조 (임시제목) (0) | 2011.06.29 |
2011년6월27일_리다이렉션(Redirection) (0) | 2011.06.28 |
2011년6월27일_네트워크, 패킷, 프로토콜, IP주소, 포트번호, 루프백주소, 소켓이란? (0) | 2011.06.28 |
2011년6월24일_고수준/저수준파일입출력(임시제목) (0) | 2011.06.27 |