외로운 Nova의 작업실

c 소켓프로그래밍 공부 - 2(함수, 자료형 정리) 본문

Programming/C

c 소켓프로그래밍 공부 - 2(함수, 자료형 정리)

Nova_ 2022. 3. 22. 11:42

유튜브만 보고 만들어 보려했는데 좀 더 깊이 알고싶어서, 책을 삿습니다.

윤성우의 열혈 tcp/ip 프로그래밍을 삿습니다.

이 책을 정독한 후에 채팅 프로그램을 만들어볼 생각입니다.

책을 읽고 윈도우 운영체제 기반 소켓프로그래밍에 관련된 함수들을 정리해볼생각입니다.

결국에 프로그래밍을 배운다는건 이미 만들어져있는 라이브러리에 정의된 함수, 구조체, 상수들을 알고 활용한다는 것이라고 생각합니다.

아래는 winsock.h 헤더파일에 들어있는 여러가지 함수,구조체 상수들 입니다.

아래 함수들이 어떻게 작동하는지가 아닌 앞으로의 프로그램 만드는 과정에 있어서 함수나 구조체의 정의가 필요할때면 이번 2장으로 와서 정의를 확인하는게 좋을 것 같아서 이번 2장에는 정리만 하겠습니다.

앞으로 새로운 함수나 구조체가 정의되면 2장에 업데이트 하겠습니다.

2장을 꼭 자주 보셧으면 좋겠습니다.

 

#include <winsock2.h>
int WSAStart(WORD wVersioRequested, LPWSADATA lpWSAData);// - 소켓 버전에 맞는 라이브러리 초기화 작업
//wVersionRequested : 프로그래머가 사용할 윈속의 버전정보 전달 - ㅡMAKEWORD(1, 2)로 보통 전달//ipWSAData : WSADATA라는 구조체 변수의 주소값 전달 - &wsaData로 보통 전달int WSACleanup(void)
// - 라이브러리 운영체제에 반환으로 윈속 함수 관련 호출 불가로 만듦

SOCKET soket(int protocolFamily, int type, int protocol);
//프로토콜 체계와 연결 유형, 특정 프로토콜로 통신할 소켓을 반환하는 함수
//protocolFamily : 프로토콜 체계를 전달한다.
//type : 소켓의 데이터 전송방식의 유형을 전달한다.
//protocol : 보통 하나의 프로토콜 체계와 하나의 타입을 정하면 프로토콜이 정해지지만 그렇지 않은 경우에 정확한 프로토콜을 정해준다.
//아래는 각각 쓸수있는 메크로 상수들
PF_INET//IPv4 인터넷 프로토콜 체계 상수
PF_INET6//IPv6 인터넷 프로토콜 체계 상수
PF_LOCAL//로컬 통신을 위한 UNIX프로토콜 체계 상수
PF_PACKET//LOW Level을 소켓을 위한 프로토콜 체계 상수
PF_IPX//IPX 노벨 프로토콜 체계 상수

SOCK_STREAM//tcp 연결 지향형 통신 상수
SOCK_DGRAM// UDP 비 연결지향형 통신 상수

IPPROTO_TCP//IPv4 TCP 프로토콜 상수
IPPROTO+UDP//IPv4 UDP 프로토콜 상수


int bind(SOCKET s, const struct sockaddr* name, int namelen);
//소켓 s을 sockaddr 구조체에 담긴 ip주소와 포트번호로 설정하는 함수
//아래는 sockaddr 구조체의 정의
struct sockaddr{
	sa_family_t sin_family;//주소 체계
    char sa_data[14]//주소 정보
}
//sockaddr은 ip,포트번호를 전달하는데 가독성이 좋지않음 따라서 sockaddr_in으로 가독성 좋게만든다음 aockaddr형변환으로 bind에 인자로 씀
//아래는 sockaddr_in과 그안의 구조체 in_addr의 구조체 정의
struct SOCKADDR_IN {
	sa_famuly_t sin_family;//주소 체계
    uint16_t sin_port;//16비트 port번호
    struct in_addr sin_addr;// 32비트 ip주소가 들어있는 구조체
    char sin_zero[8];//sockaddr과 크기를 맞출려고 그냥 0을 집어넣음
}
struct in_addr{
	in_addr_t s_addr;//32비트 IPv4주소
}
//아래는 sin_family에 사용되는 상수들
AF_INET//IPv4주소 체계
AF_INET6//IPv6주소체계
AF_LOCAL//로컬통신 체계


