2012년 3월 28일 수요일

fd,파일디스크립터,socket 참고


1.시작하기
이 문서에서는 fd(file descriptor),소켓에 대해 조금 삐딱한 시선으로 설명해 볼 참이다.
많은 초보 플밍 입문서나 네트워크 입문서에 이 용어들에 대해 설명을 시도하고 있긴 하지만 아직 리어카 한대분의 공부도 마치지 못한,더구나 게임 중독자인 내가 볼 때 그 설명들이 바이올린처럼 높고 날카롭거나 아니면 첼로처럼 깊고 공허해서 원초적 감동을 안겨주는 그런내용,즉 가끔은 모든 삶의 부조리와 비애에도 불구하고 '살아서 좋았다!' 는 정도까지 엔지니어의 심장을 겨눈다고 할 만한 그런 내용들은 아직 본 적이 없다.
물론 미천한 내가 이 글에서 그러한 지고의 의식을 갖고 도전한다는 뜻은 결코 아니다.기대조차 말라.
하지만 어설픈 풀피리 정도라도,휘파람 정도라도 나는 내 방식안에서 설명해 볼 참이다.

여기에 당신의 너그러움을 구하는 바이다.
2.fd,파일디스크립터,파일지시자,파일기술자,,,도대체 이게 뭐냐?
한글번역에서(이 번역은 누가 어떻게 했는지 모르지만 참 적절한 사용인 것 같다.)지시자/기술자 등이 컴퓨터 프로그래밍에서 쓰이면 이는 거의 포인터의 개념으로 보면 된다.
포인터는 일정 메모리블럭의 시작주소를 값으로 갖기 때문에 fd 와 연계하여 생각하면 사용자영역에서 커널영역으로 접근할 수 있는 통로이며 그 통로는 커널의 내부 작용에 의해 커널영역안에 커널자신이 생성한 적절한 구조의 메모리블락을(버퍼를) 포인터하고 있는 변수의 이름으로 해석하면 된다.

2.1.커널영역,사용자영역
부팅시 CPU 가 자신이 설계된 방식대로 메모리를 블록/초기화하여 커널에 리턴하면 커널은 이 전체 메모리를 커널영역과 사용자영역이라는 2개의 커다란 블럭으로 구분하여 초기화한다.
  • 두 블록사이의 통신은,즉 커널 <------> 사용자 프로세서간 통신은 사용자프로세서가 커널에게 하는 특정 함수사용에 의한 특정 호출작동에 대해 커널이 그 권한을 검사한 후 적절한 요청에 대해서 커널은 내부의 일정영역에 I/O 를 위한 버퍼블럭을 할당하고 이 버퍼에 링크된 포인터를 fd 번호로 이름지어서 사용자 프로세서에 리턴하게 된다.
  • 사용자 프로세서는 이 번호를 통해서만 커널영역에 접근할 수 있는데 이 연결점,이 포인터,이 레퍼런스,이 인스턴스(용어들 제각기가 다르게 설명될 수 있지만 이 용어들의 바닥에는 '블럭화된 메모리를 포인터하고 있는 주소' 라는 공통의 뉘앙스가 있다.이미지 확장을 도우려 이런 나열을 택했다.)가 리눅스에서는,그리고 아마도 대부분의 유닉스스타일에서는 그 종류의 요청에 무관하게 공통된 일관성을 유지하고 있는데
  • 일관성의 예를 들면 사용자 프로세서의 파일을 여는 요청/소켓을 여는 요청/장치를 여는 요청 등의 경우처럼 서로 다른 목적의 요청에 대해 그것을 처리하는 커널의 내부 기능들 (파일시스템 모듈/네트워크 모듈/디바이스 드라이버 모듈 같은 것들) 역시 다른 영역들이지만 이 것들이 행동하는 스타일은 다음과 같다.


    "해당하는 커널 내부의 블럭안에 I/O 버퍼를 할당하고 포인터에 양의정수로 이름을 붙여 리턴한다."

  • I/O 버퍼의 크기 및 구조는 커널내부의 어떤 모듈이 요청을 처리하느냐에 따라 다른데 커널소스에 각 과정에 대한 추적을 할 수 있으며,어떤 요청에 대해서는 해당모듈 안에서만,어떤 요청에 대해서는 그 버퍼가 여러 모듈에 걸쳐서 참조되거나 전역으로 복사되기도 하지만 이는 커널내부의 동작일 뿐 사용자프로세서는 원래의 목적에 의해 승인받은 그 fd 로 1차적인 접근만 할 뿐이다.
  • 앞에서도 말했듯 포인터에 양의 정수로 이름을 붙여 리턴하며 이는 고유의 커널자원으로 2가지 형태로 커널내부에서 관리되는데

    Per-Process file table (하나의 프로세서와 관계된 : 열린 fd 테이블)
    ->아래 커널소스에서 구조체 fdtable
    Open file table (시스템 전체 : 열린 fd 테이블)
    ->아래 커널소스에서 구조체 files_struct

    로 이 2가지 자료구조는 긴밀히 연관되어 있고 커널의 여러곳에서 서로 교차하여 참조되고 있는 것을 볼 수 있으며 리눅스커널에서는
    include/linux/file.h 에
    구조체 fdtable와 구조체 files_struct 로 정의되어 있다.(PC방에서 윈도우상에서 리눅스 커널을 검색해 본 결과 커널 버전에 따라 없거나 위치가 다른 버전도 있기는 하다.)
  • 이 2가지 구조체 멤버에 따라 하나의 프로세서가 열 수 있는 fd 의 갯수라든가 시스템 전체에서 열 수 있는 fd 의 갯수가 제한되는데 NR_OPEN,NR_FILE 과 같은 것들이 여기에 적용된다.
