순천향대학교컴퓨터학부이상정 1 학습내용 인터넷과 TCP/IP 프로토콜 소켓의생성과해제 소켓주소표현 연결지향소켓프로그래밍 순천향대학교컴퓨터학부이상정 2
인터넷과 TCP/IP 프로토콜 순천향대학교컴퓨터학부이상정 3 인터넷구조의프로토콜계층 인터넷구조의프로토콜계층 응용계층 (application layer) 응용서비스제공 http, ftp, smtp, telnet, 트랜스포트계층 (transport layer) 단말호스트사이의데이터전송을기술 TCP(Transmission Control Protocol), UDP(User Datagram Protocol) 네트워크계층 (network layer) 패킷들의경로를라우팅 IP(Internet Protocol) 네트워크접근계층 링크계층 (link layer) 이더넷 (Ethernet), 토큰링 (TokenRing) 물리계층 (physical layer) 순천향대학교컴퓨터학부이상정 4
TCP/IP 인터넷상의모든컴퓨터는데이터를 TCP/IP 프로토콜로전송 순천향대학교컴퓨터학부이상정 5 TCP 와 UDP TCP(Transmission Control Protocol) 전송방식 전화와비슷한통신망으로항상연결되어야사용가능한방식 양방향통신이가능 데이터를전송하는측에서보낸데이터를반대쪽에서수신했다고응답해주어야만두컴퓨터간에데이터교환이이루어지는신뢰성을기반으로하는통신방식 상대방이자료를받지못했다면재송신 UDP(User Datagram Protocol) 전송방식 편지와비슷한비연결형통신방식 단방향통신 상대방에게데이터가 100% 확실하게전달되었는지알지못함 부하가적고, 연결과정이없기때문에데이터를빠르게전송 순천향대학교컴퓨터학부이상정 6
소켓의정의 소켓 (socket) 은 TCP/IP 를이용하는 API 1982년 BSD(Berkeley Software Distribution) 유닉스 4.1에서처음소개 윈도우소켓 (Winsock), 자바소켓 BSD 소켓과호환성 여기서프로그램코드의호환성이아니라서로통신을할수있는통신프로토콜의호환성 소켓은소프트웨어로작성된통신접속점 응용프로그램은소켓을통하여통신망으로 IP 패킷을송수신 Windows CE 에서지원하는 Winsock API Winsock 1.1: 작은크기 Winsock 2.0: 다양한기능 순천향대학교컴퓨터학부이상정 7 소켓인터페이스의위치 순천향대학교컴퓨터학부이상정 8
소켓의생성과해제 순천향대학교컴퓨터학부이상정 9 소켓생성및해제절차 윈속소켓생성절차 헤더파일선언과라이브러리링크 #include <Winsock2.h> #pragma comment(lib,"ws2.lib") 윈속초기화, WSAStartup() 함수 윈속버전과라이브러리 (ws2.dll) 초기화 소켓생성, socket() 함수 주소체계및소켓타입기술하여소켓생성 연결및데이터송수신 소켓해제, closesocket() 함수 윈속해제, WSACleanup() 함수 윈속라이브러리 (ws2.dll) 사용종료 순천향대학교컴퓨터학부이상정 10
윈속 API (1) 윈속 API int WSAStartup( WORD wversionrequested, LPWSADATA lpwsadata ); 윈속버전과라이브러리 (ws2.dll) 초기화 성공하면 0을리턴 wversionrequested: 사용하려는 winsock 버전 MAKEWORD (2, 2) lpwsadata: WSADATA 구조체포인터 윈속의구현한 DLL 의세부정보제공 예 WSADATA wsadata; INT nres = WSAStartup( t (MAKEWORD(22) MAKEWORD(2,2), &wsadata); int WSACleanup (void); 윈속라이브러리 (ws2.dll) 사용종료 순천향대학교컴퓨터학부이상정 11 윈속 API (2) SOCKET socket( int af, int type, int protocol ); 주소체계및소켓타입기술하여소켓생성 생성된소켓의핸들 ( 소켓디스크립터 ) 리턴 af: 주소체계 (address family) AF_ INET : TCP/IP 통신용소켓 AF_ ARDA : IrDA 용소켓 AF_ BT : Bluetooth 용소켓 type: 소켓타입 SOCK_STREAM: TCP 소켓, Bluetooth 와 IrDA 소켓 SOCK_DGRAM : UDP 소켓 protocol: 사용할프로토콜 사용할프로토콜을명시적으로기술 일반적으로 0 기술 int closesocket( SOCKET s ); 소켓을해제 순천향대학교컴퓨터학부이상정 12
예제 46: 윈속생성및해제예 스크린을터치하면소켓생성후해제 순천향대학교컴퓨터학부이상정 13 예제 46: 코드 (1) #include #pragma <Winsock2.h> comment(lib,"ws2.lib") SOCKET g_hsock = INVALID_SOCKET; SOCKET SocketCreate() { WSADATA wsadata; INT nres = WSAStartup( MAKEWORD(2,2), &wsadata); if (nres!= 0) return FALSE; g_hsock = socket(af_inet, SOCK_STREAM, 0); if (g_hsock == INVALID_SOCKET) return FALSE; return TRUE; void SocketRelease() { closesocket(g_hsock); WSACleanup(); 순천향대학교컴퓨터학부이상정 14
예제 46: 코드 (2) LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch (message) { case WM_LBUTTONDOWN: if (SocketCreate() == FALSE) { MessageBox(NULL,L"SocketCreate Fail",L"", MB_ICONERROR); return 0; else MessageBox(NULL,L"SocketCreate Success",L"", MB_OK); SocketRelease(); break; case WM_COMMAND: 순천향대학교컴퓨터학부이상정 15 소켓주소표현 순천향대학교컴퓨터학부이상정 16
소켓번호, 포트번호, IP 주소의관계 순천향대학교컴퓨터학부이상정 17 소켓주소구조체 (1) 통신객체 ( 클라이언트또는서버 ) 의구체적인주소를표현하기위해다음의세가지가지정 주소체계 (address family) IP 주소 포트번호 위의세가지정보를소켓주소 (socket address) 라고하며구조체 sockaddr 로정의 struct sockaddr { u_short sa_family; /* address family */ char sa_data[14]; /* 주소 */ ; 순천향대학교컴퓨터학부이상정 18
소켓주소구조체 (2) sockaddr 소켓주소구조체에 IP 주소, 포트번호등을직접쓰거나읽기가불편 4바이트의 IP 주소와 2바이트의포트번호를구분하여액세스할수있는인터넷전용소켓주소구조체 sockaddr_in 를정의하여사용 struct in_addr { u_long s_addr; /* 32비트의 IP 주소를저장할구조체 */ ; struct sockaddr_in { short sin_family; /* 주소체계 */ u_short sin_port; /* 16비트포트번호 */ struct in_addr sin_addr; /* 32비트 IP 주소 */ char sin_zero[8]; /* 전체크기를 16바이트로맞추기위한 dummy */ ; 순천향대학교컴퓨터학부이상정 19 호스트바이트정렬 호스트바이트정렬 (host byte ordering) 컴퓨터가메모리에숫자를저장하는순서 프로세서마다다름 Little-endian, big-endian 0xC3E2( 십진수 50146) 의호스트바이트순서비교 순천향대학교컴퓨터학부이상정 20
네트워크바이트정렬 네트워크바이트정렬 (network byte ordering) IP 주소, 포트번호와같은정보를바이트단위로네트워크로전송하는순서 high-order 바이트부터전송 (Big-endian) X86 계열의컴퓨터에서네트워크를통하여전송한숫자를 MC68000 계열의컴퓨터가수신하면바이트순서가뒤바뀌는문제발생 이러한문제를해결하기위하여숫자를네트워크로전송하기전에 htons() 함수를사용하여네트워크바이트정렬변환 반대로네트워크로부터수신한숫자는 ntohs() 함수를사용하여자신의호스트바이트정렬로변환 순천향대학교컴퓨터학부이상정 21 바이트정렬변환함수 unsigned short integer 변환 (2 바이트크기 ) u_short htons( u_short hostshort ); host-to-network 바이트변환 u_short ntohs( u_short netshort ); network-to-host 바이트변환 unsigned long integer 변환 (4 바이트크기 ) ulonghtonl( u_long u_long ulonghostlong ); host-to-network 바이트변환 u_long ntohl( u_long netlong ); network-to-host 바이트변환 순천향대학교컴퓨터학부이상정 22
IP 주소변환함수 주소변환함수 unsigned long inet_addr( const char *cp ); IP 주소문자열을32비트숫자 ( 네트워크바이트정렬 ) 로변환 char *inet_ntoa( struct in_addr in ); 32 비트숫자 ( 네트워크바이트정렬 ) 의 IP 주소를문자열로변환 주소표현예 sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("147.69.209.55"); addr.sin_port = htons(3000); 순천향대학교컴퓨터학부이상정 23 연결지향소켓프로그래밍 순천향대학교컴퓨터학부이상정 24
서버 / 클라이언트구조 연결지향형 (TCP) 소켓프로그래밍은서버와클라이언트로구성 서버는연결포트를개설하고클라이언트의접속을기다림 클라이언트는서버의 IP 주소와포트를사용하여연결접속 서버 소켓생성, socket() 클라이언트 소켓생성, socket() 주소와소켓결합, bind() 연결요청대기, listen() 연결수락, accept() 데이터송신, send() 데이터수신, receive() 연결중단 순천향대학교컴퓨터학부이상정 25 연결요청, connect() 데이터수신, receive() 데이터송신, send() 연결중단 서버함수 서버함수 int bind( SOCKET s, const struct sockaddr FAR *name, int namelen ); 소켓과서버의 IP 주소와포트를연결 name: 소켓주소구조체포인터 namelen: 소켓주소구조체크기 성공하면 0을리턴하고, 에러이면 SOCKET_ERROR를리턴 int listen( SOCKET s, int backlog ); 클라이언트로부터의연결요청을접속대기 backlog: 접속가능한클라이언트개수 성공하면 0을리턴하고, 에러이면 SOCKET_ERROR를리턴 SOCKET accept( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen ); 클라이언트의연결요청을수락 서버와접속된클라이언트와통신하는새로운소켓생성하여리턴 addr: 연결을개시한클라이언트의주소를받을버퍼포인터 addrlen: 주소버퍼크기를가리키는포인터 순천향대학교컴퓨터학부이상정 26
서버함수사용예 (1) int retval; sockaddr_in addr; /// 소켓생성 SOCKET listen_sock = socket(af_inet, SOCK_STREAM, 0); if (listen_sock == INVALID_SOCKET) { MessageBox(NULL,L"SocketCreate Fail",L"", MB_ICONERROR); /// 주소 / 포트지정및연결 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(inaddr_any); // 서버의 IP 주소 addr.sin_port = htons(3000); // 포트번호 retval = bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)); if (retval == SOCKET_ERROR) { MessageBox(NULL,L Bind Fail",L L"", MB_ICONERROR); 순천향대학교컴퓨터학부이상정 27 서버함수사용예 (2) // 클라이언트접속대기 retval = listen(listen_sock, SOMAXCONN); // 클라이언트개수를최대로설정 if (retval == SOCKET_ERROR) { MessageBox(NULL,L Listen Fail",L"",, MB_ICONERROR); return 0; // 클라이언트접속 sockaddr_in client_addr; SOCKET client_sock; int addrlen; addrlen = sizeof(client_addr); client_sock = accept(listen_sock, (struct sockaddr *)&client_addr, &addrlen); if (client_sock == INVALID_SOCKET) { MessageBox(NULL,L Accept Fail",L"", MB_ICONERROR); return 0; 순천향대학교컴퓨터학부이상정 28
클라이언트함수 클라이언트함수 int connect( SOCKET s, const struct sockaddr FAR* name, int namelen ); 지정된주소의서버에연결요청 name: 소켓주소구조체포인터 namelen: 소켓주소구조체크기 성공하면 0을리턴하고, 에러이면 SOCKET_ERROR를리턴 순천향대학교컴퓨터학부이상정 29 클라이언트함수사용예 int retval; sockaddr_in serveraddr; /// 소켓생성 SOCKET sock = socket(af_inet, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(NULL,L"SocketCreate Fail",L"", MB_ICONERROR); return 0; /// 주소 / 포트지정및연결 memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = inet_addr("147.69.209.55"); // 서버의 IP 주소 serveraddr.sin_port sin = htons(3000); // 포트번호 retval = connect(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); if (retval == SOCKET_ERROR) { MessageBox(NULL,L Connect Fail",L L"", MB_ICONERROR); return 0; 순천향대학교컴퓨터학부이상정 30
데이터전송함수 데이터전송함수 int send( SOCKET s, const char FAR* buf, int len, int flags ); 연결된소켓에데이터를송신 buf, len: 송신할데이터버퍼포인터와길이, flags: 0 송신한데이터의길이리턴, 에러시 SOCKET_ERROR 리턴 send(sock, buf, strlen(buf), 0); int recv( SOCKET s, char FAR* buf, int len, int flags ); 연결된소켓으로부터데이터를수신 buf, len: 수신할데이터버퍼포인터와길이, flags: 0 수신한데이터의길이리턴, 에러시SOCKET_ERROR 리턴 recv(sock, buf, strlen(buf), 0); int shutdown( SOCKET s, int how ); 소켓의송수신을비활성화 how: 종료오퍼레이션타입지정 0, 1, 2=SDRECEIVE SD_RECEIVE, SD_SEND, SDSEND SD_BOTH SDBOTH 성공하면 0을리턴, 에러시 SOCKET_ERROR 리턴 int shutdown( SOCKET s int how ); 순천향대학교컴퓨터학부이상정 31 예제 47: TCP 서버 / 클라이언트예 TCP 서버 / 클라이언트로간단한문자열을송수신하는프로그램 각각독립된서버와클라이언트프로그램작성 스크린을터치하면각프로그램시작 실행예 IP 주소 서버 IP: 192.168.1.59, 포트 : 7000 PocketPC PDA 클라이언트 IP: 192.168.1.28 CAP9-STK 실습 인터넷회선연결후실습보드 IP 설정은 DHCP로설정 옆사람과서버와클라이언트역할분담후실습 서버측 IP 주소확인후수정 순천향대학교컴퓨터학부이상정 32
예제 47: 실행결과 서버먼저실행하고스크린터치한후, 클라이언트실행하고스크린터치 순천향대학교컴퓨터학부이상정 33 실습보드 IP 주소설정 순천향대학교컴퓨터학부이상정 34
IP 주소확인 순천향대학교컴퓨터학부이상정 35 예제 47: 서버코드 (1) #include #pragma <Winsock2.h> comment(lib,"ws2.lib") /// 서버프로그램 void start_server(hwnd hwnd) { HDC hdc = GetDC(hWnd); WCHAR sztext[1024], szmsg[1024], ip[50]; CHAR bsztext[1024], bip[50]; SIZE sz; int y = 50, retval; /// 윈속초기화 WSADATA wsadata; retval = WSAStartup(MAKEWORD(2,2), 2) &wsadata); if (retval!= 0) { MessageBox(NULL,L"WSAStartup Fail",L"", MB_ICONERROR); /// 소켓생성 sockaddr_in addr; SOCKET listen_sock = socket(af_inet, SOCK_STREAM, 0); if (listen_sock sock == INVALID_SOCKET) { MessageBox(NULL,L"SocketCreate Fail",L"", MB_ICONERROR); 순천향대학교컴퓨터학부이상정 36
/// 주소 / 포트지정및연결 memset(&addr, 0, sizeof(addr)); addr.sin_family =AF AF_INET; addr.sin_addr.s_addr = htonl(inaddr_any); addr.sin_port = htons(7000); 예제 47: 서버코드 (2) // 서버의 IP 주소 // 포트번호 retval = bind(listen_sock, sock (struct sockaddr *)&addr, sizeof(addr)); if (retval == SOCKET_ERROR) { MessageBox(NULL,L"Bind Fail",L"", MB_ICONERROR); /// 클라이언트접속대기 retval = listen(listen_sock, SOMAXCONN); // 클라이언트개수를최대로설정 if (retval == SOCKET_ERROR) ERROR) { MessageBox(NULL,L"Listen Fail",L"", MB_ICONERROR); /// 메시지출력 wcscpy(szmsg, L"Server Start..."); ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); wcscpy(szmsg, L"Waiting for client connection... "); GetTextExtentPoint32(hdc, szmsg, wcslen(szmsg), &sz); y = y + sz.cy; ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); 순천향대학교컴퓨터학부이상정 37 예제 47: 서버코드 (3) /// 클라이언트접속 sockaddr_in client_addr; SOCKET client_sock; int addrlen; addrlen = sizeof(client_addr); client_sock = accept(listen_sock, sock (struct sockaddr *)&client_addr, &addrlen); if (client_sock == INVALID_SOCKET) { MessageBox(NULL,L"Accept Fail",L"", MB_ICONERROR); /// 클라이언트주소출력 strcpy(bip, inet_ntoa(client_addr.sin_addr)); // 숫자 IP주소를문자열로변환 mbstowcs(ip, bip, strlen(bip)+1); // ASCII 문자를유니코드로변환 wsprintf(szmsg, L"Client ClientIP %s, port %d", ip, client_addr.sin_port); y = y + 2*sz.cy; // 다음출력 y 좌표계산 ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); /// 클라이언트로데이터송신 wcscpy(sztext, L"Client is connected"); wcstombs(bsztext, sztext, wcslen(sztext)+1); // 유니코드를 ASCII 문자로변환 retval = send(client_sock, bsztext, strlen(bsztext)+1, 0); // 데이터송신 if (retval == SOCKET_ERROR) ERROR) { MessageBox(NULL,L"Send Fail",L"", MB_ICONERROR); 순천향대학교컴퓨터학부이상정 38
예제 47: 서버코드 (4) /// 클라이언트에서데이터수신 retval = recv(client_sock, bsztext, sizeof(bsztext), 0); // 데이터수신 mbstowcs(sztext, bsztext, strlen(bsztext)+1); // ASCII 문자를유니코드로변환 wsprintf(szmsg, L"Recv> %s", sztext); y = y + 2*sz.cy; if (retval > 0) { ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); else if (retval == 0) { wcscpy(szmsg, L"No received dada from client"); ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); else { MessageBox(NULL,L"Receive Fail",L"", MB_ICONERROR); closesocket(client_sock); closesocket(listen_sock); LRESULT CALLBACK ACK WndProc(HWND hwnd, UINT message, WPARAM AM wparam, LPARAM AM lparam) { switch (message) { case WM_LBUTTONDOWN: start_server(hwnd); break; 순천향대학교컴퓨터학부이상정 39 예제 47: 클라이언트코드 (1) #include #pragma <Winsock2.h> comment(lib,"ws2.lib") /// 클라이언트프로그램 void start_client(hwnd hwnd) { HDC hdc = GetDC(hWnd); WCHAR sztext[1024], szmsg[1024]; CHAR bsztext[1024]; SIZE sz; int y = 50, retval; /// 윈속초기화 WSADATA wsadata; retval = WSAStartup(MAKEWORD(2,2), 2) &wsadata); if (retval!= 0) { MessageBox(NULL,L"WSAStartup Fail",L"", MB_ICONERROR); /// 소켓생성 sockaddr_in serveraddr; SOCKET sock = socket(af_inet, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { MessageBox(NULL,L"SocketCreate Fail",L"", MB_ICONERROR); 순천향대학교컴퓨터학부이상정 40
예제 47: 클라이언트코드 (2) /// 접속할서버주소 / 포트지정및연결 memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family sin = AF_INET; serveraddr.sin_addr.s_addr = inet_addr("192.168.1.59"); // 서버의 IP 주소 serveraddr.sin_port = htons(7000); // 포트번호 retval = connect(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); if (retval == SOCKET_ERROR) { MessageBox(NULL,L"Connection Fail",L"", MB_ICONERROR); /// 메시지출력 wcscpy(szmsg, L"Connecting to the server..."); ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); GetTextExtentPoint32(hdc, sztext, wcslen(szmsg), &sz); y = y + sz.cy; /// 클라이언트에서데이터수신 retval = recv(sock, bsztext, sizeof(bsztext), 0); // 데이터수신 mbstowcs(sztext, bsztext, strlen(bsztext)+1); // ASCII 문자를유니코드로변환 wsprintf(szmsg, L"Recv> %s", sztext); y=y+szcy; y sz.cy; if (retval > 0) { ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); 순천향대학교컴퓨터학부이상정 41 예제 47: 클라이언트코드 (3) else if (retval == 0) { wcscpy(szmsg, L"No received data from the server"); ExtTextOut(hdc, 2, y, 0, NULL, szmsg, wcslen(szmsg), NULL); else { MessageBox(NULL,L"Receive Fail",L"", MB_ICONERROR); /// 클라이언트로데이터송신 wcscpy(sztext, L"Hello, server!"); wcstombs(bsztext, sztext, wcslen(sztext)+1); ) // 유니코드를 ASCII 문자로변환 retval = send(sock, bsztext, strlen(bsztext)+1, 0); // 데이터송신 if (retval == SOCKET_ERROR) { MessageBox(NULL,L"Send Fail",L"", MB_ICONERROR); closesocket(sock); LRESULT CALLBACK ACK WndProc(HWND hwnd, UINT message, WPARAM AM wparam, LPARAM AM lparam) { switch (message) { case WM_LBUTTONDOWN: start_client(hwnd); break; 순천향대학교컴퓨터학부이상정 42
과제 15 예제 47 의 TCP 클라이언트프로그램을다음과같이수정 다이얼로그에서서버의주소와포트번호를입력하도록클라이언트프로그램수정 서버프로그램은그대로사용 순천향대학교컴퓨터학부이상정 43