[다중 입출력 함수 select]

I/O 처리하는 경우 non-blocking 으로 여러개의 file descriptor를 체크하면서

읽어들일 데이터가 어떤 상태인지 확인하다가, 어떤 변화가 생기면

file descriptor를 리턴하게 된다.

만일 아무런 변화가 없다면 block 상태에 걸려버리는데

이는 timeout을 지정해서 빠져나올 수 있게 한다.

이 기능을 가지고 sleep대신 select를 사용할 수도 있다.

 

개인적으로 이해가 잘 안되서 이래저래 좀 자세히 테스트 해봤다.

 

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

 

내용출처 : http://mintnlatte.tistory.com/313

- nfds : 검사 대상이 되는 fd 범위로 세개의 집합(readfds/writefds/exceptfds)중 가장 큰 파일 디스크립터 값에 1을 더해서 전달하는 매개변수

- readfds : 시스템에 의해 즉시 입력이 가능한지 확인(읽기가 block되지 않았는지 검사하기 위한 리스트/ EOF 발생 검사)

- writefds : 시스템에 의해 즉시 출력이 가능한지 확인(쓰기가 block되지 않았는지 검사하기 위한 리스트)

- exceptfds : 예외가 있는지 검사하기 위한 리스트

- timeout : select가 반환하기 전에 블럭킹될 수 있는 시간의 제한 값 (0은 즉시반환 / NULL은 무한 block)

 

 ○ 리턴값

  -1 : 오류발생 

   0 : 타임아웃

양수: 변화 발생 파일 디스크립터 수

 

: FD_SET 구조체 / 변수 조작하는데 사용되는 함수들

 

○ FD_SET 구조체

 

 typedef struct fd_set {

    u_int          fd_count;

    SOCKET    fd_array[FD_SETSIZE];

 } fd_set;

- fd_count : 설정하는 파일 디스크립터의 번호

- fd_array : 설정된 파일 디스크립터의 배열

* fd_set은 0과 1로 저장되는 비트들의 배열이다.

 

