发信人: liangvy()
整理人: hahalee(1999-06-29 12:02:55), 站内信件
|
[ Lenn<[email protected]>版权所有,不得书面出版 ]
2。4进程通信 (socket和network interface)
网络协议和路由选择的过程中,为选择合适的网络接口,一般进程没必要对 网络接口进行明确指示。所以,网络卡就不和文件系统的名字对应,而是在核心内部 的struct ifnet(@net/if.h)进行对应。用命令ifconfig和netstat -i就可以看到各个 网卡的struct ifnet的参数。 unix中,进程通信和网络介入的通信的场合,使用network interface。进行 通信的进程,根据socket()的系统调用,把socket作为通信手段。这个时候,需要指 定协议族,通信类型,具体的协议等。综合起来,有如下的参数:
int socket( int domain, //protocal family int type, //通信形式 int protocal //具体的协议 )
根据protocal family可以推算出可以通信的范围,同时,可以控制通信类型和具体的 协议。通信类型有如下的四个种类。
.SOCK_STREAM 基于连接的传输,具有可靠性,可以保证通信的发送接收顺序的双向通信路。 但不限制数据的传输顺序的紧急数据发送情况也有可能。发送数据和接受数据的 的间隔不一定。比如一次发送10个byte,可能一次接受完毕,但发送100个byte, 可能一次接受完毕,也可能分两次接收。
.SOCK_DREAM 可靠性比较低。不是基于连接传输。每次的发送数据长度是有限制的。
.SOCK_SEQPACKET 基于连接的传输,具有可靠性,可以保证通信的发送接收顺序的双向通信路。 和.SOCK_STREAM不同的地方是,发送数据和接受数据的间隔一定,每次的发送长度 也是限制的。
.SOCK_RAW 核心内部的network protocal和interface的控制中使用。
通信类型受制于具体的协议。freebsd协议族有如下的一些: --------------------------------------------------------------------------- 协议族 通信类型 定义模块 PF_ROUTE SOCK_RAW net/rtsock.c PF_APPLETALK SOCK_DGRAM netatalk/at_proto.c PF_INET SOCK_DGRAM netinet/in_proto.c SOCK_STREAM SOCK_RAW PF_IPX SOCK_DRAM netipx/ipx_proto.c SOCK_STREAM SOCK_SEQACKET SOCK_RAW PF_KEY SOCK_RAW netkey/key.c PF_NS SOCK_DGRAM netns/ns_proto.c SOCK_STREAM SOCK_SEQACKET SOCK_RAW PF_LOCAL SOCK_STREAM kern/uipc_proto.c SOCK_DGRAM --------------------------------------------------------------------------
这些协议族由各个struct domain里定义。在这里面,当前的协议族里可能利用的通信 类型可以在struct protosw里找到。protocal family的登记可以把宏DOMAIN_SET()设 定的信息通过函数domaininit()(@kern/uipc_domain.c)读到kernel的初始化中。
由系统调用socket()取得的socket,在进程里可以象文件柄一样的进行操作。 适当的设置后,可以使用read()/write()调用。由open()取得的文件柄对应read()/ write()/ioctl()/select()/close()处理可以使用vn_read()/vn_write()/vn_ioctl() /vn_select()/vn_close()进行相应替换,对socket的处理则是soo_read()/soo_write ()/soo)ioctl()/soo_select()/soo_close()(@kern/sys_socket.c)进行取代。对应于 socket的struct protosw的子过程则在任何地方都可以进行处理。还有可以用send() /sendto()/sendmsg()进行发送,recv()/resvfrom()/recvmsg()进行接收。
socket是绑定在通信路上的,所以,如果不规定通信对象的端子,就不能进行 实际的通信操作。也就是说,必须指定对象和自己的socket的地址。这个和protocal family不大一样,它由struct sockaddr_XXX指定。但是对socket指定地址的系统调用 对每个socket family并没有统一性,系统调用层次的地址在struct sockaddr(@sys/ socket.h)里面包含。这样,就可以区别它的成员sa_family里各个 struct sockaddr_XXX 了。 s = socket(PF_INET,SOCK_DGRAM,0)取得的socket由band()进行address的设 定后, sendto(s,msg,mlen,sockaddr_to,tolen) 里的 message msg向sockaddr_to的地址送去,kernel内则顺序进行如下的操 作处理。
1.系统调用sendto()的处理过程sendto()(@kern/uipc_syscalls.c)就是,得 到参数后在调用sendit()(@kern/uipc_syscalls.c). 2.sendit()先从参数得到发送的地址,再调用sosend() (@kern/uipc_socket.c). 3.sosend()从struct uio取得发送数据,然后向struct mbuf变换。建立socket 时候所指定address family/protocal的处理过程把 so_proto->pr_usrreqs->pru_send调出来。在这里调用了udp_userreq()(@netinet/ udp_usrreq.c)。 4.udp_usrreq()是PRU_SEND处理,它调用了udp_output()。 5.udp_output是UDP包的分组变换,它调用ip_output()(@netinet/ip_output)。 6.ip_output()的功能是从发送ip地址开始,选择network interface的子过程。 如果是ethernet,则调用ether_output()(@net/if_ethersubr.c)。还有IP firewall 的处理也在这里进行。 7.ether_output()则由发送ip地址取得ethernet的地址。进行ethernet打包, 调用在network interface里设定的子过程if_start。再对network card进行io。
(下章开始介绍如何编写驱动程序) Lenn <[email protected]>
--
Lenn Tel: 0755-3913403(H) E-mail: [email protected] Oicq: Lenn 28663
※ 来源:.网易 BBS bbs.netease.com.[FROM: www2.dt.sanyo.co.jp]
|
|