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.h946 /* open file information */
947 struct files_struct *files;files_struct안의 fdtable과 files_struct <--------------- include/linux/file.h29 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.h747 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(PF_PACKET,SOCK_RAW, int protocol);
일반적인 유닉스스타일로는
socket(AF_INET, SOCK_RAW, 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 자료형은typedef struct _IO_FILE FILE;
glibc-2.7/libio/libio.h (C 라이브러리로)에 _IO_FILE 로 정의되어 있는 구조체의 다른이름으로
glibc-2.7/libio/stdio.h 에 다음처럼 다른이름으로 정의되어 있다.
원래의 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
댓글 없음:
댓글 쓰기