○ FD_SET 변수 조작 함수

  - FD_SETFD_ZERO(fd_set *fdset) : fdset 포인터가 가리키는 변수의 모든 비트들을 0으로 초기화

  - FD_SET(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수에 fd로 전달되는 파일 디스크립터의 정보 설정(1로 설정)

  - FD_CLR(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수에 fd로 전달되는 파일 디스크립터의 정보를 삭제(0으로 설정)

  - FD_ISSET(int fd, fd_set *fdset) : fdset 포인터가 가리키는 변수가 fd로 전달되는 파일 디스크립터의 정보를 지니는지 확인

 

○ timeout 구조체

 

 

 struct timeval {

    long    tv_sec;

    long    tv_usec;

 }

-  tv_sec : 초 단위 설정 변수

- tv_usec : 마이크로 초 단위 설정 변수

 

 

 동작하는 방식

  FD_SET 변수에 변화가 생긴 파일 디스크립터는 1로 세팅, 변화가 없는 파일 디스크립터는 0으로 세팅한다.

 

 

- select 함수 호출 전 관찰 대상으로 fd0 과 fd3 이 설정되어 있다.

- select 함수 호출 후 fd3만 1로 설정되어있다.

=> fd3에 변화가 생겼음을 확인 & 해당 파일 디스크립터와 데이터 통신을 진행한다.

 

다음은 간단한 server/client를 구현했다. 그냥 echo 서버인데 서버쪽에서 여러개의

클라이언트를 그냥 받아들인다.

이걸 기본으로 하면 다른 것도 금방 짜겠다..

소스코드라인도 좀 기네;;;

 

==================================

 

서버측 소스코드
#include "sys/socket.h"
#include "sys/time.h"
#include "sys/types.h"
#include "sys/stat.h"
#include 
#include 
#include 
#include 
#include "netinet/in.h"
#include "arpa/inet.h"

#define FD_MAX_SIZE 1024

int main(int argc, char **argv)
{
    int server_sockfd, client_sockfd, sockfd;
    int state, client_len;
    int pid;
    int i, max_client, maxfd;
    int client[FD_MAX_SIZE];

    FILE *fp;
    struct sockaddr_in clientaddr, serveraddr;
    struct timeval tv;
    fd_set readfds, otherfds, allfds;

    int current_cli_num;
    char buf[255];
    char line[255];

    memset(line, 0x00, 255);
    state = 0;
    current_cli_num = 3;

    if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket error : ");
        exit(0);
    }

    memset(&serveraddr, 0x00, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(9000);

    state = bind(server_sockfd, (struct sockaddr *)&serveraddr,
            sizeof(serveraddr));
    if (state == -1) {
        perror("bind error : ");
        exit(0);
    }

    state = listen(server_sockfd, 5);
    if (state == -1) {
        perror("listen error : ");
        exit(0);
    }

    client_sockfd = server_sockfd;

    max_client = -1;
    maxfd = server_sockfd;

   for (i = 0; i < FD_MAX_SIZE; i++) {
        client[i] = -1;
    }

    FD_ZERO(&readfds);
    FD_SET(server_sockfd, &readfds);

    printf("\nTCP Server Waiting ...");
    fflush(stdout);

    while(1)
    {
        allfds = readfds;
        state = select(maxfd + 1 , &allfds, NULL, NULL, NULL);

        if (FD_ISSET(server_sockfd, &allfds)) {
            client_len = sizeof(clientaddr);
            client_sockfd = accept(server_sockfd,
                    (struct sockaddr *)&clientaddr, &client_len);
            printf("\nconnection from (%s , %d)",
                    inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));

            for (i = 0; i < FD_MAX_SIZE; i++)
            {
                if (client[i] < 0) {
                    client[i] = client_sockfd;
                    printf("\nclientNUM=%d\nclientFD=%d\n", i+1, client_sockfd);
                    break;
                }
            }

            printf("accept [%d]\n", client_sockfd);
            printf("===================================\n");
            if (i == FD_MAX_SIZE) {
                perror("too many clients\n");
            }
            FD_SET(client_sockfd,&readfds);

            if (client_sockfd > maxfd)
                maxfd = client_sockfd;

            if (i > max_client)
                max_client = i;

            if (--state <= 0)
                continue;

        }
        for (i = 0; i <= max_client; i++)
        {
            if ((sockfd = client[i]) < 0) {
                continue;
            }

            if (FD_ISSET(sockfd, &allfds))
            {
                memset(buf, 0x00, 255);

                if (read(sockfd, buf, 255) <= 0) {
                    close(sockfd);
                    perror("Close sockfd : ");
                    FD_CLR(sockfd, &readfds);
                    client[i] = -1;
                }
                printf("[%d]RECV %s\n", sockfd, buf);
                write(sockfd, buf, 255);

                if (--state <= 0)
                    break;
            }
        }
    }
}
클라이언트 측 소스코드
#include "sys/socket.h"
#include "sys/types.h"
#include "netinet/in.h"
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    int sock, bytes_recieved;
    char send_data[1024],recv_data[1024];
    struct hostent *host;
    struct sockaddr_in server_addr;

    host = gethostbyname("127.0.0.1");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9000);
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    memset(&(server_addr.sin_zero), 0x00, 8);

    if (connect(sock, (struct sockaddr *)&server_addr,
                sizeof(struct sockaddr)) == -1) {
        perror("Connect");
        exit(1);
    }

    while(1) {
        printf("\nSEND : ");
        fgets(send_data, sizeof(send_data), stdin);

        if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0)
            send(sock,send_data,strlen(send_data), 0);

        else {
            send(sock,send_data,strlen(send_data), 0);
            close(sock);
            break;
        }
        bytes_recieved=recv(sock,recv_data,1024,0);
        recv_data[bytes_recieved] = '\0';

        if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0) {
            close(sock);
            break;
        }
        else
            printf("\nRECV = %s\n " , recv_data);
    }
    return 0;
}
서버측의 결과 화면
TCP Server Waiting ...
connection from (127.0.0.1 , 53672)
clientNUM=1
clientFD=4
accept [4]
===================================

connection from (127.0.0.1 , 53681)
clientNUM=2
clientFD=5
accept [5]
===================================
[4]RECV nnnnnn

[5]RECV aaaaaa
클라이언트 측의 결과 화면
./aa_client

SEND : nnnnnn

RECV = nnnnnn

 

 

 

==================================

 

 

테스트하고 구현하는 건 자유인데 요러고 나니 아주쬐금 이해가 된다.

 

'Language > C' 카테고리의 다른 글

poll 함수 예제  (0) 2012.07.26
GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17

내부 프로세스끼리 TCP 또는 UDP 프로토콜을 이용해서 통신하도록

도와주는 소켓이다. 아래의 예제를 보면 이 앞의 다른 IPC 통신과는 달리

특정 함수 API가 제공되지는 않는다. 기존의 TCP/IP 통신하는 소스코드와 거의 동일함.

 

 

================================================

 

서버측 소스 코드
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/socket.h"
#include "sys/un.h"
#include 
#include 
#include 
#include 

#define MAXLINE 1024 

