[Linux Socket 프로 그래 밍 입문] 04 - socket 프로 그래 밍 에서 가장 많이 사용 되 는 함수 및 데이터 구조

우정 알림: 위의 디 렉 터 리 를 이용 하여 관심 있 는 부분 을 선택 할 수 있 습 니 다.
(1) 배경
앞의 세 마디 는 주로 socket 이 무엇 인지, 네트워크 모델, IP 주소 등 기본 적 인 지식 을 소개 하 였 으 며, 다음은 socket 프로 그래 밍 에서 가장 자주 사용 되 는 몇 가지 시스템 함수 (syscall) 와 관련 된 데이터 구 조 를 소개 하여 Liux socket 프로 그래 밍 입문 준 비 를 하 였 다.
(2) 자주 사용 하 는 데이터 구조
socket 파일 설명자 (소켓 설명자)
socket 파일 설명자 가 하나 입 니 다.
int 형식의 정수.socket 파일 설명 자 는 파일 핸들 과 유사 합 니 다. 파일 핸들 에 대한 읽 기와 쓰 기 는 파일 에 대한 읽 기와 쓰 기 를 의미 합 니 다. 마찬가지 로 socket 파일 설명 자 는 목적 정 보 를 가 진 (IP 주소, 포트 번호 등) 바이트 흐름 을 의미 합 니 다. socket 파일 설명 자 를 읽 고 쓰 는 것 은 구체 적 인 IP 주소, 포트 번 호 를 읽 고 쓰 는 것 을 의미 합 니 다. socket 파일 설명자 의 데이터 형식 은 다음 과 같 습 니 다.
int

addrinfo
이 구 조 는 socket 프로 그래 밍 을 진행 할 때 만 날 수 있 는 첫 번 째 구조 입 니 다. 주로 주소 유형, 포트 번호, socket 유형 등 매개 변 수 를 기록 하여 후속 함수 호출 을 준비 합 니 다. getaddrinfo () 의 매개 변수 입 니 다. 구 조 는 다음 과 같 습 니 다.
struct addrinfo {
	int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
	int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
	int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
	int ai_protocol; // use 0 for "any"
	size_t ai_addrlen; // size of ai_addr in bytes
	struct sockaddr *ai_addr; // struct sockaddr_in or _in6
	char *ai_canonname; // full canonical hostname
	struct addrinfo *ai_next; // linked list, next node
};

