본문 바로가기

C/C++

Linux C Socket Util

@markdown


# Linux C Socket Util


## 소켓 생성 관련


### 추상 자료구조


```

 typedef struct {

    int sock;

    struct sockaddr_in addr;

} SockAndAddr;

```


### 서버 소켓 생성


```

SockAndAddr create_tcp_serversoc(char* ip, uint16_t port) {

    int error;

    SockAndAddr saa;

    saa.sock = socket(AF_INET, SOCK_STREAM, 0);

    assert(saa.sock != -1);

    memset(&saa.addr, 0, sizeof(saa.addr));

    saa.addr.sin_family         = AF_INET;

    saa.addr.sin_addr.s_addr    = ip ? inet_addr(ip) : htonl(INADDR_ANY);

    saa.addr.sin_port           = htons(port);


    error = bind(saa.sock, (struct sockaddr *)&saa.addr, sizeof(saa.addr));

    assert(!error);


    error = listen(saa.sock, 10);

    assert(!error);


    return saa;

}

```


```

SockAndAddr create_udp_serversoc(char* ip, uint16_t port) {

    int error;

    SockAndAddr saa;

    saa.sock = socket(AF_INET, SOCK_DGRAM, 0);

    assert(saa.sock != -1);

    memset(&saa.addr, 0, sizeof(saa.addr));

    saa.addr.sin_family         = AF_INET;

    saa.addr.sin_addr.s_addr    = ip ? inet_addr(ip) : htonl(INADDR_ANY);

    saa.addr.sin_port           = htons(port);


    error = bind(saa.sock, (struct sockaddr *)&saa.addr, sizeof(saa.addr));

    assert(!error);


    return saa;

}

```


## 자잘한 유틸리티 함수들



### sockaddr_in


이 함수는 주소 문자열과 포트 정수값을 입력받고, `struct sockaddr_in`을 반환한다.


주소 문자열로

- `example.com`과 같은 도메인

-  `192.168.0.1` 같은 IP

- 아예 `NULL`

을 넣을 수 있다.

_

소켓 생성에 편리하게 이용하자.


```

#include <sys/socket.h>

#include <unistd.h>

#include <assert.h>

#include <memory.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <stdlib.h>

#include <stdio.h>

#include <netdb.h>

#include <ctype.h>


struct sockaddr_in sockaddr_in(char* address, uint16_t port) {

int hostname_to_ip(char* hostname, char* ip) {

struct addrinfo hints, * servinfo, * p;

struct sockaddr_in* h;

int rv;


memset(&hints, 0, sizeof hints);

hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6

hints.ai_socktype = SOCK_STREAM;


if((rv = getaddrinfo(hostname, "http", &hints, &servinfo)) != 0) {

fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));

return 1;

}


for(p = servinfo; p != NULL; p = p->ai_next) {

h = (struct sockaddr_in*) p->ai_addr;

strcpy(ip, inet_ntoa(h->sin_addr));

}


freeaddrinfo(servinfo);

return 0;

}


int is_domain_string(char* address) {

while(address)

if(isalpha(*(address++)))

return 1;

return 0;

}


struct sockaddr_in addr;

memset(&addr, 0, sizeof(addr));

addr.sin_family = AF_INET;

addr.sin_port = htons(port);


if(!address)

addr.sin_addr.s_addr = INADDR_ANY;

else if(is_domain_string(address)) {

char ip[100] = {0,};

hostname_to_ip(address, ip);

addr.sin_addr.s_addr = inet_addr(ip);

} else {

addr.sin_addr.s_addr = inet_addr(address);

}


return addr;

}

```


### readall


주어진 fd에서 `len`만큼을 다 읽을 때까지 스레드를 블록한다. 다 읽었다면 읽은 만큼의 길이를 반환하고, 읽는 도중 에러가 발생하면 0 이하의 값을 반환한다.


```

ssize_t readall(int tcp_socket, uint8_t* buf, uint32_t len) {

    int gottens = 0;


    while (gottens < len) {

        ssize_t gotten = read(tcp_socket, buf + gottens, len - gottens);

        if (gotten <= 0)

            return gotten;

        gottens += gotten;

    }


    return gottens;

}

```


### wirteall


주어진 fd에 `len`만큼을 다 쓸 때까지 스레드를 블록한다. 다 썼다면 쓴 만큼의 길이를 반환하고, 쓰는 도중 에러가 발생하면 0 이하의 값을 반환한다.


```

ssize_t writeall(int fd, uint8_t* buf, uint32_t len) {

    int total_written = 0;


    while(total_written != len) {

        ssize_t written = write(fd, &buf[total_written], (size_t) (len - total_written));

        if(written <= 0)

            return written;

        total_written += written;

    }


    return total_written;

}

```

'C/C++' 카테고리의 다른 글

C String Utility  (0) 2016.12.22
C printStackTrace  (0) 2016.12.02
pcre 사용법  (0) 2016.10.28
enum length  (0) 2016.09.20
Ubuntu C Include Paths  (0) 2016.08.08