int main(int argc, char **argv)
{
    int server_sockfd, client_sockfd;
    int state, client_len;
    pid_t pid;

    FILE *fp;
    struct sockaddr_un clientaddr, serveraddr;

    char buf[MAXLINE]; 

    if (argc != 2) {
        printf("Usage : %s [socket file name]\n", argv[0]);
        exit(0);
    }

    if (access(argv[1], F_OK) == 0) {
        unlink(argv[1]);
    }

     client_len = sizeof(clientaddr);
     if ((server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
         perror("socket error : ");
         exit(0);
     }
     bzero(&serveraddr, sizeof(serveraddr));
     serveraddr.sun_family = AF_UNIX;
     strcpy(serveraddr.sun_path, argv[1]);

     state = bind(server_sockfd , (struct sockaddr *)&serveraddr,
             sizeof(serveraddr));
     if (state == -1) {
         perror("bind error : ");
         exit(0);
     }

     state = listen(server_sockfd, 5);
     if (state == -1) {
         perror("listen error : ");
         exit(0);
     }
     while(1)
     {
         client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr,
                 &client_len);
         pid = fork();
         if (pid == 0)
         {
             if (client_sockfd == -1) {
                 perror("Accept error : ");
                 exit(0);
             }

             while(1)
             {
                 memset(buf, 0x00, MAXLINE);
                 if (read(client_sockfd, buf, MAXLINE) <= 0) {
                     close(client_sockfd);
                     exit(0);
                 }
                 printf("RECV-> %s\n", buf);
                 write(client_sockfd, buf, strlen(buf));
             }
         }
     }
     close(client_sockfd);
}
클라이언트 측 소스코드
#include 
#include "sys/un.h"
#include 
#include 
#include 

#define MAXLINE 1024 


int main(int argc, char **argv)
{

    int client_len;
    int client_sockfd;

    FILE *fp_in;
    char buf_in[MAXLINE]; 
    char buf_get[MAXLINE]; 

    struct sockaddr_un clientaddr;

    if (argc != 2) {
        printf("Usage : %s [file_name]\n", argv[0]);
        exit(0);
    }

    client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client_sockfd == -1) {
        perror("error : ");
        exit(0);
    }

    bzero(&clientaddr, sizeof(clientaddr));
    clientaddr.sun_family = AF_UNIX;
    strcpy(clientaddr.sun_path, argv[1]);
    client_len = sizeof(clientaddr);

    if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) < 0)
    {
        perror("Connect error: ");
        exit(0);
    }
    while(1)
    {
        memset(buf_in, 0x00, MAXLINE); 
        memset(buf_get, 0x00, MAXLINE); 
        printf("> "); 
        fgets(buf_in, MAXLINE, stdin);
        write(client_sockfd, buf_in, strlen(buf_in));
        read(client_sockfd, buf_get, MAXLINE);
        printf("-> %s", buf_get);
    }

    close(client_sockfd);
    exit(0);
}
서버측 결과화면
RECV-> opipoipoikl

RECV-> 1

클라이언트측 결과화면
INPUT-> opipoipoikl
RECV-> opipoipoikl
INPUT-> 1
RECV-> 1

================================================

 

 

테스트하는 경우 %[실행파일명] [통신에 사용할 파일명]

저 파일을 설정해주고 사용하는 것만

다르고 나머지는 기본 TCP/IP와 동일하다.

 

다시 보니 이해가 좀 되네..

'Language > C' 카테고리의 다른 글

GCC 컴파일러 에러 메세지 리스트(Error Message List)  (0) 2012.07.24
select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13

소스코드를 블로그에 삽입하기엔

기가 막히게 좋은것 같다.

 

5단계 만으로도 충분하다. 빨간글씨만 잘봐도 이해가 금방될것인데,

의문점은 댓글을 남겨 주시면 답변드리겠습니다.

mediawiki에 적용하는것 보다 훨씬 쉽네요.

 

 

다른 블로그에도 많은 내용들이 있기에 간단하게 적용하는 순서만 나열한다.

 

1. 다운 받는다.

http://alexgorbatchev.com/SyntaxHighlighter/download/

 

이 웹페이지 맨윗줄에 Click here to download라고 있다.

 

2. 받은 파일 압축 풀어둔다.

 

3. 티스토리 'Admin' - '꾸미기' 'html/css 편집' 모드에 가서  파일 업로드 누른다. 그리고 올린다.

 

[scripts]안의 모든 *.js 파일들 과 [styles] 폴더안의 모든 *.css 파일들을 업로드 하면 됨.

 

4. HTML/CSS에서 skin.html 수정해야한다.

</body>, </html> 사이에다가 이거 가져다 붙이면된다.

2012년 7월에 작성해놓고 2016년 2월에 다시 따라서 해봤는데 잘됩니다. 오예

 

</body>

