728x90
반응형

local virtualbox + linux => server

another linux => client

 

위 환경으로 TCP socket 통신 테스트를 하는데 server 쪽에서 accept이 안되는 문제가 있어서 삽질하다 결국 server 측의 port가 open되지 않아서 생긴문제였다. 그래서 아래와 같이 chatgpt에게 물어봐서 해결하였다.

 

$ firewall-cmd --zone=public --add-port=9000/tcp --permanent

$ firewall-cmd --reload   

 

* 확인방법

$ firewall-cmd --list-ports                                 
3306/tcp 9000/tcp

 

[DEV][ root@localhost /root ]
$ vi /etc/firewalld/zones/public.xml                     
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"/>
  <service name="dhcpv6-client"/>
  <port protocol="tcp" port="3306"/>
  <port protocol="tcp" port="9000"/>
</zone>

 

 

728x90
반응형
728x90
반응형

서버는 socket 함수를 호출해서 소켓을 생성하고, bind 함수로 포트에 연결한 후 listen함수로 클라이언트로부터 연결 요청을 받는다.

이때 소켓의 상태는 CLOSED에서 LISTEN이 된다. 클라이언트가 connect 함수를 호출하면 서버는 LISTEN 상태에서 SYN_RCVD 상태가 된 다음 ESTABLISHED 상태가 된다. 자료의 전송은 서버와 클라이언트 모두 ESTABLISHED 상태일 때 가능하다.

연결의 종료는 누가 먼저 종료를 시작하는가에 따라 상태가 달라지는데, 서버의 경우 클라이언트에서 먼저 종료를 시작하면 CLOSE_WAIT, LAST_ACK 상태를 거쳐 CLOSED 상태가 된다. 반대로 서버에서 먼저 종료를 시작하면 FIN_WAIT_1, FIN_WAIT_2, TIME_OUT 상태를 거쳐 CLOSED 상태가 된다.

클라이언트는 우선 socket 함수를 호출해서 소켓을 생성하고, connect 함수를 호출해서 서버와 연결하는데, SYN_SENT 상태를 거쳐 ESTABLISHED 상태가 된다. 그러면 자료의 송수신이 가능하게 된다.

 

연결준비단계

TCP는 연결형 서비스이다. 따라서 TCP로 통신하려는 두개의 호스트는 별도의 제어정보를 주고받음으로써 호스트간의 연결을 이루어낸다.

클라이언트의 응용프로그램에서 서버와 연결하기 위해 connect 함수를 호출하면 특정 제어비트를 1로 설정한 TCP 패킷을 서로 교환함으로써 이루어지는데 패킷 3개를 서로 교환하기 때문에 3-way handshaking이라고 부른다.

 

* 1단계(SYN 패킷 전송)

우선 클라이언트는 제어비트(control bit)중 SYN 비트를 1로 설정한 TCP 제어 패킷(SYN 패킷)을 서버로 전송해 연결을 시도한다.

TCP는 송수신되는 자료의 바이트 순서를 관리하는데, SYN 패킷에 기록된 일련번호와 확인번호 필드의 값으로 순서를 추척한다.

처음 SYN 패킷에는 클라이언트가 사용할 일련번호의 시작값을 일련번호 필드에 기록해서 전송한다.

즉, SYN 패킷의 일련번호 필드에는 연결후 자료를 송수신할 때 사용할 ISN이 있다.

 

* 2단계(SYN_ACK 패킷 전송)

서버는 제어비트중 SYN비트와 ACK비트를 1로 설정한 SYN_ACK 패킷을 클라이언트로 전송함으로써 클라이언트에게 SYN 패킷을 잘 받았음을 알린다. 역시 서버가 사용할 ISN을 SYN_ACK 패킷의 일련번호 필드에 기록해서 전송한다.

 

* 3단계(ACK 패킷전송)

클라이언트는 2단계의 SYN_ACK 패킷을 서버로부터 받은후 두 호스트간에 연결이 되었다는 것을 확인하고, 제어비트의 ACK 비트를 1로 설정한 TCP 제어패킷을 서버로 보낸다.

 

자료 송수신 단계

원격지로 자료를 전송할 때 응용 프로그램의 버퍼의 내용은 커널의 TCP 송신버퍼로 복사된다.

