linux内核中socket的实现Word格式文档下载.docx

上传人:b****5 文档编号:18636055 上传时间:2022-12-30 格式:DOCX 页数:23 大小:29.62KB
下载 相关 举报
linux内核中socket的实现Word格式文档下载.docx_第1页
第1页 / 共23页
linux内核中socket的实现Word格式文档下载.docx_第2页
第2页 / 共23页
linux内核中socket的实现Word格式文档下载.docx_第3页
第3页 / 共23页
linux内核中socket的实现Word格式文档下载.docx_第4页
第4页 / 共23页
linux内核中socket的实现Word格式文档下载.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

linux内核中socket的实现Word格式文档下载.docx

《linux内核中socket的实现Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《linux内核中socket的实现Word格式文档下载.docx(23页珍藏版)》请在冰豆网上搜索。

linux内核中socket的实现Word格式文档下载.docx

31sys_getsockname(a0,(structsockaddr__user*)a1,

32(int__user*)a[2]);

33break;

34.....................................

35returnerr;

36}

可以看到代码比较简单,就是通过传递进来的call类型,来调用相应的socket相关的函数.

这里你可能注意到了,那就是一般文件句柄相关的操作,比如write,read,aio,poll这些并没有看到(也就是file_operations).这是因为socket上面其实还有一层vfs层,内核把socket当做一个文件系统来处理,并实现了相应的vfs方法.因此下面我们先来了解下vfs.然后会描述下进程如何通过vfs存取句柄.

vfs其实就相当于对下层的文件系统和上层应用之间的粘合层,它定义了文件系统需要实现的相关的操作,然后下层的文件系统只需要实现这些方法就可以了,也就是说在内核其他部分和上层应用看来,所有的文件系统没有任何区别.

下面的这张图就是从用户空间调用write的大体流程:

vfs中有4种主要的数据结构:

1超级块对象,代表一个已安装的文件系统.super_block

2索引节点对象,代表一个文件.inode

3目录项对象,代表一个目录项.dentry

4文件对象,表示一个被进程打开的文件.file

其中每种对象都包含一个操作对象.依次为super_operations,inode_operations,dentry_operations以及file_operations.各自操作不同的层次.然后我们的文件系统只需要实现这些方法,然后注册到内核就可以了.

接下来我们来看和vfs相应的结构:

第一个就是file_system_type结构,这个结构表示了一个文件系统:

37structfile_system_type{

38constchar*name;

39intfs_flags;

40///最关键的函数,得到文件系统的超级块.

41int(*get_sb)(structfile_system_type*,int,

42constchar*,void*,structvfsmount*);

43void(*kill_sb)(structsuper_block*);

44...........................................

45};

然后是vfsmount结构,它表示了一个安装点,换句话说也就是一个文件系统实例.

第三个是files_struct结构,它主要是为每个进程来维护它所打开的句柄.这里只需要注意一个就是fd_array和fstable中的fd的区别.当进程数比较少也就是小于NR_OPEN_DEFAULT(32)时,句柄就会存放在fd_array中,而当句柄数超过32则就会重新分配数组,然后将fd指针指向它(然后我们通过fd就可以取得相应的file结构).

而且files_struct是每个进程只有一个的.

46structfiles_struct{

47/*

48*readmostlypart

49*/

50atomic_tcount;

51structfdtable*fdt;

52structfdtablefdtab;

53/*

54*writtenpartonaseparatecachelineinSMP

55*/

56spinlock_tfile_lock____cacheline_aligned_in_smp;

57intnext_fd;

58structembedded_fd_setclose_on_exec_init;

59structembedded_fd_setopen_fds_init;

60///所打开的所有文件

61structfile*fd_array[NR_OPEN_DEFAULT];

62};

63

64

65structfdtable{

66unsignedintmax_fds;

67structfile**fd;

/*currentfdarray*/

68fd_set*close_on_exec;

69fd_set*open_fds;

70structrcu_headrcu;

71structfdtable*next;

72};

还有两个一个是fs_struct,一个是namespace也都是进程相关的.这里就不一一介绍了.

我这里vfs介绍只是个大概,需要详细了解的,可以去看ulk的vfs相关章节和linux内核设计与实现的相关章节.

因此下面的图表示了进程和socket的关系:

上面的这张图有些老了,新的内核中的inode节点中已经没有u这个联合体了,对应的是会有一个包含socket和inode的一个结构体,然后我们通过inode,而inode中专门有个i_mode域来判断相应的inode类型,比如socket就是S_IFSOCK.就可以直接计算出相应的socket的地址,然后就可以存取socket了.后面我们会介绍.

内核中标售socket有两个数据结构,一个是socket,另一个是sock,其中socket是一个generalBSDsocket,它也就是应用程序和4层协议之间的一个接口,屏蔽掉了相关的4层协议部分.而在内核中,socket所需要使用的相关的4层协议的信息全部是保存在sock结构当中的,而socket和sock这两个结构都有保存对方的指针,因此可以很容易的存取对方.

还有一个就是ops域,这个域保存了所有的相关的4层协议的操作函数..

而在sock中有一个sk_common保存了一个skc_prot域,这个域保存的是相应的协议簇的操作函数的集合.

后面介绍到socket创建的时候,我们会分析proto_ops和proto的区别.其实proto相当于对proto_ops的一层封装,最终会在proto中调用proto_ops.

73/**

74*structsocket-generalBSDsocket

75*@state:

socketstate(%SS_CONNECTED,etc)

76*@type:

sockettype(%SOCK_STREAM,etc)

77*@flags:

socketflags(%SOCK_ASYNC_NOSPACE,etc)

78*@ops:

protocolspecificsocketoperations

79*@fasync_list:

Asynchronouswakeuplist

80*@file:

Filebackpointerforgc

81*@sk:

internalnetworkingprotocolagnosticsocketrepresentation

82*@wait:

waitqueueforseveraluses

83*/

84structsocket{

85socket_statestate;

86shorttype;

87unsignedlongflags;

88conststructproto_ops*ops;

89structfasync_struct*fasync_list;

90structfile*file;

91structsock*sk;

92wait_queue_head_twait;

93};

94

95structsock_common{

96unsignedshortskc_family;

97volatileunsignedcharskc_state;

98unsignedcharskc_reuse;

99intskc_bound_dev_if;

100structhlist_nodeskc_node;

101structhlist_nodeskc_bind_node;

102atomic_tskc_refcnt;

103unsignedintskc_hash;

104structproto*skc_prot;

105#ifdefCONFIG_NET_NS

106structnet*skc_net;

107#endif

108};

109

110structproto_ops{

111intfamily;

112structmodule*owner;

113int(*release)(structsocket*sock);

114int(*bind)(structsocket*sock,

115structsockaddr*myaddr,

116intsockaddr_len);

117int(*connect)(structsocket*sock,

118structsockaddr*vaddr,

119intsockaddr_len,intflags);

120...................................................

121};

然后我们来看sock_init的实现,在这个函数中,将socket注册为一个伪文件系统,并安装相应的mount点:

122///相应的mount对象

123staticstructvfsmount*sock_mnt__read_mostly;

124///文件系统对象.

125staticstructfile_system_typesock_fs_type={

126.name="

sockfs"

127.get_sb=sockfs_get_sb,

128.kill_sb=kill_anon_super,

129};

130

131staticint__initsock_init(void)