2.2.간단히 알아보는 커널의 fd 관련 자료구조의 위치
fd 의 처리를 추적해 위에서 말한 2가지의 fd 테이블을 시작으로 아래처럼 계속 트리구조를 이루게 되는데 미리 말하지만 난 C 플머도 아니고 뭣도 아니고 PC 도 없으므로 오랜 시간에 걸쳐 이 소스를 분석하거나 모든 함수와 구조체에 대해 트리를 파 볼 수는 없다.
플밍에 대한 것을 내게 묻지말라.내가 언젠가 플밍을 하게 되기라도 한다면 아마도 "헬로우 월드"부터 다시 시작하게 될 것이니까 말이다!
앞부분은 커널 자료구조이며 뒷부분은 커널소스에서의 위치이다.

task_struct 에서 시작하여 <---------------  include/linux/sched.h
946 /* open file information */
947         struct files_struct *files;

files_struct안의 fdtable과 files_struct <---------------  include/linux/file.h  
 29 struct fdtable {
 30         unsigned int max_fds;
 31         struct file ** fd;      /* current fd array */
 32         fd_set *close_on_exec;
 33         fd_set *open_fds;
 34         struct rcu_head rcu;
 35         struct fdtable *next;
 36 };
 37
 38 /*
 39  * Open file table structure
 40  */

 41 struct files_struct {
 42   /*
 43    * read mostly part
 44    */
 45         atomic_t count;
 46         struct fdtable *fdt;
 47         struct fdtable fdtab;
 48   /*
 49    * written part on a separate cache line in SMP
 50    */
 51         spinlock_t file_lock ____cacheline_aligned_in_smp;
 52         int next_fd;
 53         struct embedded_fd_set close_on_exec_init;
 54         struct embedded_fd_set open_fds_init;
 55         struct file * fd_array[NR_OPEN_DEFAULT];
 56 };

files_struct 안의 file,inode    <---------------  include/linux/fs.h
747 struct file {
748         /*
749          * fu_list becomes invalid after file_free is called and queued via
750          * fu_rcuhead for RCU freeing
751          */
752         union {
753                 struct list_head        fu_list;
754                 struct rcu_head         fu_rcuhead;
755         } f_u;
756         struct path             f_path;
757 #define f_dentry        f_path.dentry
758 #define f_vfsmnt        f_path.mnt
759         const struct file_operations    *f_op;
760         atomic_t                f_count;
761         unsigned int            f_flags;
762         mode_t                  f_mode;
763         loff_t                  f_pos;
764         struct fown_struct      f_owner;
765         unsigned int            f_uid, f_gid;
766         struct file_ra_state    f_ra;
767
768         unsigned long           f_version;
769 #ifdef CONFIG_SECURITY
770         void                    *f_security;
771 #endif
772         /* needed for tty driver, and maybe others */
773         void                    *private_data;
774
775 #ifdef CONFIG_EPOLL
776         /* Used by fs/eventpoll.c to link all the hooks to this file */
777         struct list_head        f_ep_links;
778         spinlock_t              f_ep_lock;
779 #endif /* #ifdef CONFIG_EPOLL */
780         struct address_space    *f_mapping;
781 };