응용프로그램의 버퍼의 내용 모두가 커널의 TCP 송신버퍼에 복사될 때가지 응용프로그램은 차단된다.

TCP 송신버퍼의 크기는 옵션 SO_SNDBUF으로 지정한다.

응용프로그램의 버퍼의 크기가 크거나 송신버퍼에 비어있지 않아서 모두 복사하지 못하면 응용프로그램이 차단된다.

 

TCP 소켓옵션

#include <sys/types.h>

#include <sys/socket.h>

int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

 

s: 옵션을 읽거나 수정하려는 소켓 기술자

level: 옵션을 해석하는 커널 내 시스템 코드의 구분

optname: 소켓의 옵션을 수정할 옵션 이름

optval: 수정할 옵션의 값

optlen: 인자 optval의 메모리 크기

 

SO_KEEPALIVE 옵션

SO_KEEPALIVE 옵션은 TCP 소켓에 적용된다. 이 옵션을 1로 설정하면 일정시간(통상 2시간)동안 해당 소켓을 통해 어떤 자료도 송수신되지 않을때, 커널에서 상대방의 상태를 확인하는 패킷을 전송한다.

소켓이름 처리구분 적용 프로토콜
SO_KEEPALIVE SOL_SOCKET TCP

 

ACK 패킷으로 정상이라고 응답하는 경우 응용프로그램에는 어떠한 통보도 하지 않고 커널간의 확인만으로 상대방이 살아있음을 확인하고 마무리 한다. 상대방으로부터 아무런 응답이 없거나 RST 응답을 받으면 소켓을 자동으로 종료한다.

기본적으로 SO_KEEPALIVE 옵션은 서버측 소켓에 설정되어 상대방 시스템의 고장이나 정전, 네트워크 연결이 끊기는 등 통신이 불가능한 상황을 탐지해준다. 상대방 시스템이 고장난 경우 ETIMEOUT 오류를, 상대방 시스템까지 네트워크 연결이 불가능한 경우 EHOSTUNREACH 오류를 반환한다. 응용프로그램에서는 해당 오류에 따라 처리하면 된다. 시스템이나 네트워크 문제가 아닌 응용프로그램 문제라면 으용프로그램이 종료될 때 상대방 커널에서 FIN 패킷을 보내 연결 종료를 시작하기 때문에 응용 프로그램에서는 EOF에 대한 처리를 하면 된다.

728x90
반응형
728x90
반응형

 

#서버

1. 소켓 생성

나중에 클라이언트로부터의 연결 요청을 받을 수 있도록 socket 함수를 이용하여 네트워크 연결 장치인 소켓을 생성한다.

아래 예는 TCP용 전화기를 준비한 경우라 할 수 있다. 즉, TCP 통신이 가능한 TCP용 소켓을 생성하였다고 생각하면 된다.

int s_socket = socket(PF_INET, SOCK_STREAM, 0);

 

2. 연결 요청을 수신할 주소 설정

클라이언트로부터의 연결 요청을 받을 서버 IP주소와 포트를 설정하고 있다.

여기서 IP주소는 INADDR_ANY, 포트번호는 9000번으로 설정하고 있는데, 이는 현재 서버의 9000번 포트를 목적지로 하는 모든 연결 요청에 대해 처리하겠다는 의미이다. IP주소로 INADDR_ANY를 설정한 이유는 한 컴퓨터에 여러장의 랜카드가 장착되어 있어서 여러개의 IP 주소가 할당되고, 서버 응용프로그램은 이들 IP를 통해 들어오는 모든 연결요청을 받아 처리해야 하기에 사용한 것이다.

memset(&s_addr, 0, sizeof(s_addr));
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_family = AF_INET;
s.addr.sin_port = htons(PORT);

 

3. 소켓을 포트에 연결

1번에서 생성한 소켓을 2번에서 설정한 주소에 연결한다. 여기서는 소켓을 포트 9000번에 연결하고 있다.

if(bind(s_socket, (struct sockaddr *)&s_addr, sizeof(s_addr))==-1) {
    printf("can't bind\n");
    return -1;
}

 

4. 커널에 개통을 요청

해당 소켓으로 통신이 이루어지도록 운영체제에 개통을 요청하고 있다.

