@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 |