526 struct inode {
527         struct hlist_node       i_hash;
528         struct list_head        i_list;
529         struct list_head        i_sb_list;
530         struct list_head        i_dentry;
531         unsigned long           i_ino;
532         atomic_t                i_count;
533         unsigned int            i_nlink;
534         uid_t                   i_uid;
535         gid_t                   i_gid;
536         dev_t                   i_rdev;
537         unsigned long           i_version;
538         loff_t                  i_size;
539 #ifdef __NEED_I_SIZE_ORDERED
540         seqcount_t              i_size_seqcount;
541 #endif
542         struct timespec         i_atime;
543         struct timespec         i_mtime;
544         struct timespec         i_ctime;
545         unsigned int            i_blkbits;
546         blkcnt_t                i_blocks;
547         unsigned short          i_bytes;
548         umode_t                 i_mode;
549         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
550         struct mutex            i_mutex;
551         struct rw_semaphore     i_alloc_sem;
552         struct inode_operations *i_op;
553         const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
554         struct super_block      *i_sb;
555         struct file_lock        *i_flock;
556         struct address_space    *i_mapping;
557         struct address_space    i_data;
558 #ifdef CONFIG_QUOTA
559         struct dquot            *i_dquot[MAXQUOTAS];
560 #endif
561         struct list_head        i_devices;
562         union {
563                 struct pipe_inode_info  *i_pipe;
564                 struct block_device     *i_bdev;
565                 struct cdev             *i_cdev;
566         };
567         int                     i_cindex;
568
569         __u32                   i_generation;
570
571 #ifdef CONFIG_DNOTIFY
572         unsigned long           i_dnotify_mask; /* Directory notify events */
573         struct dnotify_struct   *i_dnotify; /* for directory notifications */
574 #endif
575
576 #ifdef CONFIG_INOTIFY
577         struct list_head        inotify_watches; /* watches on this inode */
578         struct mutex            inotify_mutex;  /* protects the watches list */
579 #endif
580
581         unsigned long           i_state;
582         unsigned long           dirtied_when;   /* jiffies of first dirtying */
583
584         unsigned int            i_flags;
585
586         atomic_t                i_writecount;
587 #ifdef CONFIG_SECURITY
588         void                    *i_security;
589 #endif
590         void                    *i_private; /* fs or device private pointer */
591 };