그 중:
  • ai flags: AI PASSIVE 를 작성 하면 IP 주 소 를 수 동 으로 지정 할 필요 가 없다 고 합 니 다. 시스템 에서 IP 주 소 를 지정 해 줍 니 다. 보통 서버 엔 드 프로그램 일 때 이 flag 를 사용 하여 bid () 를 호출 합 니 다.시스템 에서 이 컴퓨터 의 IP 주 소 를 자동 으로 입력 합 니 다. AI CANONNAME flag 는 ai canonname 을 실제 호스트 이름 으로 채 웁 니 다. 물론 다른 flag 도 많 습 니 다. man page 를 통 해 볼 수 있 습 니 다.
  • ai family: IPv 4 인지 IPv 6 인지 지정 합 니 다. AF INET 는 IPv 4 를 대표 하고 AF INET 6 는 ipv 6 를 대표 하 며 AF UNSPEC 대 표 는 시스템 에서 자동 으로 선택 합 니 다.
  • ai next: addrinfo 는 하나의 링크 구조 입 니 다. 함수 getaddrinfo () 는 하나의 링크 를 되 돌려 줍 니 다. 이 는 여러 가지 선택 이 있 을 수 있 음 을 의미 합 니 다. 예 를 들 어 같은 호스트 이름: www. baidu. com 은 여러 개의 IP 주소 에 대응 할 수 있 습 니 다. getaddrinfo () 는 모든 IP 주 소 를 되 돌려 줍 니 다.
  • sockaddr
    addrinfo 구조 에 sockaddr 구조 가 있 습 니 다. 이 구 조 는 주로 각종 sock address (IPv 4 or IPv 6) 정 보 를 저장 합 니 다. 그 정 의 는 다음 과 같 습 니 다.
    struct sockaddr {
    unsigned short sa_family; // address family, AF_xxx
    char sa_data[14]; // 14 bytes of protocol address
    };
    그 중:
  • sa family 는 여러 가지 값 을 가 질 수 있 는데 가장 많이 사용 되 는 것 은 AF INET 와 AF INET 6 이다.
  • sa data: 목적 주소 와 port 정 보 를 포함 합 니 다. 그러나 이 구 조 는 매우 직관 적 이지 않 기 때문에 스스로 전환 해 야 IP 주소 와 port 번 호 를 얻 을 수 있 습 니 다.
  •  sockaddr_in
    sockaddr 사용 이 직관 적 이지 않 기 때문에 IPv 4 에 대해 이 구 조 를 추 가 했 습 니 다. 이 구조 체 의 내부 배열 은 sockaddr 와 같 습 니 다. 따라서 유형의 강제 전환 으로 sockaddr 를 sockaddr in 으로 강제 변환 할 수 있 습 니 다.
    sock 프로 그래 밍 에 서 는 이 구조 체 를 자주 사용 하여 IP address 와 port 번 호 를 가 져 옵 니 다. 그의 정 의 는 다음 과 같 습 니 다.
    struct sockaddr_in {
    short int sin_family; // Address family, AF_INET
    unsigned short int sin_port; // Port number
    struct in_addr sin_addr; // Internet address
    unsigned char sin_zero[8]; // Same size as struct sockaddr
    };
    그 중의 struct in addr 구 조 는 다음 과 같다.
    struct in_addr {
    uint32_t s_addr; // that's a 32-bit int (4 bytes)
    };
    그 중:
  • sin family: sockaddr 의 sa family 와 마찬가지 로 AF INET 로 설정 합 니 다.
  • sin port: 포트 번호.
  • sin addr: 목적지 의 IP address.
  • sin zero [8]: padding 입 니 다. memset 를 이용 하여 모두 0 으로 설정 해 야 합 니 다.
  • sockaddr_in6
    sockaddr in 과 마찬가지 로 이 구 조 는 주로 IPv 6 를 대상 으로 하 는데 그의 정 의 는 다음 과 같다.
    struct sockaddr_in6 {
    u_int16_t sin6_family; // address family, AF_INET6
    u_int16_t sin6_port; // port number, Network Byte Order
    u_int32_t sin6_flowinfo; // IPv6 flow information
    struct in6_addr sin6_addr; // IPv6 address
    u_int32_t sin6_scope_id; // Scope ID
    };
    struct in6_addr {
    unsigned char s6_addr[16]; // IPv6 address
    };
    주의: socket 입문 에 대해 서 는 sin6 scope id 를 잠시 무시 할 수 있 습 니 다.
    sockaddr_storage
    IPv 4 인지 IPv 6 인지 미리 알 수 없 을 때 가 있 습 니 다. IPv 4 의 정 보 를 담 을 수 있 는 구조 체 가 충분 한 지, IPv 6 의 정 보 를 담 을 수 있 는 지, 그리고 IPv 6 의 정 보 를 담 을 수 있 는 지 미리 알 수 없 을 때 가 있 습 니 다. 정 답 은: 있 습 니 다. 바로 sockaddr storage 입 니 다. 정 의 는 다음 과 같 습 니 다.
    struct sockaddr_storage {
    sa_family_t ss_family; // address family
    // all this is padding, implementation specific, ignore it:
    char __ss_pad1[_SS_PAD1SIZE];
    int64_t __ss_align;
    char __ss_pad2[_SS_PAD2SIZE];
    };
    ss family 가 AF INET 인지 AF INET 6 인지 에 따라 sockaddr storage 를 sockaddr in 또는 sockaddr in6 로 강제 변환 합 니 다. sockaddr storage 의 용법 은 다음 코드 분석 에서 볼 수 있 습 니 다.
    (3) 상용 함수
    inet_pton()
    이 함 수 는 주로 숫자 와 점 호 를 나타 내 는 IP 주 소 를 in addr 또는 in addr 6 의 구조 로 바 꾸 는 데 사 용 됩 니 다. "pton" 은 "presentation to network" 를 표시 합 니 다. 그 용법 은 다음 과 같 습 니 다.
    struct sockaddr_in sa; // IPv4
    struct sockaddr_in6 sa6; // IPv6
    inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4
    inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
    주의: 이 함수 가 실패 하면 - 1 또는 0 으로 돌아 갑 니 다. 반환 값 을 확인 하고 반환 값 이 0 이상 인지 확인 하 십시오.
     inet_ntop()
    inet pton () 과 반대로 이 함 수 는 IP 주 소 를 숫자 와 점 으로 표시 하 는 문자열 로 변환 합 니 다. "ntop" 은 "network to presentation" 을 대표 합 니 다. 그 용법 은 다음 과 같 습 니 다.
    // IPv4:
    char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
    struct sockaddr_in sa; // pretend this is loaded with something
    inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
    printf("The IPv4 address is: %s
    ", ip4); // IPv6: char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string struct sockaddr_in6 sa6; // pretend this is loaded with something inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN); printf("The address is: %s
    ", ip6);
    주의: INET ADDRSTRLEN 은 IPv 4 문자열 의 길 이 를 나타 내 는 미리 정 의 된 매크로 입 니 다. INET 6 ADDRSTRLEN 은 IPv 6 의 길 이 를 나타 냅 니 다.
     
    getaddrinfo()
    이 함 수 는 첫 번 째 로 호출 될 함수 입 니 다. 그 역할 은 주로 필요 한 매개 변 수 를 입력 하여 시스템 이 struct addrinfo 를 자동 으로 채 워 서 후속 함수 에 사용 하도록 하 는 것 입 니 다. 함수 원형 은 다음 과 같 습 니 다.
    #include 
    #include 
    #include 
    int getaddrinfo(const char *node, // e.g. "www.example.com" or IP
                    const char *service, // e.g. "http" or port number
                    const struct addrinfo *hints,
                    struct addrinfo **res);
    그 중:
  • 앞의 세 개 는 입력 매개 변수 이 고 마지막 하 나 는 출력 매개 변수 이 며 후속 함수 에 사용 할 수 있 습 니 다.
  • node: 보통 호스트 이름 이나 IP 주소 입 니 다.
  • service: service 의 수치 가 많 을 수 있 습 니 다. 우 리 는 포트 (port) 번 호 를 채 우 는 것 을 가장 많이 사용 합 니 다. 다른 값 은 보통 "http", "fpt", "telnet", "smtp" 등 서비스의 이름 입 니 다.
  • Sample:
    int status;
    struct addrinfo hints;
    struct addrinfo *servinfo; //        
    memset(&hints, 0, sizeof hints); //    ,     structure 0
    hints.ai_family = AF_UNSPEC; //           IPv4  IPv6,       。
    hints.ai_socktype = SOCK_STREAM; //   TCP socket
    hints.ai_flags = AI_PASSIVE; //        IP  。
    if ((status = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s
    ", gai_strerror(status)); exit(1); } // servinfo , IP 。 // ... freeaddrinfo(servinfo); // servinfo 。

    socket()
    이 함 수 는 주로 socket 파일 설명자 (socket file descriptor) 를 가 져 오 는 데 사 용 됩 니 다. 함수 원형 은 다음 과 같 습 니 다.
    #include 
    #include 
    int socket(int domain, int type, int protocol);
    그 중:
  • domain: PF INET 또는 PF INET 6. 실제 프로 그래 밍 에서 저 희 는 getaddrinfo () 에서 돌아 오 는 addrinfo - > ai family 를 자주 사용 합 니 다.
  • type: SOCK STREAM or SOCK DGRAM, 실제 프로 그래 밍 에 서 는 getaddrinfo () 가 되 돌아 오 는 addrinfo - > ai socktype 을 자주 사용 합 니 다.
  • protocol: 0 또는 getprotoby name () 을 통 해 protocol 의 이름 을 가 져 옵 니 다. 실제 프로 그래 밍 에 서 는 getaddrinfo () 에서 돌아 오 는 addrinfo - > ai protocol 을 자주 사용 합 니 다.
  • 반환 값: - 1 은 오 류 를 표시 합 니 다. 정상 적 인 상황 은 int 형의 socket 파일 설명 자 를 되 돌려 줍 니 다.
  • Sample:
    int s;
    struct addrinfo hints, *res;
    //...
    getaddrinfo("www.example.com", "http", &hints, &res);
    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

    bid () 이 함 수 는 주로 포트 번 호 를 연결 하 는 데 사 용 됩 니 다. 그 원형 은 다음 과 같 습 니 다.
    #include 
    #include 
    int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
    그 중:
  • sockfd: socket () 에서 얻 은 파일 설명자 입 니 다.
  • my addr: 자신의 IP 주소, 포트 번호 등 정 보 를 포함 하 는 sockaddr 구조 입 니 다. 프로 그래 밍 에 서 는 getaddrinfo () 가 되 돌아 오 는 addrinfo - > ai addr 를 자주 사용 합 니 다.
  • addr len: address 의 길이, 프로 그래 밍 에서 getaddrinfo () 가 되 돌아 오 는 addrinfo - > ai addrlen 을 자주 사용 합 니 다.
  • 반환 값: - 1 은 실 수 를 표시 합 니 다.
  • Sample:
    struct addrinfo hints, *res;
    int sockfd;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // fill in my IP for me
    getaddrinfo(NULL, "3490", &hints, &res);
    // make a socket:
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    // bind it to the port we passed in to getaddrinfo():
    bind(sockfd, res->ai_addr, res->ai_addrlen);

    connect () 이 함 수 는 클 라 이언 트 프로그램 에 사 용 됩 니 다. 서버 에 연결 하 는 요청 을 주동 적 으로 합 니 다. 보통 server 엔 드 의 IP 주소 와 포트 정 보 를 알 아야 합 니 다. 함수 원형 은 다음 과 같 습 니 다.
    #include 
    #include 
    int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
    그 중:
  • sockfd: socket 파일 설명자.
  • serv addr: server 의 IP 주소 정보 입 니 다. 프로 그래 밍 에 서 는 getaddrinfo () 가 되 돌아 오 는 addrinfo - > ai addr 를 자주 사용 합 니 다.
  • addrlen: address 의 길이, 프로 그래 밍 에서 getaddrinfo () 가 되 돌아 오 는 addrinfo - > ai addrlen 을 자주 사용 합 니 다.
  • 반환 값: - 1 은 실 수 를 표시 합 니 다.
  • Sample:
    struct addrinfo hints, *res;
    int sockfd;
    
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    getaddrinfo("www.example.com", "3490", &hints, &res);
    // make a socket:
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    // connect!
    connect(sockfd, res->ai_addr, res->ai_addrlen);

    listen()
    이 함 수 는 다른 사람 에 게 당신 이 주동 적 으로 연결 (connect) 하지 않 고 다른 사람 이 당신 을 연결 할 수 있다 는 것 을 알려 주 는 데 사 용 됩 니 다. 항상 accept () 와 연 결 됩 니 다. 함수 의 원형 은 다음 과 같 습 니 다.
    #include 
    #include 
    int listen(int sockfd, int backlog);
     
         
     
        
    • sockfd:socket 。
    • backlog: listen 。 accepte() , queue , queue 。
    • :-1 。
    Sample: , accept() 。
    getaddrinfo();
    socket();
    bind();
    listen();
    /* accept() goes here */

    accept()

    listen 。 , blocking( sleep) (connect), , 。 :
    #include 
    #include 
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    • sockfd:socket 。
    • addr: IP 。 , sockaddr_storage , 。
    • addrlen:address , sizeof(struct sockaddr_storage) 。 , , sizeof(struct sockaddr_storage) ,addrlen 。
    • :-1 。 socket 。 sockfd 。 。 ? listen , sockfd, , , 。
    Sample:
    #include 
    #include 
    #include 
    #include 
    #define MYPORT "3490" // the port users will be connecting to
    #define BACKLOG 10 // how many pending connections queue will hold
    int main(void)
    {
        struct sockaddr_storage their_addr;
        socklen_t addr_size;
        struct addrinfo hints, *res;
        int sockfd, new_fd;
    
        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_flags = AI_PASSIVE; // fill in my IP for me
        getaddrinfo(NULL, MYPORT, &hints, &res);
        // make a socket, bind it, and listen on it:
        sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        bind(sockfd, res->ai_addr, res->ai_addrlen);
        listen(sockfd, BACKLOG);
        // now accept an incoming connection:
        addr_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
        // ready to communicate on socket descriptor new_fd!
        .
        .
        .

    send() and recv()

    。 :
    int send(int sockfd, const void *msg, int len, int flags);
    • sockfd: 。
    • msg: 。
    • len: 。
    • flags: 0。
    • :-1 。 , 。 , 。 , 1K , 。
    int recv(int sockfd, void *buf, int len, int flags);
    • sockfd: 。
    • buf: buffer。
    • len:buffer 。
    • flags: 0。
    • :-1 。0 。 byte 。
    Sample: send() ,recv() 。
    char *msg = "Hello World!";
    int len, bytes_sent;
    ...
    len = strlen(msg);
    bytes_sent = send(sockfd, msg, len, 0);
    .
    .

    sendto() and recvfrom()

    datagram stream 。 datagram socket , UDP 。 :
    int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, socklen_t tolen);
    • send() , send() 。
    • to: sockaddr , IP , , , getaddrinfo() addrinfo->ai_addr。
    • to_len:addr , , getaddrinfo() addrinfo->ai_addrlen。
    • :-1 。 , 。 , 。
    int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
    • , recv。
    • from:  sockaddr_storage , IP , 。
    • fromlen:from 。 , , , from 。
    Sample:

    :UDP send(), recv() 。

    close()

    sock , close() 。 :
    int close(int sockfd);
    • sockfd
    • :-1 。 0.
    Sample:
    ...
    close(fd);


    --THE END--

    좋은 웹페이지 즐겨찾기