int listen(SOCKET s, int backlong);
//s 소켓에게 연결요청 대기 큐를 backlong 만큼 요청 받으라는 함수


SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);
//서버소켓 s에 클라이언트의 요청이 오면 클라이언트의 주소 정보를 addrlen크기의 구조체 addr에 담고 그 길이를 addrlen에 담음
//이후 클라이언트와 연결된 소켓 하나를 반환


int connect(SOCKET s, const struct sockaddr* name, int namelen);


int closesocket(SOCKET s);
//아래는 half-close함수
int shutdown(int socket. int howto); //socket을 howto 모드에 맞춰 종료하는 함수
//아래는 howto에 들어갈 상수
SD_RECEIVE //데이터를 수신하는 스트림 종료
SD_SEND //데이터를 전송하는 스트림 종료
SD_BOTH //데이터를 전송,수신하는 스트림 종료


//아래는 데이터 송수신 함수
int send(SOCKET s, const char* buf, int len, int flags);
//buf의 내용을 len 만큼 s 소켓으로 보냄
int recv(SOCKET s, const char* buf, int len, int flag);
//소켓 s로 온 내용을 최대 len만큼 buf에 저장함, 만약 보낸 메시지가 len보다 적다면 받은메시지 길이 반환 
//send로 서버에게 문자열을 보낸다음 마지막으로 끝! 이라는 메시지를 보낸다. recv함수는 끝!이라는 메시지를받으면 0을 반환한다.


//아래는 바이트 순서 변환 함수의 정의
unsigned short htons(insigned short);
// 호스트 바이트 순서 포트번호를 네트워크 순서로 변환시켜준다u
nsigned short ntohs(sunsigned short);// 네트워크 바이트 순서 포트번호를 호스트 순서로 변환시켜준다.
unsigned long htonl(unsigned long);//호스트 바이트 순서 ip주소를 네트워크 순서로 변환시켜준다.
unsigned long ntohl(unsigned long);//네트워크 바이트 순서 ip주소를 호스트 바이트순서로 변환시켜준다.


//아래는 형변환 함수의 정의
#inlcude <ws2tcpip.h>

in_addr_t inet_addr(const char* string);//스트링값을 빅엔디안으로 변형된 in_addr_t형으로 변환시켜주는 함수, sockaddr_in 함수에 넣어야함
//위 함수는 보안상문제가있어서 아래와 같은 함수로 대체할수 있다.
int inet_pton(int sin_family, char* ip, (in_addr_t*) memory)
//sin_family주소체계를 가진 ip를 빅엔디안으로 변경후 memory가 가르키고있는 주소에 넣는다. 
//아래는 서버 주소 상수
INADDR_ANY//현재 ip주소룰 넣는다.
char* inet_ntop(int af, (in_addr_t*)addr, (char*)buf, (size_t)bufSize);
//addr을 bufsize만큼 buf에 바꿔서 넣는다.
//af는 address family
//addr은 문자열로 바꿔야하는 10진수 address
//buf는 바꾼 문자열을 담을 공간
//bufSize는 담을 공간의 크기전달


//아래는 클라이언트 소켓관련 함수
int connect(int sock, struct sockaddr* servaddr, socklen_t addrlen);
//클라이언트 소켓으로 주소 정보크기가 addrlen인 주소 구조체 servaddr에 담겨 있는 주소와 연결


//아래는 UDP 통신 관련 함수
int sendto(SOCKET s, char* buf, int len, int flag, SOCKADDR* to, int tolen);
//to에 들어있는 주소로 소켓 s를 통해 buf에담긴 문자열을 len만큼 보낸다.
int recvfrom(SOCKET s, char* buf, int len, int flag, SOCKADDR* from, int fromlen);
//form에 들어있는 주소로 오는것을 s소켓을통해 len만큼 buf에 담는다.

//아래는 address를 얻어오는 함수
//도메인 네임으로 ip를 얻어오는 함수
int getaddrinfo(char* hostname, char* service, struct addrinfo* hint, struct addrinfo **result)
//정상작동하면 0을 반환하고 아니면 다른걸 반환한다.
//아래는 함수인자 설명
//char* hostname : ip를 받아올 호스트이름 문자열
//char* service : 포트번호 문자열, 보통 https포트는 80번 포트이다.
//struct addrinfo* hint : 받아올 주소의 유형을 설정한 구조체
//struct addrinfo **result : 유형대로 받아온 주소를 넣을 구조체의 포인터의 포인터