132{

133/*

134*InitializesockSLABcache.

135*/

136

137sk_init();

138

139/*

140*InitializeskbuffSLABcache

141*/

142skb_init();

143

144///初始化一个inodecache.

145init_inodecache();

146///注册文件系统到内核.

147register_filesystem(&

sock_fs_type);

148///安装mount点.

149sock_mnt=kern_mount(&

150

151#ifdefCONFIG_NETFILTER

152netfilter_init();

153#endif

154return0;

155}

我们知道每次创建一个socket,都是要依赖于当前的protocolfamily类型的(后面会分析sys_socket的源码的时候会看到).而在内核中,每种类型的protocolfamily都会有一个相对应的net_proto_family结构,然后将这个结构注册到内核的net_families数组中,这样我们创建socket的时候,就可以调用这个数组来创建socket.

我们先来看sock_register的源码,也就是如何将一个net_proto_family注册到相应的数组:

156staticconststructnet_proto_family*net_families[NPROTO]__read_mostly;

157

158intsock_register(conststructnet_proto_family*ops)

159{

160interr;

161

162if(ops->

family>

=NPROTO){

163printk(KERN_CRIT"

protocol%d>

=NPROTO(%d)\n"

ops->

family,

164NPROTO);

165return-ENOBUFS;

166}

167

168spin_lock(&

net_family_lock);

169///代码非常简单,就是根据类型,然后放到相应的位置.

170if(net_families[ops->

family])

171err=-EEXIST;

172else{

173net_families[ops->

family]=ops;

174err=0;

175}

176spin_unlock(&

177

178printk(KERN_INFO"

NET:

Registeredprotocolfamily%d\n"

family);

179returnerr;

180}

我们知道每个协议簇和相应的套接口都对应有好多种组合,因此在协议簇的实现中保存了一个相应的结构来保存这些组合,然后后面就首先通过family然后确定到某个结构,再根据套接口的类型来得到这个结构,并赋值给sock.

这里要注意我们只分析af_inet的实现,其他的协议簇都差不多:

我们来看这个的实现:

181///可以看到这是一个数组,每个元素都是一个链表,也就是每种类型的socket就是一个链表.而这个链表所包含的是不同4层协议的inetsw.可是在inet中,现在每种类型的socket只对应一个4层协议.这里只是为了以后扩展.

182staticstructlist_headinetsw[SOCK_MAX];

183

184///相应的socket的对应的信息的结构.

185structinet_protosw{

186structlist_headlist;

187

188///需要这两个key才能定位一个inet_protosw.

189unsignedshorttype;

/*Thisisthe2ndargumenttosocket

(2).*/

190unsignedshortprotocol;

/*ThisistheL4protocolnumber.*/

191

192///相应的基于ipv4的4层协议的操作集合.

193structproto*prot;

194///相应的协议簇的操作信息.

195conststructproto_ops*ops;

196

197intcapability;

/*Which(ifany)capabilitydo

198*weneedtousethissocket

199*interface?

200*/

201charno_check;

/*checksumonrcv/xmit/none?

*/

202unsignedcharflags;

/*SeeINET_PROTOSW_*below.*/

203};

204

205voidinet_register_protosw(structinet_protosw*p)

206{

207structlist_head*lh;

208structinet_protosw*answer;

209intprotocol=p->

protocol;

210structlist_head*last_perm;

211.............................................

212answer=NULL;

213last_perm=&

inetsw[p->

type];

214///这个操作也很简单,就是将inet_protosw根据套接口类型插入到全局链表数组.

215list_for_each(lh,&

type]){

216answer=list_entry(lh,structinet_protosw,list);

217

218/*Checkonlythenon-wildmatch.*/

219if(INET_PROTOSW_PERMANENT&

answer->

flags){

220if(protocol==answer->

protocol)

221break;

222last_perm=lh;

223}

224

225answer=NULL;

226}

227if(answer)

228gotoout_permanent;

229///插入链表.

230list_add_rcu(&

p->

list,last_perm);

231..............................

接下来来分析inet_init的源码.

232///表示了所有的可能的当前协议簇和套接口类型的组合.

233staticstructinet_protoswinetsw_array[]=

234{

235{

236.type=SOCK_STREAM,

237.protocol=IPPROTO_TCP,

238.prot=&

tcp_prot,

239.ops=&

inet_stream_ops,

240.capability=-1,

241.no_check=0,

242.flags=INET_PROTOSW_PERMANENT|

243INET_PROTOSW_ICSK,

244},

245

246{

247.type=SOCK_DGRAM,

248.protocol=IPPROTO_UDP,

249.prot=&

udp_prot,

250.ops=&

inet_dgram_ops,

251.capability=-1,

252.no_check=UDP_CSUM_DEFAULT,

253.flags=INET_PROTOSW_PERMANENT,

254},

255

256

257{

258.type=SOCK_RAW,

259.protocol=IPPROTO_IP,/*wildcard*/

260.prot=&

raw_prot,

261.ops=&

inet_sockraw_ops,

262.capability=CAP_NET_RAW,

263.no_check=UDP_CSUM_DEFAULT,

264.flags=INET_PROTOSW_REUSE,

265}

266};

267

268///协议簇的创建函数.

269staticstructnet_proto_familyinet_family_ops={

270.family=PF_INET,

271.create=inet_create,

272.owner=THIS_MODULE,

273};

274

275staticint__initinet_init(void)

276{

277.............................................

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 图表模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1