<script type="text/javascript" src="./images/shCore.js"></script>
<script type="text/javascript" src="./images/shLegacy.js"></script>
<script type="text/javascript" src="./images/shBrushBash.js"></script>
<script type="text/javascript" src="./images/shBrushCpp.js"></script>
<script type="text/javascript" src="./images/shBrushCSharp.js"></script>
<script type="text/javascript" src="./images/shBrushCss.js"></script>
<script type="text/javascript" src="./images/shBrushDelphi.js"></script>
<script type="text/javascript" src="./images/shBrushDiff.js"></script>
<script type="text/javascript" src="./images/shBrushGroovy.js"></script>
<script type="text/javascript" src="./images/shBrushJava.js"></script>
<script type="text/javascript" src="./images/shBrushJScript.js"></script>
<script type="text/javascript" src="./images/shBrushPhp.js"></script>
<script type="text/javascript" src="./images/shBrushPython.js"></script>
<script type="text/javascript" src="./images/shBrushSql.js"></script>
<script type="text/javascript" src="./images/shBrushXml.js"></script>
<link type="text/css" rel="stylesheet" href="./images/shCore.css">
<link type="text/css" rel="stylesheet" href="./images/shThemeEmacs.css">
<script type="text/javascript">
SyntaxHighlighter.all();
</script>

 </html>


* shThemeEmac.css는 내가 저 스타일이 좋아서 쓴것이므로 아무거나 좋은대로 바꿔쓰면 된다. [styles]폴더안에 있는 파일중에 업로드 시킨건 아무거나 다 될것임.

테마 종류 관련 정보는 여기 가면 완벽하게 나와있음

http://alexgorbatchev.com/SyntaxHighlighter/manual/themes/

 

5. 이제 글쓰기 모드로 가서 글을 쓴다.

 

 

저기 HTML 체크하고 나서

 

<pre class="brush:c;">

#include <stdio.h>

int main()

{

printf("HELLO WORLD\n"):

return 0;

}

</pre>

 

이런식으로 하면 끝난다.

브러쉬를 C로 설정했는데 다른게 필요하다면 다음의 링크를 참조해주시길..

http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/

TCP 를 통해서 Newwrok Throughput 을 확인하는 툴이다. (UDP도 가능)

영어로 된 옵션들 보기 좋으라고 간단하게 한글로 썼다.

   

   

 클라이어트 모드 -c 옵션 주면 된다

#iperf -c 10.1.1.1

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 16384 Byte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 33453 connected with 10.1.1.1 port 5001

[ 3]   0.0-10.2 sec   1.26 MBytes   1.05 Mbits/sec

   

서버모드   -s 옵션 주면된다.

#iperf -s

------------------------------------------------------------

Server listening on TCP port 5001

TCP window size: 8.00 KByte (default)

------------------------------------------------------------

[852] local 10.1.1.1 port 5001 connected with 10.6.2.5 port 33453

[ ID]   Interval          Transfer       Bandwidth

[852]   0.0-10.6 sec   1.26 MBytes   1.03 Mbits/sec

   

   

클라이언트모드에  -f  옵션 주면

결과 값을 설정 가능하다. 아래와 같이 -f b 로 하면 bits로 나오는데

bits(b), bytes(B), kilobits(k), kilobytes(K), megabits(m), megabytes(M), gigabits(g) or gigabytes(G).

이런식으로 볼 수 있다.

#iperf -c 10.1.1.1 -f b

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 16384 Byte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 54953 connected with 10.1.1.1 port 5001

[ 3]   0.0-10.2 sec   1359872 Bytes   1064272 bits/sec

#iperf -s

------------------------------------------------------------

Server listening on TCP port 5001

TCP window size: 8.00 KByte (default)

------------------------------------------------------------

[852] local 10.1.1.1 port 5001 connected with 10.6.2.5 port 33453

[ ID]   Interval          Transfer       Bandwidth

[852]   0.0-10.6 sec   920 KBytes   711 Kbits/sec

   

윈도우 사이즈옵션 주려면 -w 하고 숫자 넣어주면 간단하게 된다.   

요거는 서버 쪽에서도 맞춰 줘야 한다.

#iperf -c 10.1.1.1 -w 2000

WARNING: TCP window size set to 2000 bytes. A small window size

will give poor performance. See the Iperf documentation.

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 3.91 KByte (WARNING: requested 1.95 KByte)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 51400 connected with 10.1.1.1 port 5001

[ 3]   0.0-10.1 sec   704 KBytes   572 Kbits/sec

   

#iperf -s -w 4000

------------------------------------------------------------

Server listening on TCP port 5001

TCP window size: 3.91 KByte

------------------------------------------------------------

[852] local 10.1.1.1 port 5001 connected with 10.6.2.5 port 51400

[ ID]   Interval          Transfer       Bandwidth

[852]   0.0-10.1 sec   704 KBytes   570 Kbits/sec

 

포트 번호 설정은 -p, 그리고 -t는 전체 시간이고 -i는 인터벌(시간간격)
가지고 구하는 경우

#iperf -c 10.1.1.1 -p 12000 -t 20 -i 2

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 12000

TCP window size: 16.0 KByte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 58316 connected with 10.1.1.1 port 12000

[ 3]    0.0- 2.0 sec    224 KBytes    918 Kbits/sec

[ 3]    2.0- 4.0 sec    368 KBytes    1.51 Mbits/sec

[ 3]    4.0- 6.0 sec    704 KBytes    2.88 Mbits/sec