//아래는 addrinfo 구조체의 정의이다
struct addrinfo{
    int ai_flags;				//추가적인 옵션을 정의할때 사용함
    int ai_familiy; 			//address family를 나타냄 AF_INET, AF_INET6, AF_UNSPEC등등
    int ai_socktype; 			//socket_type을 나타냄 SOCK_STRAM, SOCK_DGRAM
    int ai_protocol;			//특정 프로토콜을 나타냄 IPPROTO_TCP 등등
    socklen_t ai_addrlen;		//socket주소인 ai_adrr의 길이를 나타냄
    char* aicanonname; 			//호스트의 정식이름을 나타냄 -ai_flag를 AI_CANNONNAME으로 설정해줘야 값이 들어감
    struct sockaddr *ai_addr;	//SOCKADDR 구조체 포인터
    struct addrinfo *ai_next 	//다음addrinfo 데이터에대한 포인터
}


//아래는 addrinfo구조체 메모리의 초기화 함수
freeaddrinfo(struct addrinfo *res); 
//사용후 초기화를 하지않으면 메모리 누수현상이 발생한다(사용하지않으면서 메모리가 차있는 현상)


//아래는 소켓 옵션 관련 함수들
int getsockopt(SOCKET sock, int level, int opname, char* optval, int* optlen);
//sock에 opname설정의 값을 optval주소값에 optlen만큼 넣는다

int setsockopt(SOCKET sock, int level, int opname, char* optval, int optlen);
//sock에 opname의 설정값을 optval주소에 있는 optlen크기의 값으로 변경한다.


//아래부터는 멀티플렉싱기반 다중서버 구현 함수, 자료형들
struct fd_set //소켓을 모아놓는 자료형
{
	u_int fd_count; //fd셋에 들어있는 소켓의 갯수
	SOCKET fd_array[FD_SETSIZE] //SOCKET들이 들어있는 배열
}

FD_ZERO(fd_set *fdset) //fd_set의 모든 저장공간을 0으로 초기화한다.
FD_SET(int fd, fd_set *fdset) //fd의 핸들을 fdset에 저장한다.
FD_CLR(int fd, fd_set *fdset) //fd의 핸들을 fdset에서 삭제한다.
FD_ISSET(int fd, fd_set *fdset) //fdset에서 fd가 저장되어있으면 양수를 반환한다.

//아래는 알림이 실제로 온 소켓들을 골라주는 함수
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set, *exceptfds, struct timeval *timeout);
//nfds - 호환을 위해 남겨둔것으로 실제 사용하지않음
//fd_set *readfds - 입력버퍼가 왔을때 알림을 받으려고하는 소켓을 모아놓은 fd_set
//fd_set *writefds - 데이터 전송이 가능하다고 알림받으려고하는 소켓을 모아놓은 fd_set
//fd_set *exceptds - 예외상황이 발생했을때 알림받으려고하는 소켓을 모아놓은 fd_set
//struct timeval *time - 무한정 블로킹에 빠지지않도록 타임아웃을 설정하기위한 구조체

//아래는 timeval 구조체의 정의
struct TIMEVAL
{
	long tv_sec; //seconds
    long tv_usec; //microseconds
}


//아래는 쓰레드 관련 함수

#include <process.h>

uintptr_t  _beginthreadex(
	void* security, //쓰레드의 보안관련전당 디폴트는 null
    unsigned stack_size, //쓰레드에게 할당될 스택의 크기, 디폴트 크기는 0
    unsigned (*start_address)(void * arg), //쓰레드의 메인함수 정보 전달
    void *arglist, //쓰레드의 함수호출시 전달할 인자정보 전달
    unsigned initflag, //쓰레드 생성이후 행동결정, 0전달하면 바로 실행
    unsigned *thrdaddr //쓰레드 ID의 저장을위한 변수의 주소값 전달
);
//쓰레드가 종료되면 signaled - 메모리를 줌 , 종료되지않으면 non-signaled - 메모리 차지중

//아래는 함수 포인터의 선언
//↓ 반환값 자료형
void (*fp)();    // 반환값과 매개변수가 없는 함수 포인터 fp 정의
//     ↑   ↖ 매개변수가 없음
// 함수 포인터 이름

