新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > linux內核中的文件描述符(二)--socket和文件描述符

        linux內核中的文件描述符(二)--socket和文件描述符

        作者: 時間:2016-11-22 來源:網絡 收藏
        Kernel version:2.6.14

        CPU architecture:ARM920T

        本文引用地址:http://www.104case.com/article/201611/319998.htm

        Author:ce123(http://blog.csdn.net/ce123)

        socket和文件系統緊密相關,我們可以通過文件系統的open、read、write和close等操作socket。下面是一個簡單的例子。

        [plain]view plaincopy
        print?
        1. /****************************************************************************/
        2. /*簡介:TCPServer示例*/
        3. /****************************************************************************/
        4. #include
        5. #include
        6. #include
        7. #include
        8. #include
        9. #include
        10. #include
        11. #include
        12. intmain(intargc,char*argv[])
        13. {
        14. intsockfd,new_fd;
        15. structsockaddr_inserver_addr;
        16. structsockaddr_inclient_addr;
        17. intsin_size,portnumber;
        18. constcharhello[]="Hellon";
        19. if(argc!=2)
        20. {
        21. fprintf(stderr,"Usage:%sportnumberan",argv[0]);
        22. exit(1);
        23. }
        24. if((portnumber=atoi(argv[1]))<0)
        25. {
        26. fprintf(stderr,"Usage:%sportnumberan",argv[0]);
        27. exit(1);
        28. }
        29. /*服務器端開始建立socket描述符*/
        30. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
        31. {
        32. fprintf(stderr,"Socketerror:%sna",strerror(errno));
        33. exit(1);
        34. }
        35. /*服務器端填充sockaddr結構*/
        36. bzero(&server_addr,sizeof(structsockaddr_in));
        37. server_addr.sin_family=AF_INET;
        38. server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
        39. server_addr.sin_port=htons(portnumber);
        40. /*捆綁sockfd描述符*/
        41. if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==
        42. -1)
        43. {
        44. fprintf(stderr,"Binderror:%sna",strerror(errno));
        45. exit(1);
        46. }
        47. /*監聽sockfd描述符*/
        48. if(listen(sockfd,5)==-1)
        49. {
        50. fprintf(stderr,"Listenerror:%sna",strerror(errno));
        51. exit(1);
        52. }
        53. while(1)
        54. {
        55. /*服務器阻塞,直到客戶程序建立連接*/
        56. sin_size=sizeof(structsockaddr_in);
        57. if((new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size))==-1)
        58. {
        59. fprintf(stderr,"Accepterror:%sna",strerror(errno));
        60. exit(1);
        61. }
        62. fprintf(stderr,"Servergetconnectionfrom%sn",
        63. inet_ntoa(client_addr.sin_addr));
        64. if(write(new_fd,hello,strlen(hello))==-1)
        65. {
        66. fprintf(stderr,"WriteError:%sn",strerror(errno));
        67. exit(1);
        68. }
        69. /*這個通訊已經結束*/
        70. close(new_fd);
        71. /*循環下一個*/
        72. }
        73. close(sockfd);
        74. exit(0);
        75. }

        下圖說明了socket和fd是怎樣聯系起來的。

        下面通過來具體分析一下。sys_socket是socket相關函數的總入口。

        [plain]view plaincopy
        print?
        1. net/socket.c
        2. /*
        3. *Systemcallvectors.
        4. *
        5. *Argumentcheckingcleanedup.Saved20%insize.
        6. *Thisfunctiondoesntneedtosetthekernellockbecause
        7. *itissetbythecallees.
        8. */
        9. asmlinkagelongsys_socketcall(intcall,unsignedlong__user*args)
        10. {
        11. unsignedlonga[6];
        12. unsignedlonga0,a1;
        13. interr;
        14. if(call<1||call>SYS_RECVMSG)
        15. return-EINVAL;
        16. /*copy_from_usershouldbeSMPsafe.*/
        17. if(copy_from_user(a,args,nargs[call]))
        18. return-EFAULT;
        19. err=audit_socketcall(nargs[call]/sizeof(unsignedlong),a);
        20. if(err)
        21. returnerr;
        22. a0=a[0];
        23. a1=a[1];
        24. switch(call)
        25. {
        26. caseSYS_SOCKET:
        27. err=sys_socket(a0,a1,a[2]);
        28. break;
        29. caseSYS_BIND:
        30. err=sys_bind(a0,(structsockaddr__user*)a1,a[2]);
        31. break;
        32. caseSYS_CONNECT:
        33. err=sys_connect(a0,(structsockaddr__user*)a1,a[2]);
        34. break;
        35. caseSYS_LISTEN:
        36. err=sys_listen(a0,a1);
        37. break;
        38. caseSYS_ACCEPT:
        39. err=sys_accept(a0,(structsockaddr__user*)a1,(int__user*)a[2]);
        40. break;
        41. caseSYS_GETSOCKNAME:
        42. err=sys_getsockname(a0,(structsockaddr__user*)a1,(int__user*)a[2]);
        43. break;
        44. caseSYS_GETPEERNAME:
        45. err=sys_getpeername(a0,(structsockaddr__user*)a1,(int__user*)a[2]);
        46. break;
        47. caseSYS_SOCKETPAIR:
        48. err=sys_socketpair(a0,a1,a[2],(int__user*)a[3]);
        49. break;
        50. caseSYS_SEND:
        51. err=sys_send(a0,(void__user*)a1,a[2],a[3]);
        52. break;
        53. caseSYS_SENDTO:
        54. err=sys_sendto(a0,(void__user*)a1,a[2],a[3],
        55. (structsockaddr__user*)a[4],a[5]);
        56. break;
        57. caseSYS_RECV:
        58. err=sys_recv(a0,(void__user*)a1,a[2],a[3]);
        59. break;
        60. caseSYS_RECVFROM:
        61. err=sys_recvfrom(a0,(void__user*)a1,a[2],a[3],
        62. (structsockaddr__user*)a[4],(int__user*)a[5]);
        63. break;
        64. caseSYS_SHUTDOWN:
        65. err=sys_shutdown(a0,a1);
        66. break;
        67. caseSYS_SETSOCKOPT:
        68. err=sys_setsockopt(a0,a1,a[2],(char__user*)a[3],a[4]);
        69. break;
        70. caseSYS_GETSOCKOPT:
        71. err=sys_getsockopt(a0,a1,a[2],(char__user*)a[3],(int__user*)a[4]);
        72. break;
        73. caseSYS_SENDMSG:
        74. err=sys_sendmsg(a0,(structmsghdr__user*)a1,a[2]);
        75. break;
        76. caseSYS_RECVMSG:
        77. err=sys_recvmsg(a0,(structmsghdr__user*)a1,a[2]);
        78. break;
        79. default:
        80. err=-EINVAL;
        81. break;
        82. }
        83. returnerr;
        84. }/*Itmaybealreadyanotherdescriptor8)Notkernelproblem.*/
        85. returnretval;
        86. out_release:
        87. sock_release(sock);
        88. returnretval;
        89. }
        當應用程序使用socket()創建一個socket時,會執行sys_socket,其定義如下

        [plain]view plaincopy
        print?
        1. asmlinkagelongsys_socket(intfamily,inttype,intprotocol)
        2. {
        3. intretval;
        4. structsocket*sock;
        5. retval=sock_create(family,type,protocol,&sock);//創建socket
        6. if(retval<0)
        7. gotoout;
        8. retval=sock_map_fd(sock);//分配一個未使用的文件描述符fd,并將socket和fd建立聯系
        9. if(retval<0)
        10. gotoout_release;
        11. out:
        12. /*Itmaybealreadyanotherdescriptor8)Notkernelproblem.*/
        13. returnretval;
        14. out_release:
        15. sock_release(sock);
        16. returnretval;
        17. }
        結構體socket的定義如下(includelinuxnet.h):

        [plain]view plaincopy
        print?
        1. structsocket{
        2. socket_statestate;
        3. unsignedlongflags;
        4. structproto_ops*ops;
        5. structfasync_struct*fasync_list;
        6. structfile*file;//通過這個和文件描述符建立聯系
        7. structsock*sk;
        8. wait_queue_head_twait;
        9. shorttype;
        10. };
        下面我們再來看看sock_map_fd函數

        [plain]view plaincopy
        print?
        1. intsock_map_fd(structsocket*sock)
        2. {
        3. intfd;
        4. structqstrthis;
        5. charname[32];
        6. /*
        7. *Findafiledescriptorsuitableforreturntotheuser.
        8. */
        9. fd=get_unused_fd();//分配一個未使用的fd
        10. if(fd>=0){
        11. structfile*file=get_empty_filp();
        12. if(!file){
        13. put_unused_fd(fd);
        14. fd=-ENFILE;
        15. gotoout;
        16. }
        17. this.len=sprintf(name,"[%lu]",SOCK_INODE(sock)->i_ino);
        18. this.name=name;
        19. this.hash=SOCK_INODE(sock)->i_ino;
        20. file->f_dentry=d_alloc(sock_mnt->mnt_sb->s_root,&this);
        21. if(!file->f_dentry){
        22. put_filp(file);
        23. put_unused_fd(fd);
        24. fd=-ENOMEM;
        25. gotoout;
        26. }
        27. file->f_dentry->d_op=&sockfs_dentry_operations;
        28. d_add(file->f_dentry,SOCK_INODE(sock));
        29. file->f_vfsmnt=mntget(sock_mnt);
        30. file->f_mapping=file->f_dentry->d_inode->i_mapping;
        31. sock->file=file;//建立聯系
        32. file->f_op=SOCK_INODE(sock)->i_fop=&socket_file_ops;//socket操作函數,當使用文件系統的IO函數時,其實使用的是socket的IO函數
        33. file->f_mode=FMODE_READ|FMODE_WRITE;
        34. file->f_flags=O_RDWR;
        35. file->f_pos=0;
        36. file->private_data=sock;
        37. fd_install(fd,file);
        38. }
        39. out:
        40. returnfd;
        41. }
        42. staticstructfile_operationssocket_file_ops={
        43. .owner=THIS_MODULE,
        44. .llseek=no_llseek,
        45. .aio_read=sock_aio_read,
        46. .aio_write=sock_aio_write,
        47. .poll=sock_poll,
        48. .unlocked_ioctl=sock_ioctl,
        49. .mmap=sock_mmap,
        50. .open=sock_no_open,/*specialopencodetodisallowopenvia/proc*/
        51. .release=sock_close,
        52. .fasync=sock_fasync,
        53. .readv=sock_readv,
        54. .writev=sock_writev,
        55. .sendpage=sock_sendpage
        56. };



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 洛浦县| 西藏| 固安县| 禄劝| 左贡县| 栾城县| 家居| 华蓥市| 庐江县| 金川县| 喀喇沁旗| 曲水县| 陵川县| 芜湖县| 扬州市| 罗平县| 伊金霍洛旗| 文成县| 滨州市| 赫章县| 梧州市| 施甸县| 隆回县| 若尔盖县| 白朗县| 来凤县| 庐江县| 温州市| 同德县| 得荣县| 公主岭市| 潞城市| 九寨沟县| 云浮市| 花莲县| 蓝山县| 白沙| 霍邱县| 焦作市| 贵港市| 舟曲县|