소켓 프로그래밍 보고서
본 보고서는 내 동아리인 Layer7의 숙제는 아니고, Layer7에서의 팀 프로젝트를 하기에 앞서 소켓프로그래밍을 전혀 모르는 팀원들과 함께 프로젝트 진행에 앞서 공부를 하기로 약속했기 때문이다.
그래서 오늘 그 보고서를 쓴다.
일단 구글에서 "C언어 소켓프로그래밍" 을 검색했다. 그런데, POSIX 규격에서 작동하는 <sys/socket.h>을 사용한 소켓프로그래밍 강좌가 매우 많았다.
Windows에서는 sys/socket.h가 아닌 winsock2.h를 사용해야한다.
나는 평소에 POSIX 규격을 준수하는 macOS를 사용하기때문에 내가 코딩하기에는 문제가 없었지만 동아리 프로젝트 시연은 Windows에서 진행해야 하기 때문에 좀 애를 먹었다.
나중에 시간이 된다면 이와 관련한 내용도 다루어 보도록 하겠다.
아무튼, 일단 visual studio를 켜고 속성에 다음과 같은 종속성을 추가해주어야한다.
만약 안된다면 ws2_32.lib 을 추가하면 된다.
그리고, 다음과 같은 과정을 통해 서버를 만들 수 있다.
0. 소켓 변수 및 소켓주소를 담는 구조체 생성
1. WSAStartup 함수를 실행함으로써 소켓을 지금부터 사용하겠다고 선언
2. 소켓 생성
3. 서버의 주소를 담고있는 SOCKADDR_IN 구조체를 초기화
4. 포트, 주소, 프로토콜과 같은 내용을 SOCKADDR_IN 구조체에 지정
5. 서버 바인딩
6. 리스닝 설정
7. 클라이언트 허용(accept)
8. 메시지 수신 / 보내기
9. 소켓 닫기
클라이언트는 다음과 같다.
0. 소켓 변수 및 소켓주소를 담는 구조체 생성
1. WSAStartup 함수를 실행함으로써 소켓을 지금부터 사용하겠다고 선언
2. 소켓 생성
3. 서버의 주소를 담고있는 SOCKADDR_IN 구조체를 초기화
4. 포트, 주소, 프로토콜과 같은 내용을 SOCKADDR_IN 구조체에 지정
5. 서버 커넥트
6. 리시브
7. 메시지 수신 / 보내기
8. 소켓 닫기
그래서 해당 내용들을 코드로 옮겨보면 다음과 같다.
주석만 읽어도 이해하는데 큰 이해가 없을것이니 별도의 설명은 추가하지 않겠다. 서버가 클라이언트의 메시지를 받기 전까지 대기하다가 메시지를 받으면 연결을 종료하는 프로그램이다.
서버쪽 코드는 다음과 같다.
그리고 다음은 클라이언트 코드이다.
그래서 오늘 그 보고서를 쓴다.
일단 구글에서 "C언어 소켓프로그래밍" 을 검색했다. 그런데, POSIX 규격에서 작동하는 <sys/socket.h>을 사용한 소켓프로그래밍 강좌가 매우 많았다.
Windows에서는 sys/socket.h가 아닌 winsock2.h를 사용해야한다.
나는 평소에 POSIX 규격을 준수하는 macOS를 사용하기때문에 내가 코딩하기에는 문제가 없었지만 동아리 프로젝트 시연은 Windows에서 진행해야 하기 때문에 좀 애를 먹었다.
나중에 시간이 된다면 이와 관련한 내용도 다루어 보도록 하겠다.
아무튼, 일단 visual studio를 켜고 속성에 다음과 같은 종속성을 추가해주어야한다.
만약 안된다면 ws2_32.lib 을 추가하면 된다.
그리고, 다음과 같은 과정을 통해 서버를 만들 수 있다.
0. 소켓 변수 및 소켓주소를 담는 구조체 생성
1. WSAStartup 함수를 실행함으로써 소켓을 지금부터 사용하겠다고 선언
2. 소켓 생성
3. 서버의 주소를 담고있는 SOCKADDR_IN 구조체를 초기화
4. 포트, 주소, 프로토콜과 같은 내용을 SOCKADDR_IN 구조체에 지정
5. 서버 바인딩
6. 리스닝 설정
7. 클라이언트 허용(accept)
8. 메시지 수신 / 보내기
9. 소켓 닫기
클라이언트는 다음과 같다.
0. 소켓 변수 및 소켓주소를 담는 구조체 생성
1. WSAStartup 함수를 실행함으로써 소켓을 지금부터 사용하겠다고 선언
2. 소켓 생성
3. 서버의 주소를 담고있는 SOCKADDR_IN 구조체를 초기화
4. 포트, 주소, 프로토콜과 같은 내용을 SOCKADDR_IN 구조체에 지정
5. 서버 커넥트
6. 리시브
7. 메시지 수신 / 보내기
8. 소켓 닫기
그래서 해당 내용들을 코드로 옮겨보면 다음과 같다.
주석만 읽어도 이해하는데 큰 이해가 없을것이니 별도의 설명은 추가하지 않겠다. 서버가 클라이언트의 메시지를 받기 전까지 대기하다가 메시지를 받으면 연결을 종료하는 프로그램이다.
서버쪽 코드는 다음과 같다.
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <WinSock2.h> int main(void) { SOCKET serverSocket, acceptSocket; // 서버 소켓과 해당 내용을 받아주는 소켓 생성 WSADATA wsaData; // 소켓사용을 알리는 함수인 WSAStartup 함수를 위해서 필요함 SOCKADDR_IN serverAddress, clientAddress; // 서버 주소와 클라이언트의 주소를 담는 구조체 선언 char cache[100]; int clientSize; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { // word 형식으로 버전을 입력 받는데, makeword 매크로 함수를 통하여 상위 2바이트와 하위 2바이트에 주 버전 번호와 부 버전 번호를 적는다. 윈도우 소켓을 사용하겠다고 알린다. printf("Error occured while starting WSA, error %u", WSAGetLastError()); return -1; } serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // IPv4, SOCK_STREAM for TCP, IPPROTO_TCP for TCP, but dunno why I have to set two arguments to use TCP if (serverSocket == INVALID_SOCKET) { // if failed to create socket printf("Creating socket failed, error %u", WSAGetLastError()); WSACleanup(); return -1; } memset(&serverAddress, 0, sizeof(serverAddress)); // initialize the structure serverAddress serverAddress.sin_family = PF_INET; // set the protocol family to IPv4 serverAddress.sin_port = htons(4500); // set the port // the function 'htons' is a function that changes the short memory value from host byte ordering to network byte ordering. // host byte ordering is little endian, and network byte ordering is big endian. serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); // set bind area to ANY if (bind(serverSocket, (SOCKADDR*)& serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) { printf("Binding failed, error %u", WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return -1; } if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) { // somaxconn means the max number of connections printf("Listening failed, error %u", WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return -1; } clientSize = sizeof(clientAddress); memset(&serverAddress, 0, clientSize); // initialize the structure clientAddress puts("Listening..."); acceptSocket = accept(serverSocket, (SOCKADDR*)& serverAddress, &clientSize); if (acceptSocket == INVALID_SOCKET) { printf("Accept failed, error %u", WSAGetLastError()); closesocket(serverSocket); WSACleanup(); return -1; } printf("Connected\nWaiting for client\'s message.\n"); recv(acceptSocket, cache, sizeof(cache), 0); printf("What you've got from the client: %s", cache); closesocket(serverSocket); closesocket(acceptSocket); WSACleanup(); return 0; }
#define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <WinSock2.h> int main(int argc, char* argv) { SOCKET clientSocket; SOCKADDR_IN serverAddress; WSADATA wsaData; char input[100]; printf("Connecting...\n\n"); if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { // word 형식으로 버전을 입력 받는데, makeword 매크로 함수를 통하여 상위 2바이트와 하위 2바이트에 주 버전 번호와 부 버전 번호를 적는다. 윈도우 소켓을 사용하겠다고 알린다. printf("Error occured while starting WSA, error %u", WSAGetLastError()); return -1; } memset(&serverAddress, 0, sizeof(serverAddress)); clientSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket == INVALID_SOCKET) { // if failed to create socket printf("Creating socket failed, error %u", WSAGetLastError()); return -1; } serverAddress.sin_family = PF_INET; serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); serverAddress.sin_port = htons(4500); if (connect(clientSocket, (SOCKADDR*)& serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) { printf("Connection failed, error %u", WSAGetLastError()); return -1; } printf("Connection Success !\nType here to send: "); gets(input); send(clientSocket, input, sizeof(input), 0); closesocket(clientSocket); WSACleanup(); return 0; }
Comments
Post a Comment