안 쓰던 블로그
C언어 TCP/IP socket 서버와 클라이언트 연결하기 본문
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 | #include <stdio.h> #include <WinSock2.h> #pragma comment(lib, "wsock32.lib") int main() { SOCKET socketdescriptor, csocketdescriptor; //socket descriptor WSADATA WSAdata; //winsock data struct sockaddr_in socketin; //socket struct struct sockaddr_in client_addr; int size = sizeof(client_addr); if (WSAStartup(WINSOCK_VERSION, &WSAdata) != 0) { //winsock version check printf("WSAStartup failed, %d\n", WSAGetLastError()); return 0; } socketdescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //create TCP/IP socket if (socketdescriptor == INVALID_SOCKET) { printf("Create socket failed, %d\n", WSAGetLastError()); //if socket() get error WSACleanup(); //finish WS2_32.DLL return 0; } socketin.sin_family = AF_INET; //I will use TCP/IP or UDP protocol socketin.sin_port = htons(10000); //I will use FTP server port socketin.sin_addr.s_addr = htonl(ADDR_ANY); //I will access with this(all clinet) IP Address if (bind(socketdescriptor, (struct sockaddr*)&socketin, sizeof(socketin)) == SOCKET_ERROR) { printf("bind failed, %d\n", WSAGetLastError()); closesocket(socketdescriptor); WSACleanup(); return 0; } if (listen(socketdescriptor, SOMAXCONN) != 0) { printf("listen mode failed, %d", WSAGetLastError()); closesocket(socketdescriptor); WSACleanup(); return 0; } printf("Waiting to connect client access... \n"); csocketdescriptor = accept(socketdescriptor, (struct sockaddr*)&client_addr, &size); if (csocketdescriptor == INVALID_SOCKET) { printf("access accept failed, %d", WSAGetLastError()); closesocket(socketdescriptor); WSACleanup(); return 0; } printf("Connect Successful\n"); if (closesocket(socketdescriptor) != 0 || closesocket(csocketdescriptor) != 0) { printf("Remove socket failed, %d", WSAGetLastError()); WSACleanup(); return 0; } if (WSACleanup() != 0) { printf("WSACleanup failed, %u", WSAGetLastError()); return 0; } } | cs |
TCP/IP에서 사용하는 함수들은 WinSock2.h 헤더에 포함되어 있다. 윈도우즈 기반의 소켓 통신을 하기 위해서는 이 헤더가 필요하다.
2번째 줄에서 winsock.h과 WinSock2.h가 보일텐데 둘은 버전 차이로 WinSock.h에 Winsock.h의 대부분이 포함되어 있으므로 보통 2번을 사용한다.
지금 자신이 사용하고 있는 버전은 이렇게 확인할 수 있다.
1 | puts(WSAdata.szDescription); | cs |
4번째 줄에서 TCP/IP에서 사용하는 WSA~나 bind, listen 함수 등은 C Runtime Library에 있지 않기때문에 #pragma로 wsock32.lib 라이브러리를 불러온다.
소켓은 크게 열기, 보내기(받기), 닫기로 구성된다.
열기: socket(); 함수로 소켓을 개방한다. 위 코드에서는 이 부분에 해당한다.
18 | socketdescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //create TCP/IP socket | cs |
socket(); 함수는 다음과 같이 사용한다.
1 | SOCKET __stdcall socket(int af, int type, int protocol) | cs |
26~28번째 줄에서 프로토콜, 포트 번호, 접근 허용 범위를 설정한다.
서버의 핵심인 bind()와 listen()이 30~42줄에 있다. 두 함수는 클라이언트로부터 접속이 있을 때까지 기다린다.
접속 시도는 큐에 저장되고, accept()함수가 큐에서부터 데이터를 꺼내오는 역할은 한다.
csocketdescriptor라는 소켓 디스크립터가 연결된 클라이언트와 데이터를 주고받는다.
받기: 이 코드는 단순 연결만 하는 것이므로 아직 없다.
닫기: 57번째 줄에서 서버용 소켓 socketdescriptor와 클라이언트와 연결된 csocketdescriptor를 모두 닫고 WSA구조체들의 정보를 해제한다.
[socketclient.cpp]
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 | #include <stdio.h> #include <WinSock2.h> #pragma comment(lib, "wsock32.lib") int main() { SOCKET socketdescriptor; //socket descriptor WSADATA WSAdata; //winsock data SOCKADDR_IN socketin; //socket struct if (WSAStartup(WINSOCK_VERSION, &WSAdata) != 0) { //winsock version check printf("WSAStartup failed, %d\n", WSAGetLastError()); return 0; } socketdescriptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //create TCP/IP socket if (socketdescriptor == INVALID_SOCKET) { printf("Create socket failed, %d\n", WSAGetLastError()); //if socket() get error WSACleanup(); //finish WS2_32.DLL return 0; } socketin.sin_family = AF_INET; //I will use TCP/IP or UDP protocol socketin.sin_port = htons(10000); //I will use FTP server port socketin.sin_addr.s_addr = inet_addr("127.0.0.1"); //I will access with this IP Address if (connect(socketdescriptor, (struct sockaddr*)&socketin, sizeof(socketin)) != 0) { //try to connect server printf("Can't connect, %u\n", WSAGetLastError()); closesocket(socketdescriptor); WSACleanup(); return 0; } if (closesocket(socketdescriptor) != 0) { printf("remove socket failed, %d", WSAGetLastError()); //if socket can't finish WSACleanup(); return 0; } if (WSACleanup() != 0) { printf("WSACleanup failed, %u", WSAGetLastError()); return 0; } printf("Connect Successful\n"); } | cs |
기본 틀은 서버와 비슷하다.
26번째 줄에 inet_addr("127.0.0.1")로 바뀌었는데 127.0.0.1로 접속을 하겠다는 뜻이다.
서버에서 쓰인 htonl(ADDR_ANY)는 모든 IP주소로부터 접근을 허용하겠다는 것이다.
서버에서도 inet_addr을 사용하면 특정 IP주소의 접근만 허용하게 할 수 있다.
28번째 줄에서는 connect();함수로 서버와 연결을 한다.
connect();는 이렇게 사용한다.
1 | int __stdcall connect(SOCKET s, const sockaddr *name, int namelen) | cs |
서버용 소켓, 소켓의 주소로 서버에 접속을 요청한다.
--
혹시 주석에 문법적 오류가 있더라도 못본척ㅎㅎ
'Network' 카테고리의 다른 글
2, 3 Tier Architecture 발표 정리 (0) | 2017.03.14 |
---|---|
네트워크 구축 대회 준비(GNS-DNS/DHCP/FTP/VNC 서버 구축) (0) | 2016.11.11 |
C언어 TCP/IP socket error 10014 해결방법 (0) | 2016.10.23 |
라운드 로빈 (5) | 2016.04.19 |
네트워크 운영체제 (0) | 2016.04.14 |