이번 포스팅에서는
TCP/IP 프로그래밍을 통해서 서버와 클라이언트 간의 단방향 통신(클라이언트 -> 서버)을 구현해 보겠습니다.
먼저 결과 화면을 먼저 살펴보자면,
위 사진처럼 클라이언트에서 "Hello"라고 메세지를 보내게되면
서버 측에서 "Hello"라는 메세지를 받는 형식입니다.
구축 과정은 이렇습니다.
[서버]
WSAStartup()
▼
socket()
▼
bind()
▼
listen()
▼
accept()
▼
[send, recv]
▼
closesocket()
▼
WSACleanup()
[클라이언트]
WSAStartup()
▼
socket()
▼
connect()
▼
[send, recv]
▼
closesocket()
▼
WSACleanup()
이 순서로 구축해 나가게 됩니다.
이 각 과정을 일상생활에서 전화를 통해 상대방과 통화를 하는것으로 예를 들자면,
WSAStartup() -> 전화기를 사용할 수 있는 환경을 만드는 작업(초기화)
socket() -> 전화기를 구매
bind() -> 전화번호 부여
listen() -> 전화기에 케이블연결
accept() -> 수화기를 들어 전화를 받는 행위
[send, recv] -> 고객과 소통(통화)
Closesocket() -> 전화기를 버림
WSACleanup() -> 전화기 사용을 마침
이런식으로 설명할 수 있습니다.
여기서 클라이언트는 서버와 달리 bind(), listen()메소드가 없이 바로 connect()메소드로 넘어가게 되는데, connect()는 전화를 거는 행위 로 보시면 되겠습니다.
서버와 클라이언트 소스코드는 첨부파일로 올려놨으니, 다음 포스팅에서 서버측과, 클라이언트측 소스코드를 좀 더 자세히 알아보도록 하겠습니다.
<▼server.c>
//server.c #include <winsock2.h> #include <stdlib.h> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") #define BUFSIZE 512 // 소켓 함수 오류 출력 후 종료 int main(int argc, char* argv[]) { int retval; // 윈속 초기화 WSADATA wsa; if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) return -1; // socket() SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0); if(listen_sock == INVALID_SOCKET) return -1; // bind() SOCKADDR_IN serveraddr; ZeroMemory(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(9000); serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); retval = bind(listen_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr)); if(retval == SOCKET_ERROR) return -1; // listen() retval = listen(listen_sock, SOMAXCONN); if(retval == SOCKET_ERROR) return -1; // 데이터 통신에 사용할 변수 SOCKET client_sock; SOCKADDR_IN clientaddr; int addrlen; char buf[512]; while(1){ // accept() addrlen = sizeof(clientaddr); client_sock = accept(listen_sock, (SOCKADDR *)&clientaddr, &addrlen); if(client_sock == INVALID_SOCKET){ continue; } printf("\n[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); // 클라이언트와 데이터 통신 while(1){ // 데이터 받기 retval = recv(client_sock, buf, BUFSIZE, 0); if(retval == SOCKET_ERROR){ break; } else{ // 받은 데이터 출력 buf[retval] = '\0'; printf("%s", buf); } } // closesocket() closesocket(client_sock); printf("\n[TCP 서버] 클라이언트 종료: IP 주소=%s, 포트 번호=%d\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); } // closesocket() closesocket(listen_sock); // 윈속 종료 WSACleanup(); return 0; }
<▼client.c>
#include <winsock2.h> #include <stdlib.h> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") int main(void) { int retval; char buf1[10], buf2[10]; WSADATA wsa; if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) return -1; SOCKET tcp_sock = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN servaddr; ZeroMemory(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(9000); servaddr.sin_addr.s_addr = inet_addr("192.168.0.13"); retval = connect(tcp_sock, (SOCKADDR *)&servaddr, sizeof(servaddr)); printf("Input data(below 10 char) : "); scanf("%s",buf1); retval = send(tcp_sock, buf1, strlen(buf1), 0); retval = recv(tcp_sock, buf2, sizeof(buf2), 0); buf2[retval]='\0'; printf("Send data: %s, Recv data: %s \n", buf1, buf2); Sleep(210000); return 0; }