[ 3]    6.0- 8.0 sec    280 KBytes    1.15 Mbits/sec

[ 3]    8.0-10.0 sec    208 KBytes    852 Kbits/sec

[ 3]   10.0-12.0 sec   344 KBytes    1.41 Mbits/sec

[ 3]   12.0-14.0 sec   208 KBytes    852 Kbits/sec

[ 3]   14.0-16.0 sec   232 KBytes    950 Kbits/sec

[ 3]   16.0-18.0 sec   232 KBytes    950 Kbits/sec

[ 3]   18.0-20.0 sec   264 KBytes    1.08 Mbits/sec

[ 3]    0.0-20.1 sec   3.00 MBytes   1.25 Mbits/sec

 

#iperf -s -p 12000

------------------------------------------------------------

Server listening on TCP port 12000

TCP window size: 8.00 KByte (default)

------------------------------------------------------------

[852] local 10.1.1.1 port 12000 connected with 10.6.2.5 port 58316

[ ID] Interval Transfer Bandwidth

[852]   0.0-20.1 sec   3.00 MBytes   1.25 Mbits/sec

   

 

   

Maximum Segment Size (-m argument) MSS 크기 설정 가능하게 해준다.
디폴트값은 1500Bytes.

  

Client side:

   

   

#iperf -c 10.1.1.1 -m

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 16.0 KByte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 41532 connected with 10.1.1.1 port 5001

[ 3]   0.0-10.2 sec   1.27 MBytes   1.04 Mbits/sec

[ 3] MSS size 1448 bytes (MTU 1500 bytes, ethernet)

   

Here the MSS is not equal to 1500 - 40 but to 1500 - 40 - 12 (Timestamps option) = 1448

   

   

#iperf -c 10.1.1.1 -M 1300 -m

WARNING: attempt to set TCP maximum segment size to 1300, but got 536

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 16.0 KByte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 41533 connected with 10.1.1.1 port 5001

[ 3]   0.0-10.1 sec   4.29 MBytes   3.58 Mbits/sec

[ 3] MSS size 1288 bytes (MTU 1328 bytes, unknown interface)

   

병렬 테스트를 하고자 하면 -p 옵션 주면 된다.

Client side:

   

   

#iperf -c 10.1.1.1 -P 2

------------------------------------------------------------

Client connecting to 10.1.1.1, TCP port 5001

TCP window size: 16.0 KByte (default)

------------------------------------------------------------

[ 3] local 10.6.2.5 port 41534 connected with 10.1.1.1 port 5001

[ 4] local 10.6.2.5 port 41535 connected with 10.1.1.1 port 5001

[ 4]     0.0-10.1 sec   1.35 MBytes   1.12 Mbits/sec

[ 3]     0.0-10.1 sec   1.35 MBytes   1.12 Mbits/sec

[SUM]  0.0-10.1 sec   2.70 MBytes   2.24 Mbits/sec

   

마지막으로 내가 사용하는 주로 쓰는 옵션은..
-n 옵션은  Transfer하는 데이터 크기를 정해서 주고 받는 옵션이다.


클라이언트

$ iperf -c 10.10.1.57 -p 50000 -n 300M
------------------------------------------------------------
Client connecting to 10.10.1.57, TCP port 50000
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  3] local 10.10.4.55 port 41529 connected with 10.10.1.57 port 50000
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-26.3 sec    300 MBytes  95.8 Mbits/sec

 

서버

$ iperf -s -p 50000
------------------------------------------------------------
Server listening on TCP port 50000
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[  4] local 10.10.1.57 port 50000 connected with 10.10.4.55 port 41529
[ ID] Interval       Transfer     Bandwidth
[  4]  0.0-26.8 sec    300 MBytes  93.7 Mbits/sec
   

   

Client/Server:

   

-f

-i

-l

-m

-p

-u

-w

-B

-C

-M

-N

-V

--format

--interval

--len

--print_mss

--port

--udp

--window

--bind

--compatibility

--mss

--nodelay

--IPv6Version

[kmKM]

#

#[KM]

   

#

   

#[KM]

"host"

   

#

   

   

format to report: Kbits, Mbits, KBytes, MBytes

seconds between periodic bandwidth reports

length of buffer to read or write (default 8 KB)

print TCP maximum segment size (MTU - TCP/IP header)

server port to listen on/connect to

use UDP rather than TCP

TCP window size (socket buffer size)

bind to "host", an interface or multicast address

for use with older versions does not sent extra msgs

set TCP maximum segment size (MTU - 40 bytes)

set TCP no delay, disabling Nagle's Algorithm

Set the domain to IPv6

Server specific:

   

-s

-U

-D

--server

--single_udp

--daemon

               

   

   

run in server mode

run in single threaded UDP mode

run the server as a daemon

Client specific:

   

-b

-c

-d

-n

-r

-t

-F

-I