이상은 커널 2.6.20 의 내용이고 2.2와 2.4,2.6 에서의 inode 취급이 바뀌고 있는데 아래 2.4 의 inode 멤버를 보면 공용체로 각 파일시스템 독단적인 것이나 소켓이나 선언하고 있지만 위의 2.6 에서는 이 부분을 찾을 수 없다.
440 struct inode {
441         struct list_head        i_hash;
442         struct list_head        i_list;
443         struct list_head        i_dentry;
444        
445         struct list_head        i_dirty_buffers;
446         struct list_head        i_dirty_data_buffers;
447
448         unsigned long           i_ino;
449         atomic_t                i_count;
450         kdev_t                  i_dev;
451         umode_t                 i_mode;
452         unsigned int            i_nlink;
453         uid_t                   i_uid;
454         gid_t                   i_gid;
455         kdev_t                  i_rdev;
456         loff_t                  i_size;
457         time_t                  i_atime;
458         time_t                  i_mtime;
459         time_t                  i_ctime;
460         unsigned int            i_blkbits;
461         unsigned long           i_blksize;
462         unsigned long           i_blocks;
463         unsigned long           i_version;
464         unsigned short          i_bytes;
465         struct semaphore        i_sem;
466         struct rw_semaphore     i_alloc_sem;
467         struct semaphore        i_zombie;
468         struct inode_operations *i_op;
469         struct file_operations  *i_fop; /* former ->i_op->default_file_ops */
470         struct super_block      *i_sb;
471         wait_queue_head_t       i_wait;
472         struct file_lock        *i_flock;
473         struct address_space    *i_mapping;
474         struct address_space    i_data;
475         struct dquot            *i_dquot[MAXQUOTAS];
476         /* These three should probably be a union */
477         struct list_head        i_devices;
478         struct pipe_inode_info  *i_pipe;
479         struct block_device     *i_bdev;
480         struct char_device      *i_cdev;
481
482         unsigned long           i_dnotify_mask; /* Directory notify events */
483         struct dnotify_struct   *i_dnotify; /* for directory notifications */
484
485         unsigned long           i_state;
486
487         unsigned int            i_flags;
488         unsigned char           i_sock;
489
490         atomic_t                i_writecount;
491         unsigned int            i_attr_flags;
492         __u32                   i_generation;
493         union {
494                 struct minix_inode_info         minix_i;
495                 struct ext2_inode_info          ext2_i;
496                 struct ext3_inode_info          ext3_i;
497                 struct hpfs_inode_info          hpfs_i;
498                 struct ntfs_inode_info          ntfs_i;
499                 struct msdos_inode_info         msdos_i;
500                 struct umsdos_inode_info        umsdos_i;
501                 struct iso_inode_info           isofs_i;
502                 struct nfs_inode_info           nfs_i;
503                 struct sysv_inode_info          sysv_i;
504                 struct affs_inode_info          affs_i;
505                 struct ufs_inode_info           ufs_i;
506                 struct efs_inode_info           efs_i;
507                 struct romfs_inode_info         romfs_i;
508                 struct shmem_inode_info         shmem_i;
509                 struct coda_inode_info          coda_i;
510                 struct smb_inode_info           smbfs_i;
511                 struct hfs_inode_info           hfs_i;
512                 struct adfs_inode_info          adfs_i;
513                 struct qnx4_inode_info          qnx4_i;
514                 struct reiserfs_inode_info      reiserfs_i;
515                 struct bfs_inode_info           bfs_i;
516                 struct udf_inode_info           udf_i;
517                 struct ncp_inode_info           ncpfs_i;
518                 struct proc_inode_info          proc_i;
519                 struct socket                   socket_i;
520                 struct usbdev_inode_info        usbdev_i;
521                 struct jffs2_inode_info         jffs2_i;
522                 void                            *generic_ip;
523         } u;
524 };
결국 file,inode 2가지 주요 자료구조에서 prefix_operations 구조체내의 각 함수가 리턴한 멤버값에 따라 어떤 사용자 프로세서가 관계하는 어떤 fd 에 대해 처리를 하는 것 같은데....이 하부는 예를들어
struct file_operations {

안에 20개가 넘는 함수의 포인터가 있다.
file_operations와 inode_operations 에 대한 세세한 분석은 할 수 없다.짐작컨데 전자는 fd 가 링크하는 메모리버퍼의 취급을,후자는 그 메모리에 관계된 inode 정보의 취급을 하는 것 같다.어디까지나 짐작이다.이게 맞다면 전자는 필요해도 후자는 필요없는 경우도 있지 않을까.......
2.3.실제 전체 시스템 fd 자원 중 할당가능한 번호를 찾아 FD_SET하는 함수의 예
다음은 fs/open.c 중 get_unused_fd() 함수이다.
856 int get_unused_fd(void)
857 {
858         struct files_struct * files = current->files;
859         int fd, error;
860         struct fdtable *fdt;
861
862         error = -EMFILE;
863         spin_lock(&files->file_lock);
864
865 repeat:
866         fdt = files_fdtable(files);
867         fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
868                                 files->next_fd);
869
870         /*
871          * N.B. For clone tasks sharing a files structure, this test
872          * will limit the total number of files that can be opened.
873          */
874         if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
875                 goto out;
876
877         /* Do we need to expand the fd array or fd set?  */
878         error = expand_files(files, fd);
879         if (error < 0)
880                 goto out;
881
882         if (error) {
883                 /*
884                  * If we needed to expand the fs array we
885                  * might have blocked - try again.
886                  */
887                 error = -EMFILE;
888                 goto repeat;
889         }
890
891         FD_SET(fd, fdt->open_fds);
892         FD_CLR(fd, fdt->close_on_exec);
893         files->next_fd = fd + 1;
894 #if 1
895         /* Sanity check */
896         if (fdt->fd[fd] != NULL) {
897                 printk(KERN_WARNING "get_unused_fd: slot %d not NULL! ", fd);
898                 fdt->fd[fd] = NULL;
899         }
900 #endif
901         error = fd;
902
903 out:
904         spin_unlock(&files->file_lock);
905         return error;
906 }
907
908 EXPORT_SYMBOL(get_unused_fd);
3.socket,소켓, 너는 또 뭐냐?
소켓에 대한 일반 정의는 다음 RFC 147 에 이미 있다.

