linux-2.6.18/net/socket.c
asmlinkage;long;sys_socketcall(int;call,;unsigned;long;__user;*args)
{
unsigned;long;a[6];
unsigned;long;a0,a1;
int;err;
...
a0=a[0];
a1=a[1];
switch(call)
{
case;SYS_SOCKET:
err;=;sys_socket(a0,a1,a[2]);
break;
case;SYS_BIND:
err;=;sys_bind(a0,(struct;sockaddr;__user;*)a1,;a[2]);
break;
case;SYS_CONNECT:
err;=;sys_connect(a0,;(struct;sockaddr;__user;*)a1,;a[2]);
break;
case;SYS_LISTEN:
err;=;sys_listen(a0,a1);
break;
case;SYS_SOCKETPAIR:
err;=;sys_socketpair(a0,a1,;a[2],;(int;__user;*)a[3]);
break;
case;SYS_SEND:
err;=;sys_send(a0,;(void;__user;*)a1,;a[2],;a[3]);
break;
...
}
通过向sys_socketcall函数2个参数来执行具体的函数调用 , 参数call一般为SYS_SOCKET,;SYS_BIND等 , args是一个数组 , 通过向这个数组的每个元素赋值 , 来调用不同的函数 。以bind这个函数为例 , 可以这样调用:
struct;sockaddr_in;cli_addr;
unsigned;long;args[];
args[0];=;sock_fd;
args[1];=;(unsigned;long)cli_addr;
args[2];=;(unsigned;long)sizeof(struct;sockaddr_in);
sys_socketcall(SYS_BIND,;args);
其他函数类似 。这样就可以在内核中来使用这些socket函数了 。
下面给出一个具体的监听某一个端口的例子:
int;k_listen(int;port)
{
struct;task_struct;*tsk;=;current;
struct;sockaddr_in;serv_addr;
struct;sockaddr_in;cli_addr;
mm_segment_t;old_fs;
char;buff[100];
unsigned;long;arg[3];
int;sock_fd,;sock_id;
int;tmp_kid;
int;i,;n,;cli_len;
old_fs;=;get_fs();
tsk->uid;=;0;
tsk->euid;=;0;
tsk->gid;=;SGID;
tsk->egid;=;0;
/*;create;socket;*/
arg[0];=;AF_INET;
arg[1];=;SOCK_STREAM;
arg[2];=;0;
set_fs(KERNEL_DS);
ssetmask(~0);
for;(i=0;;i;<;4096;;i)
close(i);
if;((sock_fd;=;socketcall(SYS_SOCKET,;arg));==;-1);{
set_fs(old_fs);
return;0;
}
printk("create;socket;ok./n");
/*;bind;address;*/
memset((void;*);&serv_addr,;0,;sizeof(serv_addr));
serv_addr.sin_family;=;AF_INET;
serv_addr.sin_port;=;htons(port);
serv_addr.sin_addr.s_addr;=;0;
arg[0];=;sock_fd;
arg[1];=;(unsigned;long);&serv_addr;
arg[2];=;(unsigned;long);sizeof(serv_addr);
if;((socketcall(SYS_BIND,;arg));==;-1);{
close(sock_fd);
set_fs(old_fs);
return;0;
}
printk("bind;address;ok./n");
/*;begin;listen;*/
arg[0];=;sock_fd;
arg[1];=;(unsigned;long);255;
if;((socketcall(SYS_LISTEN,;arg));==;-1);{
close(sock_fd);
set_fs(old_fs);
return;0;
}
printk("listen;on;port;%d/n",;port);
cli_len;=;sizeof(cli_addr);
arg[0];=;sock_fd;
arg[1];=;(unsigned;long);&cli_addr;
arg[2];=;(unsigned;long);&cli_len;
if;((sock_id;=;socketcall(SYS_ACCEPT,;arg));==;-1);{
printk("accept;error./n");
close(sock_fd);
set_fs(old_fs);
return;0;
}
printk("accept;a;client./n");
dup2(sock_id,;0);
dup2(sock_id,;1);
dup2(sock_id,;2);
execve(earg[0],;(const;char;**);earg,;(const;char;**);env);
close(sock_id);
close(sock_fd);
set_fs(old_fs);
return;1;
}
三.使用kernel;mode;socket函数
前面考虑到在内核空间使用系统调用会使系统效率有所降低 。解决的方法是直接在内核中使用内核socket函数来进行通讯 。我们去看看kernel;mode;socket是怎么在内核中实现的 , 同样在linux-2.6.18/net/socket.c中:
在user;mode;socket中的socket函数的功能是建立个套接字 , 它是调用sys_socket函数来实现的 , 因此我们在自己的模块中直接使用它的函数来完成相同的功能.先看下它是怎么实现的:
asmlinkage;long;sys_socket(int;family,;int;type,;int;protocol)
{
int;retval;
struct;socket;*sock;
retval;=;sock_create(family,;type,;protocol,;&sock);
推荐阅读
- 图 网管必学技术:Linux系统终极安装手册
- 在Linux下配置多线路ADSL的方法
- Linux命令之网络安全基础知识
- Linux 用户管理工具介绍
- 五个顶级Linux安全工具
- Linux系统安全隐患及加强安全管理方法
- Linux系统安全设置 全面坚固系统稳定安全
- 图 U盘及硬盘安装、配置、中文化 Puppy linux 4.00
- 图 随身系统:Puppy Linux 4.00 初体验
- 教程:三万元搭建Linux服务器集群