-L

-P

-T

--bandwidth    

--client

--dualtest

--num

--tradeoff

--time

--fileinput

--stdin

--listenport

--parallel

--ttl

#[KM] 

"host"

   

#[KM]

   

#

"name"

   

#

#

#

for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u)

run in client mode, connecting to "host"

Do a bidirectional test simultaneously

number of bytes to transmit (instead of -t)

Do a bidirectional test individually

time in seconds to transmit for (default 10 secs)

input the data to be transmitted from a file

input the data to be transmitted from stdin

port to recieve bidirectional tests back on

number of parallel client threads to run

time-to-live, for multicast (default 1)

Miscellaneous:

   

-h

-v

--help

--version

                    

   

print this message and quit

print version information and quit

 

간단하게 리소스 카운터라고 생각해도 되는데 일단은 데드락 피하기 위한

기술 중의 하나라고 한다..

실제 어디다 써먹을지는 아직 모르겠지만.. 이거보다는 개인적으로 뮤텍스를 더 자주 쓰는듯 싶네..

 

소스코드 출처 : http://forum.falinux.com/zbxe/?document_srl=428639

 

int semget ( key_t key, int nsems, int semflg )

세마포어 식별자를 가지고 오는 함수다.

 

key_t key

시스템에서 세머포어를 식별하는 키 번호

int nsems

세마포어 집합 내의 세마포어 개수로 접급 제한하려는 세마포어 자원의 개수

int semflg 동작 옵션 ( IPC_CREATE와 IPC_EXCL이 있다.)

 

 

int semctl ( int semid, int semnum, int cmd, union semun arg)

세마포어를 control 하는 함수다.

 

int semid 시스템에서 세머포어를 식별하는 집합 번호
int semnum

세마포어 집합 내에서의 세마포어 위치 (세마포어 넘버...)

int cmd

제어 명령( 값을 설정, 삭제, 소유권, 등등 많다.)

union semun arg 위의 제어명령 cmd 에 따라 달라진다., 설정 또는 값을 구하는 변수 
union semun{
   int                  val;
   struct   semid_ds   *buf;
   unsigned short int  *arrary;
}

int semop ( int semid, struct sembuf *sops, unsigned nsops )

세마포어의 값을 변경한다. 값을 증가, 감소시킨다.

 

int semid 시스템에서 세머포어를 식별하는 집합 번호
struct sembuf *sops

세마포어 값을 계산하기위한 설정 값 
struct sembuf {
    short sem_num;   세마포어 번호
    short sem_op;     세마포어 증감값
    short sem_flg;     옵션 
}

unsigned nsops

변경하려는 세마포어 개수로 변경하려는 세마포어 개수가 여러 개일 때 사용
n개의 세마포어 옵션들..

 

 

예제를 봐야 이게 뭔지 조금은 이해가 간다.

매우간단한 멀티 쓰레드 구조의 카운터다.

failinux.com.. 참 괜찮다.

 

 

============================================

#include 
#include 
#include 
#include 
#include "sys/ipc.h"
#include "sys/sem.h"
#include "sys/poll.h"

int         cnt   = 0;
static int  semid;

void semop1() 
{
    struct sembuf buf1;

    buf1.sem_num   = 0;
    buf1.sem_op    = -1;
    buf1.sem_flg   = SEM_UNDO;

    if (semop(semid, &buf1, 1) == -1)
        printf( "%s::semop() Fail\n", __func__);
}

void semop2()
{
    struct sembuf buf2;

    buf2.sem_num   = 0;
    buf2.sem_op    = 1;
    buf2.sem_flg   = SEM_UNDO;

    if (semop(semid, &buf2, 1) == -1)
        printf( "%s::semop() Fail\n", __func__);
}

void *fun_thread1(void *arg) {
    while( 1) {
        semop1();
        printf( "thread1 run \n");
        if ( 5 < cnt) {
            printf( "thread1 Completely terminated \n");
            semop2();
            break;
        }
        else {
            cnt++;
            poll(0,0,100);
            printf( "thread1 terminated \n");
        }
        semop2();
    }
    return;
}

void *fun_thread2(void *arg)
{
    while( 1) {
        semop1();
        printf( "thread2 run \n");
        if (5 < cnt) {
            printf( "thread2 Completely terminated \n");
            semop2();
            break;
        }
        else {
            printf( "=====>>Counter= %d\n", cnt);
            poll(0,0,100);
            printf( "thread1 terminated \n");
        }
        semop2();
    }

    return;
}