운영체제는 이 시점부터 다른 호스트에서 포트번호 9000번으로 요청하는 연결을 받아들이기 시작한다.

우리가 전화기를 전화기 콘센트에 물리적으로 연결하고서 전화국에 개통을 요청해야 외부에서 오는 전화를 받을 수 있는 것과 마찬가지 이치이다. 다시말해서 전화국 역할을 하는 운영체제에 개통을 요청하는 단계이다. 

if(listen(s_socket, 5) == -1) {
    printf("listen fail\n");
    return -1;
}

 

5. 클라이언트로부터 연결 요청을 수신
클라이언트로부터 연결 요청을 받아들이는 코드이다. 전화오기를 기다리다가 비로소 수화기를 들어받는 단계이다.

클라이언트로부터의 연결 요청을 1번에서 생성한 소켓 s_socket으로 받으면, 운영체제에서는 클라이언트와 자료를 송수신할 때 사용할 소켓 c_socket을 반환한다. 이후에는 연결소켓 c_socket을 통해 클라이언트와 자료를 송수신한다.

int len = sizeof(c_addr);
int c_socket = accept(s_socket, (struct sockaddr *)&c_addr, &len);

 

6. 클라이언트에게 서비스를 제공

int n = strlen(buffer);
write(c_socket, buffer, n);

 

#클라이언트

1. 소켓생성

서버와 통신할 소켓을 생성

c_socket = socket(PF_INET, SOCK_STREAM, 0);

 

2. 연결할 주소를 설정

연결할 서버의 주소를 구조체 변수 c_addr에 설정하고 있다. 클라이언트 프로그램에서 연결할 서버의 IP주소는 127.0.0.1 자기자신으로,

포트번호는 9000번으로 각각 설정하고 있다.

#define PORT 9000
#define IPADDR "127.0.0.1"

 

memset(&c_addr, 0, sizeof(c_addr));
c_addr.sin_addr.s_addr = inet_addr(IPADDR);
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(PORT);

 

3. 소켓을 서버에 연결

c_socket으로 변수 c_addr에 설정된 주소에 연결을 시도한다. 이와 관련해서 서버와의 연결은 커널 내부에서 3-way handshaking을 거쳐 이루어진다. 클라이언트는 클라이언트 커널에서 서버연결에 사용할 포트(예: 2345번 포트)를 결정하기 때문에 클라이언트 프로그램에서는 포트번호를 특별히 지정하지는 않는다.

if(connect(c_socket, (struct sockaddr *) &c_addr, sizeof(c_addr))==-1) {
    printf("Can not connect\n");
    close(c_socket);
    return -1;
}

728x90
반응형
728x90
반응형

cli.c
0.00MB
srv.c
0.00MB

 

 

TCP Keepalive HOWTO (tldp.org)

 

TCP의 경우, connection oriented protocol이지만, 송수신 중, 상대방 프로세스가 종료되는 등 정상적인 상황이 아닌 경우에는 세션의 종료여부를 감지할 수 없다. 

다시말해, LAN 케이블이 뽑힌다든지, 기타 비정상적인 종료가 있을 경우, 상대측에서 감지할 수 없다는 것이다.

 

1. TCP_KEEPIDLE

- 연결 활성화 상태를 유지하는 시간

- The time(in seconds) the connection needs to remain idle before TCP starts sending keepalive probes.

flags = 10;
setsockopt(sfd, SOL_TCP, TCP_KEEPIDLE, (void *)&flags, sizeof(flags)));

 

2. TCP_KEEPCNT

- 연결을 종료하기 전에 연결 유효성을 검사하는 횟수

- The maximum number of keepalive probes TCP should send before dropping the connection.

flags = 5;
setsockopt(sfd, SOL_TCP, TCP_KEEPCNT, (void *)&flags, sizeof(flags))) 

 

3. TCP_KEEPINTVL

- The time (in seconds) between individual keepalive probes.
flags = 5;
setsockopt(sfd, SOL_TCP, TCP_KEEPINTVL, (void *)&flags, sizeof(flags)));

 

4. SO_KEEPALIVE

flags =1;
setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags)))

