socket 在linux 上的实现

socket 在linux 上的实现这样对于用户空间的一组 socket 函数 实际上只用到了 socketcall 一个系统调用 通过不同的参数来进行区分 而进入内核中的实现则可发现 对于不同的参数 由 switch case 中不同的 case 再分别进入不同的内核函数

大家好,欢迎来到IT知识分享网。

头文件包含是<sys/socket.h> 你没有在/usr/include下找到是因为不在这个目录下,而是在 /usr/include/i38-linux-gnu/sys低下(我ubuntu 13.10) 或者你可以直接用 find / -name sys 查找所有的 sys目录,就一目了然 谢谢2014-12-31孙socket函数是由glibc提供的,可以在glibc 源代码的include/sys/socket.h文件中找到上述socket函数的声明,这些函数的真正实现比较难找,对于x86体系来说,相关源文件在sysdeps/unix/sysv/linux/i386/socket.S,这是用汇编实现的,用来从用户空间进入名为socketcall的系统调用,并传递参数,下面是相关汇编代码: .globl __socket ENTRY (__socket) #if defined NEED_CANCELLATION && defined CENABLE SINGLE_THREAD_P jne 1f #endif /* Save registers. */ movl %ebx, %edx cfi_register (3, 2) movl $SYS_ify(socketcall), %eax /* System call number in %eax. */ /* Use so `socket’ is a separate token that might be #define’d. */ movl $P(SOCKOP_,socket), %ebx /* Subcode is first arg to syscall. */ lea 4(%esp), %ecx /* Address of args is 2nd arg. */ /* Do the system call trap. */ ENTER_KERNEL /* Restore registers. */ movl %edx, %ebx cfi_restore (3) /* %eax is < 0 if there was an error. */ cmpl $-125, %eax jae SYSCALL_ERROR_LABEL /* Successful; return the syscall’s value. */ L(pseudo_end): ret 注意上面所用的汇编代码采用的是AT&T格式(通常学校所教的是Intel汇编),这是Linux中对x86体系常用的汇编格式。glibc中一般直接采用这种汇编代码来进入内核访问系统调用,而不是_syscalln()格式的宏。 上面代码的作用是进入内核来访问名为socketcall的系统调用,在内核代码中,socketcall系统调用的对应代码在net/socket.c文件中。下面的代码取自Linux内核版本2.26.11: asmlinkage long sys_socketcall(int call, unsigned long __user *args) { unsigned long a[6]; unsigned long a0,a1; int err; if(call<1||call>SYS_RECVMSG) return -EINVAL; /* copy_from_user should be SMP safe. */ if (copy_from_user(a, args, nargs[call])) return -EFAULT; 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_ACCEPT: err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_GETSOCKNAME: err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_GETPEERNAME: err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]); 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; case SYS_SENDTO: err = sys_sendto(a0,(void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], a[5]); break; case SYS_RECV: err = sys_recv(a0, (void __user *)a1, a[2], a[3]); break; case SYS_RECVFROM: err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], (struct sockaddr __user *)a[4], (int __user *)a[5]); break; case SYS_SHUTDOWN: err = sys_shutdown(a0,a1); break; case SYS_SETSOCKOPT: err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); break; case SYS_GETSOCKOPT: err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]); break; case SYS_SENDMSG: err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]); break; case SYS_RECVMSG: err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]); break; default: err = -EINVAL; break; } return err; } 上面的switch/case对应前面socket函数组中的各个函数。这样对于用户空间的一组socket函数,实际上只用到了socketcall一个系统调用,通过不同的参数来进行区分,而进入内核中的实现则可发现,对于不同的参数,由switch/case中不同的case再分别进入不同的内核函数。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/162146.html

(0)
上一篇 2024-12-13 16:15
下一篇 2024-12-13 16:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信