int main(int argc, char *argv[])
{
    pthread_t thread1;
    pthread_t thread2;
    union semun{
        int                  val;
        struct   semid_ds   *buf;
        unsigned short int  *arrary;
    }arg;

    if ((semid = semget( IPC_PRIVATE, 1, IPC_CREAT| 0666)) == -1) {
        printf( "semget() Fail\n");
        return -1;
    }

    arg.val=1;                // Semaphore value = 1
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        printf( "semctl()-SETVAL Fail\n");
        return -1;
    }

    pthread_create(&thread1, NULL, fun_thread1, NULL);
    pthread_create(&thread2, NULL, fun_thread2, NULL);
    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL);

    if (semctl(semid, 0, IPC_RMID, arg) == -1) {
        printf( "semctl()-IPC_RMID Fail\n");
        return -1;
    }
    printf( "Process Terminated!");
    return 0;
}
/* The end of function */
# 수행결과는 다음과 같다.
./a.out
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 1
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 2
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 3
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 4
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
=====>>Counter= 5
thread1 terminated 
thread1 run 
thread1 terminated 
thread2 run 
thread2 Completely terminated 
thread1 run 
thread1 Completely terminated 

 

 

============================================

 

failinux 그대로 가져왔슴..

개인적인 테스트용이므로,, 저작권에 문제가 있다면

알려주시길.. 지우던지 다른 방식으로 구현해두겠습니다.

'Language > C' 카테고리의 다른 글

select 함수 예제  (0) 2012.07.23
Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
파일이나 디바이스를 주소 공간 메모리에 대응시키는 방식인데

일종의 IPC 통신으로 사용가능하다. 매우 빠름.

 

출처 : 소스코드 http://www.cs.purdue.edu/homes/fahmy/cs503/mmap.txt

 

void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);

파일이나 디바이스를 응용 프로그램의 주소 공간 메모리에 대응시킨다.

 

1인자 => 시작 포인터 주소 (아래의 예제 참조)

2인자 => 파일이나 주소공간의 메모리 크기

3인자 => PROT 설정 (읽기, 쓰기, 접근권한, 실행)

4인자 => flags는 다른 프로세스와 공유할지 안할지를 결정한다.

5인자 => fd는 쓰거나 읽기용으로 열린 fd값을 넣어준다.

6인자 => offset은 0으로 하던지 알아서 조절한다.

 

int munmap(void* start, size_t length);

할당된 메모리 영역을 해제한다.

 

1인자 => 위에 mmap으로 지정된 포인터값 넣어주고

2인자 => 위에서 사용했던 length와 동일하게 넣어준다.

(왜냐면.. 할당했던거 동일하게 해제해야 하니깐..)

 

더 자세한 사항은 man page에 모든게 나와있음.

 

==============================================================

#include 
#include 
#include 
#include 
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/mman.h" /* mmap() is defined in this header */

int main (int argc, char *argv[])
{
    int fdin, fdout;
    char *src, *dst;
    struct stat statbuf;

    if (argc != 3) {
        printf("usage: a.out  \n");
        return -1;
    }

    /* open the input file */
    if ((fdin = open (argv[1], O_RDONLY)) < 0) {
        printf ("can't open %s for reading", argv[1]);
        return -2;
    }
    /* open/create the output file */
    if ((fdout = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {
        printf ("can't create %s for writing", argv[2]);
        return -2;
    }

    /* find size of input file */
    if (fstat (fdin,&statbuf) < 0) {
        printf ("fstat error");
        return -2;
    }

    /* go to the location corresponding to the last byte */
    if (lseek (fdout, statbuf.st_size - 1, SEEK_SET) == -1) {
        printf ("lseek error");
        return -2;
    }

    /* write a dummy byte at the last location */
    if (write (fdout, "", 1) != 1) {
        printf ("write error");
        return -2;
    }
    /* mmap the input file */
    if ((src = mmap(0, statbuf.st_size, PROT_READ,
                    MAP_SHARED, fdin, 0)) == (caddr_t) -1)
    {
        printf ("mmap error for input");
        return -2;
    }

    /* mmap the output file */
    if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE,
                    MAP_SHARED, fdout, 0)) == (caddr_t) -1)
    {
        printf ("mmap error for output");
        return -2;
    }

    /* this copies the input file to the output file */
    memcpy (dst, src, statbuf.st_size);

    munmap(src, statbuf.st_size);
    munmap(dst, statbuf.st_size);

    return 0;
} /* main */
/* The end of function */
실행 후 결과 화면 
$ ./a.out test test_out
$ ls -al
drwxr-xr-x  2 jeon jeon 4096 Jul 17 08:39 .
drwx------ 12 jeon jeon 4096 Jul 17 08:39 ..
-rwxr-xr-x  1 jeon jeon 6410 Jul 17 08:39 a.out
-rw-r--r--  1 jeon jeon 1844 Jul 17 08:39 mmap.c
-rw-r--r--  1 jeon jeon  469 Jul 17 08:29 test
-rw-------  1 jeon jeon  469 Jul 17 08:39 test_out

 

==============================================================

 

test라는 입력파일은 미리 생성하고

test_out은 위의 프로그램을 실행하고 생성된 파일이다.

생각보다 간단한것 같은데.