SO_KEEPALIVE 옵션은 TCP 소켓에 적용된다. 이 옵션을 1로 설정하면 일정 시간(통상 2시간)동안 해당 소켓을 통해 어떤 자료도 송수신되지 않을 때, 커널에서 상대방의 상태를 확인하는 패킷을 전송한다. 이 패킷에 대해 상대방이 정상적이면 ACK 패킷을 전송한다.

  ACK 패킷으로 정상이라고 응답하는 경우 응용 프로그램에는 어떠한 통보도 하지 않고 커널 간의 확인만으로 상대방이 살아 있음을 확인하고 마무리한다. 상대방으로부터 아무런 응답이 없거나 RST 응답을 받으면 소켓을 자동으로 종료한다.

  기본적으로 SO_KEEPALIVE 옵션은 서버측 소켓에 설정되어 상대방 시스템의 고장이나 정전, 네트워크 연결이 끊기는 등 통신이 불가능한 상황을 탐지해 준다. 상대방 시스템이 고장난 경우 ETIMEOUT 오류를, 상대방 시스템까지 네트워크 연결이 불가능한 경우 EHOSTUNREACH 오류를 반환한다. 응용 프로그램에서는 해당 오류에 따라 처리하면 된다. 시스템이나 네트워크 문제가 아닌 응용 프로그램 문제라면 응용 프로그램이 종료될 때 상대방 커널에서 FIN 패킷을 보내 연결 종료를 시작하기 때문에 응용 프로그램에서는 EOF에 대한 처리를 하면 된다.

  만약 SO_KEEPALIVE 옵션이 설정되지 않은 상태에서 상대방 시스템이 고장이거나 네트워크 연결 등에 장시간 문제가 발생하면 응용 프로그램은 아무런 상황을 모른 체로 계속해서 상대방의 응답을 기다려야 하는 상황이 발생한다.

  SO_KEEPALIVE 옵션은 자료의 송수신이 일정 시간 동안 없을 경우 응용 프로그램이 아닌 커널에서 상대방의 상태를 파악하기 위해서 패킷을 보내는 옵션임을 알았다. 그런데 여기서 일정 시간은 보통 2시간 정도이고, 커널 변수로 관리된다. 따라서 커널 변수를 수정해서 시간을 조정할 수 있지만, 이런 경우 다른 모든 소켓에도 적용되기 때문에 전체 성능에 영향을 준다. 때문에 신중을 기해야 한다.

 

 

* test 결과

tcpdump

15:12:53.465155 IP (tos 0x0, ttl 128, id 31112, offset 0, flags [DF], proto TCP (6), length 52) 
    210.217.178.185.55596 > host117.cslistener: Flags [S], cksum 0x4158 (correct), seq 1438701007, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0 ==> (SYN)
15:12:53.465179 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52)
    host117.cslistener > 210.217.178.185.55596: Flags [S.], cksum 0x0b09 (incorrect -> 0x5897), seq 567562173, ack 1438701008, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0 ==> (SYN ACK)
15:12:53.465849 IP (tos 0x0, ttl 128, id 31113, offset 0, flags [DF], proto TCP (6), length 40)
    210.217.178.185.55596 > host117.cslistener: Flags [.], cksum 0xeb65 (correct), seq 1, ack 1, win 8212, length 0 ==> (ACK)