//아래는 쓰레드 종료 검사 함수
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
//hHandle : 상태확인이 되는 오브젝트의 핸들 전달
//dwMilliseconds : 무한블로킹을 막기위해 시간 지정, INFINITE전달시 오브젝트가 signaled 상태가 되기전엔 반환안함
//반환값 : signaled상태의 반환시 WAIT_OBJECT_0 반환, 타임아웃으로 반환시 WAIT_TIMEOUT 반환

DWORD WaitForMultipleObject(DWORD nCount, HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds);
//nCount : 검사할 커널 오브젝트 수 전달
//lpHandles : 핸들정보를 담고있는 배열의 주소값 전달
//bWaitAll : TRUE전달시 모든 검사대상이 signaled상태가 되어야반환, FALSE시 하나라도 signaled 상태면 반환
//dwMilliseconds : 타임아웃지정, INFINITE전달시 모든 검사대상이 signaled 상태가 되어야반환

//아래는 뮤텍스 관련 함수
#include <windows.h>

//자물쇠 뮤텍스 생성함수
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);
//lpMutexAttributes : 보안관련특성, 디폴트값은 0
//bInitialOwner : True 전달시 생성되는 Mutex는 함수를 호출한 쓰레드의 소유가 되면서 non-signaled 
//상태가된다. FALSE전달시 소유자가 존재하지않으며 signaled 상태로 생성된다.
//lpName : mutex의 이름을 부여할때 사용된다. NULL을 전달하면 이름없는 뮤텍스가 생성된다

//자물쇠 삭제 함수
BOOL CloseHandle(HANDLE Mutex);

//열쇠 획득하는 함수
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
//hHandle : 상태확인이 되는 오브젝트의 핸들 전달
//dwMilliseconds : 무한블로킹을 막기위해 시간 지정, INFINITE전달시 오브젝트가 signaled 상태가 되기전엔 반환안함
//반환값 : signaled상태의 반환시 WAIT_OBJECT_0 반환, 타임아웃으로 반환시 WAIT_TIMEOUT 반환
//뮤텍스는 auto-reset모드 오브젝트이기때문에 뮤텍스가
//signaled 일때 waitForSigleObject가 반환되고 뮤텍스를 non-signaled로 바꾼다.

//열쇠 반납하는 함수
BOOL ReleaseMutex(HANDLE Mutex);

//뮤택스가 signaled이면 열쇠가 있는상태, 뮤택스가 non-signaled이면 열쇠가 없는 상태

//아래는 세마포어 관련 함수

#include <windows.h>

//자물쇠의 키를 여러개 생성하는 함수/ 세마포어 생성함수
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount,	
	LONG lMaximumCount, LPCTSTR lpName);
//lpSemaphoreAttributes : 보안관련 정보전달, 디폴트값 0
//lInitialCount : 세마포어의 초기값, 0이면 non-signaled 상태
//lMaxumumCount : 세마포어의 최대갯수, 데이터영역의 문(자물쇠) 갯수
//lpName : 세마포어의 이름, NULL 전달시 이름없음


//열쇠를 획득하는 함수
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
//hHandle : 상태확인이 되는 오브젝트의 핸들 전달
//dwMilliseconds : 무한블로킹을 막기위해 시간 지정, INFINITE전달시 오브젝트가 signaled 상태가 되기전엔 반환안함
//반환값 : signaled상태의 반환시 WAIT_OBJECT_0 반환, 타임아웃으로 반환시 WAIT_TIMEOUT 반환
//세마포어는 auto-reset모드 오브젝트이기때문에 세마포어가
//signaled 일때 waitForSigleObject가 반환되고 뮤텍스를 non-signaled로 바꾼다.

//열쇠를 반납하는 함수
BOOL ReleaseSemaphore(HANDLE hSemaphor, LONG lReleaseCount, LPLONG lpPreviousCount);
//hSemaphore : 반납할 세마포어 핸들 전달
//lReleaseCount : 반납은 세마포어의 값의 증가를 의미하는데, 그 증가의 크기를 지정함
//lpPreviousCount : 변경이전의 세마포어 값 저장을 위한 변수의 주소값 전달, 불필요하면 NULL

//세마포어(자물쇠) 삭제 함수
BOOL CloseHandle(HANDLE Semaphore);
Comments