최대 어느정도까지 매핑시키는지는 추후에 해봐야겠다..

'Language > C' 카테고리의 다른 글

Unix Domain Socket 예제  (0) 2012.07.23
semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12

IPC 통신의 그다음 핵심인 Shared Memory 이용이다.

 

출처 : http://www.cs.cf.ac.uk/Dave/C/node27.html ,  http://failinux.com

 

int shmget(key_t key, int size, int shmflg);

 

key_t key 공유 메모리를 구별하는 식별 번호
int size 공유 메모리 크기
int shmflg 동작 옵션

 

 

void *shmat(int shmid, const void *shmaddr, int shmflg);

 

int shmid 공유 메모리를 구별하는 식별 번호
void *shmaddr 첨부되는 어드레스 주소. 일반적으로 NULL을 지정
int shmflg

동작 옵션

key값만 서로 맞추면 제대로 동작한다.

예제코드는 shm_server와 shm_client이고

서버쪽은 메모리에 쓰는역할

클라이언트쪽은 메모리에서 읽는 역할을 한다.

=============================================================

==== shm_server.c ====
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include 

#define SHMSZ     27

int main()
{
    char c;
    int shmid;
    key_t key;
    char *shm, *s;

    /* We'll name our shared memory segment
     * "5678".  */
    key = 9678;

    /* Create the segment.  */
    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        return -1;
    }

    /* Now we attach the segment to our data space.  */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return -1;
    }

    /* Now put some things into the memory for the
     * other process to read.  */
    s = shm;

    for (c = 'a'; c <= 'z'; c++)
        *s++ = c;
    *s = NULL;

    /*
     * Finally, we wait until the other process 
     * changes the first character of our memory
     * to '*', indicating that it has read what 
     * we put there.
     */
    while (*shm != '*')
        sleep(1);

    return 0;
}
==== shm_client.c ====
#include "sys/types.h"
#include "sys/ipc.h"
#include "sys/shm.h"
#include 

#define SHMSZ     27

int main()
{
    int shmid;
    key_t key;
    char *shm, *s;

    /* We need to get the segment named
     * "5678", created by the server.  */
    key = 5678;

    /* Locate the segment.  */
    if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
        perror("shmget");
        return -1;
    }

    /* Now we attach the segment to our data space.  */
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        return -1;
    }

    /* Now read what the server put in the memory.  */
    for (s = shm; *s != NULL; s++)
        putchar(*s);
    putchar('\n');

    /*
     * Finally, change the first character of the 
     * segment to '*', indicating we have read 
     * the segment.
     */
    *shm = '*';

    return 0;
}
== 서버측은 결과가 나오지않는다. ==
== 클라이언트측 결과는 다음과 같다. ==
$ ./clie 
abcdefghijklmnopqrstuvwxyz

 

=============================================================

 

위의 프로그램은 a-z까지 출력하는건데

키값은 5678이다. 이걸 16진수로 변환하면 162e가 되는데 이건

%ipcs 명령으로 확인하면 생성된것을 볼 수 있다.

---- 중략 ----

0x0000162e 4292650    test      666        27         2

---- 후략 ----

 

위에서 define으로 결정한 크기를 넘어서게 되면 앞쪽은 잘리고

뒤에만 출력되게 된다.

'Language > C' 카테고리의 다른 글

semget. semop, semctl 함수 예제  (0) 2012.07.17
mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12

출처 : www.cfaq.com

Q: I have a char * pointer that happens to point to some ints, and I want to step it over them. Why doesn't

((int *)p)++;

work?

int 형 포인터인데 왜 저렇게는 증가가 안되는건가?   

A: In C, a cast operator does not mean ``pretend these bits have a different type, and treat them accordingly''; it is a conversion operator, and by definition it yields an rvalue, which cannot be assigned to, or incremented with ++. (It is either an accident or a deliberate but nonstandard extension if a particular compiler accepts expressions such as the above.) Say what you mean: use

        p = (char *)((int *)p + 1);

or (since p is a char *) simply

        p += sizeof(int);

or (to be really explicit)

        int *ip = (int *)p;
        p = (char *)(ip + 1);

When possible, however, you should choose appropriate pointer types in the first place, rather than trying to treat one type as another.

See also question 16.7.

References: K&R2 Sec. A7.5 p. 205

ISO Sec. 6.3.4

Rationale Sec. 3.3.2.4

H&S Sec. 7.1 pp. 179-80

'Language > C' 카테고리의 다른 글

mmap / munmap 함수 예제  (0) 2012.07.17
shmget/ shmat 함수 예제  (0) 2012.07.13
C FAQ (포인터 증가 3)  (0) 2012.07.13
nmemb 의미  (0) 2012.07.12
msgsnd/ msgrcv 함수 예제  (0) 2012.07.12
C FAQ (포인터 증가 2)  (0) 2012.07.12

+ Recent posts