丨瞧一瞧linux详解socket接口实现_第1页
丨瞧一瞧linux详解socket接口实现_第2页
丨瞧一瞧linux详解socket接口实现_第3页
丨瞧一瞧linux详解socket接口实现_第4页
丨瞧一瞧linux详解socket接口实现_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

BSDTCP/IPLinuxUNIX接上,让应用程序可以用常规文件操作API网络连接。从TCP/IP协议栈的角度来看,传输层以上的都是应用程序的一部分,Linux与传统的UNIXTCP/IPLinux使用内核套接字概念与用户空间套接字通信,这样可以让实现和操作变得更简单。Linux提供了一套API和套接字数据结构,这些服务向下与内核接口,向上与用户空间接口,应用程序正是使用这一套API内核中的网络功能。在应用程序使用PP协议栈功能之前,须调用套接字库函数API新这个过程具体是这样的,在应用程序中执行socket函数,socket产生系统调用中断执行内核的套接字分路函数sys_socketcall,在sys_socketcall套接字函数分路器中将调用传送到sys_socket函数,由sys_socket函数调用套接字的通用创建函数sock_create。sock_create函数完成通用套接字创建、初始化任务后,再调用特定协议族的套接字创建这样描述你可能还没有直观感受,我特意画了图,帮你梳理socket创建的流程,你可以对照仔细体会调用过程。AF_INETinet_create一个新的structsocket数据结构起始由sock_create函数创建,该函数直接调用sock_create函数,sock_create函数的任务是为套接字预留需要的内存空间,由sock_alloc函数完成这项功能。sock_allocstructsocketstruct代代staticintsock_create(structnet*net,intfamily,inttype,intstructsocket**res,int33456789{intstructsocketconststructnet_proto_familyif(family<0||family>=NPROTO)return-EAFNOSUPPORT;if(type<0||type>=SOCK_MAX)return-EINVAL;sock=}sock_alloc代代123456789staticstructsocket{structinode*inode;structsocket*sock;//初始化一个可用的inode节点,在fs/inode.cinode=new_inode(sock_mnt->mnt_sb);if(!inode)return实际创建的是socket_alloc复合对象,因此要使用SOCKET_I宏从inode中取出关联的socketsock=SOCKET_I(inode);kmemcheck_annotate_bitfield(sock,//inode->i_mode=S_IFSOCK|S_IRWXUGO;inode->i_uid=current_fsuid();inode->i_gid=current_fsgid();percpu_add(sockets_in_use,1);returnsock;}structsocketstructproto_ops*opsNULL。随后,当某个协议族中的协议成员的套接字创建函数被调用时,ops将指向协议实例的操作函数。structsocketflags0,创建时还没有任何标志需要设在之后的调用中,应用程序调用sendreceiveflagsskfileNULL。sk建函数设置为指向内部套接字结构。file将在调用sock_ma_fd函数时设置为分配的文件文件指针用于打开套接字的虚拟文件系统的文件状态。在sock_alloc函数返回后,sock_createerrpf->create(net,sock,protocol),它通过net_families数组获取协议族的创建函数,对于TCP/IP协议栈,协议族将设置为AF_INET。sys_bind1123456789代asmlinkagelongsysbind(bind,int,fd,structsockaddruser*,umyaddr,{structsocketstructsockaddr_storageaddress;interr,fput_needed;*获取socketsock=sockfd_lookup_light(fd,&err,&fput_needed);if(sock){err=move_addr_to_kernel(umyaddr,addrlen,(structsockaddr*)&address);if(err>=0){err=security_socket_bind(sock,(structsockaddr*)&address,iferr=sock->ops-(structsockaddr&address,}fput_light(sock->file,}return}sd函数首先会查找套接字对应的socket实例,调用socoophinet_bind来完成绑定操作。inet_bind函数代代代123456789intinet_bind(structsocket*sock,structsockaddr*uaddr,int{structsockaddr_in*addr=(structsockaddr_in*)uaddr;structsock*sk=sock->sk;structinet_sock*inet=inet_sk(sk);unsignedshortsnum;intint(sk->sk_prot->bind)/*如果传输层接口上实现了bind调用,则回调它。目前只有err=sk->sk_prot->bind(sk,uaddr,goto}err=-if(addr_len<sizeof(structsockaddr_in))gotoout;err=-if(!sysctl_ip_nonlocal_bind&&/*必须绑定到本地接口的地址bindaddr->sin_addr.s_addrINADDR_ANY&&/*绑定地址不合法chk_addr_ret!=RTN_LOCAL&&chk_addr_ret!=RTN_MULTICAST&&chk_addr_ret!=RTN_BROADCAST)gotoout;snum=ntohs(addr->sin_port);err=-EACCES;if(snum&&snum<PROT_SOCK&&!capable(CAP_NET_BIND_SERVICE))gotoout;lock_sock(sk);/*对套接口进行加锁,因为后面要对其状态进行判断/*Checktheseerrors(activesocket,doublebind).err=-*如果状态不为CLOSE*或者已经指定了本地端,也不能再绑if(sk->sk_state!=TCP_CLOSE||inet-goto/*设址到传输控制块中inet->rcv_saddr=inet->saddr=addr-/*如果是广播或者多播地址,则源地址使用设备地址。if(chk_addr_ret==RTN_MULTICAST||chk_addr_ret==inet->saddr=0;/*Usedevice/*调用传输层的get_port来进行地址绑定。如tcp_v4_get_port或if(sk->sk_prot->get_port(sk,snum))…}/*设置标志,表示已经绑定了本地地址和端口if(inet-sk->sk_userlocks|=ifsk->sk_userlocks|=inet->sport=htons(inet-/*还没有连接到对方,清除远端地址和端口inet->daddr=inet->dport=/*清除路由缓存err=return}因为应用程序处理的是面向连接的网络服务(OCK_SRAM或所以在交换数据之前,需要在请求连接服务的进程(客户)与提供服务的进程(服务器)之间建立连接。connectsys_connect,详细代intsys_connect(intfd,structsockaddruser*uservaddr,int{intret=-structfdf=if(f.file)structsockaddr_storageret=move_addr_to_kernel(uservaddr,addrlen,if调用ret=sys_connect_file(f.file,&address,addrlen, return15socketlistensys_listenfd代代123456789intsys_listen(intfd,int{structsocket*sock;interr,fput_needed;intsomaxconn;//通过套接字描述符找到structsock=sockfd_lookup_light(fd,&err,&fput_needed);if(sock){somaxconn=sock_net(sock->sk)->core.sysctl_somaxconn;if((unsignedint)backlog>somaxconn)backlog=err=security_socket_listen(sock,if//err=sock->ops->listen(sock,backlog);fput_light(sock->file,fput_needed);}return}用accept函数,应用程序触发内核函数sys_accept,等待接收连接请求。如果允许连 sys_accept4_file(structfile*file,unsignedstruct user user*upeer_addrlen,intunsignedlong5structsocket*sock,structfileinterr,len,structsockaddr_storageif(flags&~(SOCK_CLOEXEC|return-if(SOCK_NONBLOCK!=O_NONBLOCK&&(flags&flags=(flags&~SOCK_NONBLOCK)|sock=sock_from_file(file,ifgotoerr=-//newsock=ifgotonewsock->type=sock-newsock->ops=sock-newfd get_unused_fd_flags(flags,if(unlikely(newfd<0))err=goto newfile=sock_alloc_file(newsock,flags,sock->sk->sk_prot_creator-if(IS_ERR(newfile))err=goto err=security_socket_accept(sock,ifgoto//根据套接字类型调用不同的函数err=sock->ops->accept(sock,newsock,sock->file->f_flags|if(err<0)gotoout_fd;if(upeer_sockaddr)len=newsock->ops->getname(newsock,(structsockaddr*)&address,2);if(len<0)err=-goto}//err=len,upeer_sockaddr,upeer_addrlen);if(err<0)goto}/*Fileflagsarenotinheritedviaaccept()unlikeanotherOSes.*/fd_install(newfd,newfile);err=newfd;returnerr;gotoout;}send,sendwritesend许应用程序指定标志,规定如何对待传送数据。调用send函数时,会触发内核的sys_send函数,把发送缓冲区的数据发送出去。sys_send应用程序的数据被到内核后,sys_send函数调用sock_sendmsg,依据协议族类如果是INET,sock_sendmsg将调用inet_sendmsgTCPinet_sendmsgtcp_sendmsgTCPsend函数返回发送成功,并不意味着在连接的另一端的进程可以收到数据,这里只能保证发送send函数执行成功,发送给网络设备驱动程序的数据没有出错。recv函数与文件读read函数类似,recv函数中可以指定标志来控制如何接收数据,调用recv函数时,应用程序会触发内核的sys_recv函数,把网络中的数据递交到应用程序。当然,read、recvfrom函数也会触发sys_recv函数。具体流程如下。为把内核的网络数据转入应用程序的接收缓冲区,sys_recv函数依次调用sys_recvfrom、sock_recvfrom和 如果是INET协议族套接字 sock_recvmsg将调 mon_recvmsg函数如果采用TCP协议 mon_recvmsg函数将调用tcp_recvmsg,按照如果接收方想获取数据包发送端的标识符,应用程序可以调用sys_recvfrom函数来获取数据包发送方的源地址,下面是sys_recvfrom函数的实现。代代intsys_recvfrom(intfd,voiduser*ubuf,size_tsize,unsignedintstructsockaddruser*addr,intuser3structsocketstructiovecstructmsghdrstructsockaddr_storageinterr,interr=import_single_range(READ,ubuf,size,&iov,ifreturn//通过套接字描述符找到structsock=sockfd_lookup_light(fd,&err,ifgotoout;msg.msg_control=NULL;msg.msg_controllen=/*Savesomecyclesanddon'tcopytheaddressifnotneeded*/msg.msg_name=addr?(structsockaddr*)&address:NULL;/*Weassumeallkernelcodeknowsthesizeofsockaddr_storage*/msg.msg_namelen=0;msg.msg_iocb=NULL;msg.msg_flags=0;if(sock->file->f_flags&O_NONBLOCK)flags|=MSG_DONTWA

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论