15:13:03.467762 IP (tos 0x0, ttl 64, id 50768, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [.], cksum 0x0afd (incorrect -> 0x0a96), seq 0, ack 1, win 229, length 0

TCP_KEEPIDLE defines the heartbeat frequency

This means the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further

flags = 10; // 10 seconds
setsockopt(sfd, SOL_TCP, TCP_KEEPIDLE, (void *)&flags, sizeof(flags));

 

15:13:08.475715 IP (tos 0x0, ttl 64, id 50769, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [.], cksum 0x0afd (incorrect -> 0x0a96), seq 0, ack 1, win 229, length 0
15:13:13.483723 IP (tos 0x0, ttl 64, id 50770, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [.], cksum 0x0afd (incorrect -> 0x0a96), seq 0, ack 1, win 229, length 0
15:13:18.492715 IP (tos 0x0, ttl 64, id 50771, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [.], cksum 0x0afd (incorrect -> 0x0a96), seq 0, ack 1, win 229, length 0
15:13:23.499762 IP (tos 0x0, ttl 64, id 50772, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [.], cksum 0x0afd (incorrect -> 0x0a96), seq 0, ack 1, win 229, length 0
15:13:28.507734 IP (tos 0x0, ttl 64, id 50773, offset 0, flags [DF], proto TCP (6), length 40)
    host117.cslistener > 210.217.178.185.55596: Flags [R.], cksum 0x0afd (incorrect -> 0x0a91), seq 1, ack 1, win 229, length 0

TCP_KEEPINTVL defines the heartbeat frequency when there is no answer from the other side;

TCP_KEEPCNT dictates how many unanswered heartbeat will indicate a dropped connection;

flags = 5;
setsockopt(sfd, SOL_TCP, TCP_KEEPCNT, (void *)&flags, sizeof(flags));
flags = 5;
setsockopt(sfd, SOL_TCP, TCP_KEEPINTVL, (void *)&flags, sizeof(flags));

 

결론: [15:13:28] read() ends

 

Holmes He

 

setsockopt, SO_KEEPALIVE and Heartbeats

There are two end purposes for sending heartbeats through a persistent connection. For a back-end application, heartbeats are generally used to detect an absent client, so as to drop a connection and

holmeshe.me

 

728x90
반응형
728x90
반응형

1. install : virtualbox + centos

[CentOS 7] Virutal Box에 CentOS 7 설치하기 (tistory.com)

 

[CentOS 7] Virutal Box에 CentOS 7 설치하기

안녕하세요. 리습입니다. Linux 환경을 만드는 방법은 다양합니다. Local PC에 직접 설치하는 방법도 있으며, Docker를 이용해 환경을 만드는 방법도 있습니다. 하지만, 테스트 환경으로써 가장 간단

programfrall.tistory.com

- 위 내용을 따라 설치하였기 때문에 virtualbox는 6.1로 설치

- GUI 사용을 위하여 gnome desktop 을 체크하고 설치

 

2. Network 설정

VirtualBox에 CentOS 7 설치 (enp0s3) - 제타위키 (zetawiki.com)

 

VirtualBox에 CentOS 7 설치 (enp0s3) - 제타위키

  다른 뜻에 대해서는 VirtualBox에 CentOS 7 설치 문서를 참조하십시오. VirtualBox에 CentOS 7 설치하기 1 사전 작업[ | ] 2 VM 생성[ | ] VirtualBox 실행 [새로 만들기(N)] 클릭 (가상 머신 만들기)[1] --- 이름: Cent

zetawiki.com

- 기본 설정인 NAT로 설정

- 위 내용과 같이 ifup enp0s3 를 실행했을 때 인터넷이 동작함

- 위 내용에서 eth0 설정까지 따라해야 재부팅 후에도 인터넷이 동작함

 

3. pc에서 ssh 접속을 위한 port forwarding

[VirtualBox] Linux 네트워크 설정 방법 (tistory.com)

 

4. virtualbox 화면 크기 조절

마무: virtualbox 화면 크기 조정 자세히! (mamu2830.blogspot.com)

728x90
반응형
728x90
반응형

1. Epoll?

Epoll은 리눅스에서 select의 단점을 보완하여 사용할 수 있도록 만든 I/O통지 모델이다.

파일 디스크립터를 사용자가 아닌 커널이 관리를 하며, 그만큼 CPU는 계속해서 파일 디스크립터의 상태 변화를 감시할 필요가 없다.

즉, select처럼 어느 파일 디스크립터에 이벤트가 발생하였는지 찾기 위해 전체 파일디스크립터에 대해서 순차검색을 위한 FD_ISSET 루프를 돌려야 하지만, Epoll의 경우 이벤트가 발생한 파일 디스크립터들만 구조체 배열을 통해 넘겨주므로 메모리 카피에 대한 비용이 줄어든다.

 

#incude <sys/epoll.h>

int epoll_create(int size)

   

fd들의 입출력 이벤트 저장을 위한 공간을 만들어야 하는데, epoll_create는 size만큼의 입출력 이벤트를 저장할 공간을 만든다. 그러나 리눅스 2.6.8 이후부터 size 인자는 사용되지 않지만 0보다는 큰 값으로 설정을 해 주어야 한다. 커널은 필요한 데이터 구조의 크기를 동적으로 조정하기 때문에 0보다 큰 값만 입력하면 된다.

    

반환 값으로는 정수형 데이터가 반환이 되는데, 이를 일반적으로 epoll fd라하며 이 fd를 통해 앞으로 epoll에 등록 된 fd들을 조작하게 된다. 


int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

epoll_ctl은 epoll에 fd들을 등록/수정/삭제를 하는 함수인데 일반적으로 epoll이 관심을 가져주길 바라는 fd와 그 fd에서 발생하는 관심있는 사건의 종류를 등록하는 인터페이스로 설명된다.

 

* epfd : epoll fd 값

* op : 관심가질 fd를 등록할지, 등록되어 있는 fd의 설정을 변경할지, 등록되어 있는 fd를 관심 목록에서 제거할지에 대한 옵션값

* fd : epfd에 등록할 관심있는 파일 디스크립터 값

* event : epfd에 등록할 관심있는 fd가 어떤 이벤트가 발생할 때 관심을 가질지에 대한 구조체. 관찰 대상의 관찰 이벤트 유형


int  epoll_wait(int  epfd,  struct epoll_event * events, int maxevents, int timeout)

epoll_wait는 관심있는 fd들에 무슨일이 일어났는지 조사한다. 다만 그 결과는 select나 poll과는 차이가 있다. 사건들의 리스트를 (epoll_event).events[] 의 배열로 전달한다. 리턴값은 발생한 사건들의 갯수가 리턴된다.

* events : 이벤트가 발생된 fd들을 모아놓은 구조체 배열.

* maxevents : 실제 동시접속수와 상관없이 maxevents 파라미터로 최대 몇개까지의 event만 처리할 것임을 지정해 주도록 하고 있다. 만약 현재 접속수가 1만이라면 최악의 경우 1만개의 연결에서 사건이 발생할 가능성도 있기 때문에 1만개의 events[] 배열을 위해 메모리를 확보해 놓아야 하지만, 이 maxevents 파라미터를 통해 한번에 처리하길 희망하는 숫자를 제한할 수 있다.

* timeout : epoll_wait의 동작특성을 지정해주는 중요한 요소인데, 밀리세컨드 단위로 지정해주도록 되어 있다. 이 시간만큼 사건발생을 기다리라는 의미이며 기다리는 도중에 사건이 발생하면 즉시 리턴된다.

-> timeout(-1)로 지정해주면 영원히 사건을 기다리는 blocking상태가 된다.

-> timeout(0)로 지정해주면 사건이 있건 없건 조사만 하고 즉시 리턴하는 상태가 된다.


Edge Trigger(ET)

 

특정 상태가 변화하는 시점에서만 감지.

 

특정 디지털 신호 000 111 000 111 000 111 일 경우 신호가 0에서 1로 변하는 시점에서만 이벤트가 발생한다.

소켓 버퍼에 대응하면, 한번에 읽을 수 있는 데이터 버퍼가 600인데, 데이터가 1000바이트가 도착했다면, 600바이트만 읽고 나머지 400바이트는 읽지 않은 상태에서 더 이상의 이벤트는 발생하지 않는다.

읽은 시점을 기준으로 보면 더이상의 상태 변화가 없기 때문이다.

따라서 한번에 읽을 수 있는 바이트 이상의 데이터가 오게 된다면 추가적인 작업을 따로 해주어야 한다.

 

ET로 작동하게 하려면 Non-blocking 소켓으로 생성해 줘야 하며 epoll에 관심 FD로 등록 할 때 EPOLLET로 설정해 주어야 한다.

 

서버의 트리거 모드가 엣지 트리거인 경우, 한번에 전송 가능한 패킷 버퍼 사이즈보다 보내야 하는 데이터의 사이즈가 더 클 경우, 여러번에 걸쳐 write를 하게 되면 엣지 트리거의 특성상 정상적으로 데이터를 전부 읽어드릴 수 없는 경우가 생긴다.


Level Trigger(LT)

 

특정 상태가 유지되는 동안 감지.

 

특정 디지털 신호 000 111 000 111 000 111 에서 1에 대한 Trigger 라면 1이 유지되는 시간동안 횟수에 상관없이 이벤트가 발생한다.

소켓 버퍼에 대응하면, 한번에 읽을 수 있는 데이터 버퍼가 600인데, 데이터가 1000바이트 도착했다면, 600바이트를 읽고 소켓 버퍼에 아직 데이터가 유지되고 있는 1인 상태이기 때문에 한번 더 이벤트가 발생하여 나머지 400바이트를 읽게 된다. 즉, 소켓 버퍼가 비어지는(0이 되는) 순간까지 계속해서 이벤트가 발생이 된다.

 

LT는 기본으로 설정되어 있으며 select나 poll은 LT만 지원이 된다.

 

서버의 트리거 모드가 레벨 트리거인 경우, 입력 버퍼에 데이터가 수신된 상황에서 이를 빠르게 읽어들이지 않으면 epoll_wait() 함수를 호출할 때 마다 이벤트가 발생하게 된다. 이로인해 발생하는 이벤트의 수가 계속 누적되는데, 이를 현실적으로 감당하는건 불가능하다. 따라서, 정상적인 접속-접속종료 테스트에 대한 처리가 불가능해질 수 있다.



출처: https://rammuking.tistory.com/entry/Epoll의-기초-개념-및-사용-방법 [쥬리스티앙 죠르즁]

728x90
반응형
728x90
반응형

1. 미디어쿼리란?

미디어쿼리는 CSS3 모듈중 하나로 사이트에 접속하는 장치에 따라 특정한 CSS 스타일을 사용하도록 해준다.

예를 들어, 다음 소스는 미디어 유형이 'screen' 이면서 최소 너비가 '200px'이고 최대 너비가 '360px'일 경우 적용할 CSS를 정의하는 구문입니다.

@media screen and (min-width:200px) and (max-width:360px) {

.....

}

 

앞의 소스에서 조건 사이에 넣은 and를 연산자라고 하는데, 미디어쿼리 구문에서 사용할 수 있는 연산자는 다음과 같습니다.

연산자 설명
and 조건을 계속 추가 가능
, 동일한 스타일 유형을 사용할 미디어의 유형과 조건이 있다면 쉼표을 이용해 추가
only 미디어 쿼리를 지원하는 웹브라우저에서만 조건을 인식
not not 다음에 지정하는 미디어 유형을 제외. 예를 들어 not tv라고 지정하면 TV를 제외한 미디어만 적용

2. 미디어 쿼리의 조건

<style>
  body {
    backgroundurl(images/bg0.jpgno-repeat fixed;
    background-sizecover;
  }
  @media screen and (max-width:1024px) {
    body {
      backgroundurl(images/bg1.jpgno-repeat fixed;
      background-sizecover;
    }
  }
  @media screen and (max-width:768px) {
    body {
      backgroundurl(images/bg2.jpgno-repeat fixed;
      background-sizecover;
    }
  }
  @media screen and (max-width:320px) {
    body {
      backgroundurl(images/bg3.jpgno-repeat fixed;
      background-sizecover;
    }
  }
</style>

3. 화면 회전

미디어쿼리를 작성할 경우, orientation 속성을 사용하면 화면 방향을 체크할 수 있습니다.

orientation 속성은 portrait값과 landscape 값을 사용할 수 있는데, portrait가 단말기 세로방향을 의미합니다.

<style>
  body {
    background-color#eee;
  }
  @media screen and (orientation:landscape) {
    body {
      background-colororange;
    }
  }
  @media screen and (orientation:portrait) {
    body {
      background-coloryellow;
    }
  }
</style>
728x90
반응형
728x90
반응형

1. 가변 글꼴

텍스트 크기를 픽셀(px) 단위로 지정하면 크기가 고정되기 때문에 화면 크기가 작은 기기에서는 매우 작게 표시됩니다.

따라서 반응형 웹디자인을 위해 가변 그리드 레이아웃을 사용할 때는 글자 크기도 유동적으로 바뀌어야 합니다.

 

1) em단위

em 단위는 부모요소에서 지정한 폰트의 대문자 M의 너비를 1em으로 지정한 것으로 1em은 16px 입니다.

 

2) rem

em 단위는 부모 요소의 글꼴을 기준으로 하기 때문에 중첩된 부모 요소의 글자 크기의 영향을 받습니다.

이런 단점을 없애기 위해 만든 단위가 rem입니다.

 

2. 가변 이미지

1) CSS 이용하기

이미지를 가변 레이아웃에 맞게 표시하려면 이미지를 감싸고 있는 부모 요소만큼 커지거나 작아지도록 max-width 속성값을 100%로 지정하면 됩니다.

<style>

.content img {

max-width: 100%

height: auto;

}

</style>

 

2) <img>태그와 secret 속성

이미지 너비값을 max-width:100%로 지정하면 가변 이미지를 간단히 만들수 있지만 고해상도 이미지를 크기만 줄여 표시하더라도 파일 사이즈가 크기 때문에 모바일에서 다운로드하는데 시간이 오래 걸린다.

또한 텍스트가 포함된 이미지일 경우, 모바일 화면에 맞게 줄여 표시하면 텍스트 내용을 알아보기 힘들수도 있다.

img 태그에서 srcset 속성을 이용하면 화면 너비값이나 픽셀 밀도에 따라 고해상도의 이미지 파일을 지정할 수 있다.

728x90
반응형
728x90
반응형

가변 그리드 레이아웃은 사이트의 모든 요소들을 상대적 크기로 지정해 브라우저의 크기에 따라 탄력적으로 보여주는 방법입니다. 가변 그리드 레이아웃에서는 CSS를 하나만 정의하면 됩니다.

 

1. 고정 그리드 레이아웃

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>Fluid Grid Layout</title>
<style>
  #wrapper {
    width960px;
    margin0 auto;
  }
  header {
    width960px;
    height120px;
    background-color#066cfa;
    border-bottom1px solid black;
  }
  .header-text {
    font-size40px;
    colorwhite;
    text-aligncenter;
    line-height120px;
  }
  .content {
    floatleft;
    width600px;
    height400px;
    padding15px;
    background-color#ffd800;
  }
  .right-side {
    floatright;
    width300px;
    height400px;
    padding15px;
    background-color#00ff90;
  }
  footer {
    clear:both;
    height120px;
    background-color#c3590a;
  }
</style>
</head>

<body>
  <div id="wrapper">
    <header>
      <h1 class="header-text">Fixed Grid Layout</h1>
    </header>
    <section class="content">
      <h4>본문</h4>
    </section>
    <aside class="right-side">
      <h4>사이드바</h4>
    </aside>
    <footer>
      <h4>푸터</h4>
    </footer>
  </div>
</body>
</html>

2. 가변 그리드 레이아웃 만들기

픽셀(px)을 이용한 레이아웃을 만들어 놓았다면 간단한 계산법으로 만들수 있다.

 

1) 전체를 감싸는 요소 확인하기

#wrapper의 너비값 960px을 백분율 값으로 변환

#wrapper {

width: 96% (화면의 양옆에 여백을 두기 위해 100%가 아닌 96%로 지정)

margin: 0 auto;

}

 

2) 각 요소의 너비 값 계산하기

기준이 되는 요소를 찾았다면 그 요소의 너비값으로 각 요소의 값을 계산합니다.

(요소의 너비 / 콘텐츠 전체를 감싸는 요소의 너비) * 100

요소 고정 그리드 가변 그리드
header 960px 100%
.content 600px 62.5%
padding 15px 1.5625%
.right-side 300px 31.25%
padding 15px 1.5625%
footer 960px 100%
728x90
반응형
728x90
반응형

1. 모바일 기기를 위한 기본 다지기, 뷰포트

뷰포트란 스마트폰 화면에서 실제 내용이 표시되는 영역입니다.

 

<meta name="viewport" content="<속성1=값>, <속성2=값2>, ... ">

content 안에서 사용하는 뷰포트 속성은 다음과 같습니다.

속성 설명 사용 가능한 값 기본값
width 뷰포트 너비 device-width 또는 크기 브라우저 기본값
height 뷰포트 높이 device-height 또는 크기 브라우저 기본값
user-scalable 확대/축소 가능여부 yes or no yes
initial-scalable 초기 확대/축소 값 1-10 1
minimum-scale 최소 확대/축소 값 0-10 0.25
maximum-scale 최대 확대/축소 값 0-10 1.6

 

2. 크롬의 디바이스 모드 활용하기

크롬에서 ctrl + shift + I 키를 눌러 개발자 도구 창을 엽니다.

개발자 도구 창의 맨 왼쪽 윗부분에 디바이스 모드 아이콘을 클릭합니다.

728x90
반응형

+ Recent posts