내 나름대로 자유롭게 더하자면 소켓은 TCP/IP 식으로 표현한 응용의 주소이다.
이것이 네트워크 계층모델의 이미지를 포함하면서도 응용의 유일성,즉 주소라는 개념으로 정의될 수 있는 이유는 이 socket 이라는 다소 컴퓨터와 거리가 있을 것 같은 미국넘들의 단어로 표현한 같은 이름의 함수가 리턴하는 것이 바로 앞에서 얘기했던 fd 이기 때문이다.
바꿔 말하면
네트워크 용어로서의 소켓은 TCP/IP 의 계층추적을 하면서 각 계층별로 내포된 주소의 의미로
맥주소 -> IP주소 -> 포트주소(번호) -> 소켓(fd = 응용의 주소)
의 연장선에 있는 뉘앙스가 강한 그런 개념이고
플밍용어로서의 소켓은 socket() 함수가 리턴하는 fd 가 하나의 시스템내에서 해당 사용자 프로세서와 커널 내부 모듈로의 최초의 연결점으로서의 주소 역할을 하기 때문에 플밍에서 소켓하면 이 커널에 fd 요청을 하는 함수 자체를 얘기하는 뉘앙스가 강한 개념이다.
네트워크 용어로서의 소켓은 결국 사용자 프로세서가 사용하는
fd  + <네트워크주소 및 전송주소> 하는 작용(bind)을 통해 인터넷상에 존재하는 유일 주소를 추상적으로 일컫는 것이므로 소켓의 기술적 의미는 어디까지나 플밍에서의 소켓,소켓함수가 커널에 요청하는 유형,커널의 그 요청 유형에 맞는 버퍼할당과 이 포인터 리턴 - 까지의 작동중에 거의 다 있다고 할 수 있다.
디스크에 있는 파일의 open 에도 fd, 소켓의 연결에도 fd,,,,라면 두 fd 는 차이가 있는가? 차이는 뭔가? 서로 혼용하여,예를들어 open 으로 할당받은 fd 에 주소를 bind 하는 것이 가능한가?.........
이런 물음에 대한 답은 앞에 거의 다 있다.
둘의 fd 는 같다.
함수자체도 커널 인터페이스에서 하나의 식별자 역할을 하므로 open 시스템콜이 오면 커널은 파일시스템루틴아래에,socket 시스템콜이 오면 네트워크루틴아래로 점프하여 버퍼를 할당하고 포인터변수를 양의정수로 이름지어 리턴한다.
따라서 포인터하고 있는 커널내의 버퍼 위치와 버퍼의 자료구조가 다르며 당연히 혼용하여 사용할 수 없다.
파일시스템처리루틴아래 할당된 버퍼의 크기와 모양은 네트워크를 위한 것과는 다르며,조금이라도 다를 경우 엄격하게 이는 에러를 리턴하기 때문이다.
3.1.플밍에서 소켓일반
이는 사용자 프로세서가 커널의 네트워크모듈내의 I/O 버퍼로 통하는 포인터로 fd 를 할당받기 위한 요청에 광범위하게 쓰이는 함수로서의 socket() 으로 구현되는 과정을 대략적으로 살펴 봄으로써 이해가능하다.
음.....소켓 함수에 대해 몇 문서를 보았지만 리눅스 맨페이지가 가장 맘에 들었다.
int socket(int domain, int type, int protocol); 
  • 첫 인자는 AF_ 또는 PF_ 접두사가 붙어 있는 상수로(AF 는 address family / PF 는 protocol family 의 약자)예를들어 IPv4 는 AF_INET 또는 PF_INET 이고 IPv6 는 AF_INET6 또는 PF_INET6 와 같이 큰 범위의 주소 세그먼트이고 이는
    include/linux/socket.h 
    에 상수로 정의되어 있다.
    AF_ 이든 PF_ 이든 아무거나 사용해도 매크로로 정의되어 있으므로 관계없다.
  • 세번째 인자는 첫 인자의 하부 개념으로 domain 세그먼트의 protocol 옵셋 으로 생각할 수 있다.
    첫 인자가 PF_INET 처럼 평범한 경우에는 'IP 버전 4 에 해당하는 커널 처리루틴 안에 메모리블럭을 만들어 주세요~' 라는 식의 요청의미가 있고
    이어 두번째 인자로 SOCK_STREAM/SOCK_DGRAM 을 주면 커널은 TCP/IP 의 전송영역의 구현에 맞는 처리를 선택하게 되는데 TCP/IP 전체 표준에서 전송영역은 TCP 또는 UDP 가 있으며 이는 전송의 전부이므로 커널은 사용자 프로세서가 요청하는 fd 의 유형을 충분히 알 수 있으므로 세번째 인자는 0 으로 전달하며 '정의되지않은' 또는 '모든 유형의' 프로토콜을 의미한다.
    즉 이 2가지 타입의 경우는 ICMP 와 같이 전송영역의 표준이 아닌 값을 줄 수 없다.
  • 반면 아래 생소켓부분에서처럼 이 2번째 인자가 SOCK_RAW 같은 경우 세번째 인자로 0을 지정하거나 아니면 커널이 알 수 있는 ICMP,IGMP 를 지정하거나 아니면 예약되지 않은 값을 지정하여 서버와 클라이언트간 사설의 독자적인 프로토콜을 구현한다. 
  • 두 번째 인자는 커널이 생성할 버퍼의 유형에 대한 추가정보를 기술한다.이 버퍼의 유형은 TCP/IP 계층의 전송영역의 처리에 해당하며 다음과 같은 아주 일반적인 사용자 프로세서의 요청은
    socket(AF_INET,SOCK_STREAM,0)
    "커널 IPv4 처리루틴안의 전송루틴안에 그에 맞는 I/O 블럭을 확보하고 fd 를 리턴해 달라" 라는 식의 문장이 된다.(사실상 넷트웍장비안의 특수 내부기능이거나 ICMP,IGMP가 아니면 IP 루틴이(버전4 및 6) 네트워크루틴의 유일한 것이다.) 
3.2.생소켓(RAW SOCKET)
생소켓은 위에서 말한 아주 평범한 소켓과 다르게 커널의 네트워크루틴안에,즉 전송영역이 아니라 네트워크영역에 I/O 버퍼를 확보하고 사용자 프로세서에 fd 를 리턴한다.따라서 이 요청은 루트 또는 루트가 설정한 권한의 사용자만 가능하다.

일반적인 유닉스스타일로는
socket(AF_INET, SOCK_RAW, protocol);
리눅스에서는 위 방법도 되고 좀 더 세부적으로
socket(PF_PACKET,SOCK_RAW, int protocol);
과 같은 형태를 지원한다. 이는 리눅스 단독의 것으로 보이는데 확실치는 않다.(2번째 인자에 SOCK_DGRAM 을 사용할 수도 있으나 그 차이는 링크계층-커널이 네트워크 장치드라이버로부터 리턴받는,내가 다른문서에서 언급했던 시스코의 양다리 그림을 연상하라-의 헤더를 포함하는가 제거하는가의 차이이므로 생소켓의 본질적인 개념 설명에는 중요하지 않아서 SOCK_RAW 로만 했다.)
  • 첫 인자가 크게 주소군을 지정하고 세번째 인자로 그 주소군 안에 세부 주소를 지정한다는 의미를 세그먼트와 옵셋으로 연결하여 말했는데
  • 생소켓은 3번째 인자를 지정하지 않으면 일반소켓과 같이 앞의 도메인에 속하는 모든 하부 프로토콜을 의미하니깐 중요하지 않고 지정을 하게되면 이 값이 일치해야 하는데 예를들어 내가 다른 문서에서 언급했던 AoE(ATA over Ethernet) 같은 경우를 구현하는 SAN 스토리지와 여기 액세스하는 시스템간의 통신의 경우 세번째 인자에 include/linux/if_ether.h 의 다음 매크로 값을 주어서 할 수 있다.

    #define ETH_P_AOE       0x88A2          /* ATA over Ethernet            */
  • 다시 말하지만 생소켓은 커널의 네트워크루틴에서 전송이 아닌 네트워크계층에 fd 를 위치시키므로 특별한 소켓이다.그리고 이것은 주로 시스템 점검 및 모니터링을 위한 root 용 프로그램에 있고 대표적으로 ping,traceroute,tcpdump 와 같은 프로그램이 내부적으로 이런 생소켓 호출을 한다.
  • ICMP,IGMP 와 같은 프로토콜을 지정한 통신에서 반드시 생소켓 호출이 일어나는데 지금에 와서는 아닌 부분도 있지만 이런 개념이 태어날 초기에는 ICMP 가 시스템의 네트워크 모듈이 이해하는 프로토콜로 기술되는 측면이 강했고,IGMP 는 라우터의 네트워크 모듈이 이해하는 프로토콜로 기술되는 측면이 강했기에 전송을 제외하고 네트워크계층에서 해석하고 포맷할 수 있는 간략하고 빠른 방법을 설계하기 위해 특별히 만들어진 것이라 보면 된다.
  • 현 시점에서는 일반인들은 ping 정도면 족하고 시스템 엔지니어라 할 만한 사람들은 각 시스템 독자적인 프로토콜의 경우도 눈여겨 볼 필요가 있다.내가 다른 문서에서 언급했던 스토리지 장비와 IEEE 의 헤더타입이 0x8100 일 경우 등과 혼합해서도 살펴보라.
    리눅스의 몇 문서에서,시스코나 인터넷의 떠도는 문서에서 차츰차츰 고속/대량의 데이타 통신에 이 네트워크계층에서 직접 처리하는 방식이나 링크계층에서 직접 처리하는 방식,즉 TCP/IP 의 계층 중에서 중간과정을 생략하여 시스템 부하를 줄이고 응용에 빠르게 접근할 수 있게끔하는 개념이 언급되는 문서를 자주 보곤한다.
    프로그래머라면
    tcpdump 개발자들이 배포하여 아주 유명하며 생소켓을 통한 읽기 기능이 필요한 곳에 많이 쓰이는 pcap 라이브러리와 시스코의 프로그래머가 개발한 읽기 및 쓰기 기능이 필요한 곳에 쓰일 수 있는,pcap 보다는 알려지지 않았지만 내가 보기에 깔끔할 것 같은 libnet 을 참고해 보라.다음 사이트를 따르라.

    http://www.tcpdump.org/
    http://www.packetfactory.net/projects/libnet/
  • ICMP 및 IGMP 는 커널내에 오래전부터 이식되었다고 말했다.
    따라서 이 두가지 프로토콜이 지정되어 호출되면 이 프로그램을 사용할 때 커널은 ICMP 헤더포맷에 따라 type,code,checksum 등을 구분하여 또 다른 처리를 하지만(예를들어 커널은 ICMP 메세지가 올 경우 헤더를 분석해서 Type 값이  8/13/18 일 경우 에코응답 등 자신이 직접 처리하고 type 값이 내장 값이 아닐 경우 생소켓으로 가거나 드랍한다.)  커널에 기본 포함되지 않은 AoE 같은 경우 외부 AoE 모듈을 호출하여 리턴된 것을 생소켓을 통해 사용한 프로그램의 fd 에 전달하게 된다.
    즉 TCP/IP 또는 OSI 측면에서 커널의 링크계층에서 AoE 드라이버를 호출하여 리턴된 것이 네트워크계층으로 올라오고 네트워크계층은 이를 생소켓으로 바로 응용의 fd로 전달한다는 말이다.
  • IEEE 이더넷 프로토콜에 대해 이전에 간단히 다룬 바 있으나 사실상 나 자신 해골이 아파 더 이상 정리된상태가 아니다.따라서 위의 설명에서 네트워크 계층간/내부 응용간 관계설명은 약간의 이미지를 가지는 정도로 그치기 바란다. 오류가 많을테니 말이다.
4.FILE 에 대해
여러 질문들이 있었기 때문에 이건 추가정보로 여기 쓴다.
stdio.h 에서 제공하는 FILE 자료형은
glibc-2.7/libio/libio.h (C 라이브러리로)에 _IO_FILE 로 정의되어 있는 구조체의 다른이름으로
glibc-2.7/libio/stdio.h 에 다음처럼 다른이름으로 정의되어 있다.
typedef struct _IO_FILE FILE;
원래의 libio.h 의 _IO_FILE 은
struct _IO_FILE {
  int _flags;  /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr; /* Current read pointer */
  char* _IO_read_end; /* End of get area. */
  char* _IO_read_base; /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr; /* Current put pointer. */
  char* _IO_write_end; /* End of put area. */
  char* _IO_buf_base; /* Start of reserve area. */
  char* _IO_buf_end; /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */
  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};




출처 URL : http://www.linux.co.kr/home2/board/subbs/board.php?bo_table=linuxetc&wr_id=609&page=2 

댓글 없음:

댓글 쓰기