linux内核中的文件描述符(二)--socket和文件描述符
来源:互联网 发布:java httpclient 保持 编辑:程序博客网 时间:2024/05/29 13:14
linux内核中的文件描述符(二)--socket和文件描述符
Kernel version:2.6.14
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
socket和文件系统紧密相关,我们可以通过文件系统的open、read、write和close等操作socket。下面是一个简单的例子。
/****************************************************************************//*简介:TCPServer示例 *//****************************************************************************/#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> int main(int argc, char *argv[]) { int sockfd,new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size,portnumber; const char hello[]="Hello\n"; if(argc!=2) { fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); } if((portnumber=atoi(argv[1]))<0) { fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); } /* 服务器端开始建立socket描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1); } /* 服务器端填充 sockaddr结构 */ bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); /* 捆绑sockfd描述符 */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))== -1) { fprintf(stderr,"Bind error:%s\n\a",strerror(errno)); exit(1); } /* 监听sockfd描述符 */ if(listen(sockfd,5)==-1) { fprintf(stderr,"Listen error:%s\n\a",strerror(errno)); exit(1); } while(1) { /* 服务器阻塞,直到客户程序建立连接 */ sin_size=sizeof(struct sockaddr_in); if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1) { fprintf(stderr,"Accept error:%s\n\a",strerror(errno)); exit(1); } fprintf(stderr,"Server get connection from %s\n", inet_ntoa(client_addr.sin_addr)); if(write(new_fd,hello,strlen(hello))==-1) { fprintf(stderr,"Write Error:%s\n",strerror(errno)); exit(1); } /* 这个通讯已经结束 */ close(new_fd); /* 循环下一个 */ } close(sockfd); exit(0); }
下图说明了socket和fd是怎样联系起来的。
下面通过来具体分析一下。sys_socket是socket相关函数的总入口。
net/socket.c/* *System call vectors. * *Argument checking cleaned up. Saved 20% in size. * This function doesn't need to set the kernel lock because * it is set by the callees. */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;err = audit_socketcall(nargs[call]/sizeof(unsigned long), a);if (err)return 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_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;}/* It may be already another descriptor 8) Not kernel problem. */return retval;out_release:sock_release(sock);return retval;}当应用程序使用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);//创建socketif (retval < 0)goto out;retval = sock_map_fd(sock);//分配一个未使用的文件描述符fd,并将socket和fd建立联系if (retval < 0)goto out_release;out:/* It may be already another descriptor 8) Not kernel problem. */return retval;out_release:sock_release(sock);return retval;}结构体socket的定义如下(include\linux\net.h):
struct socket {socket_statestate;unsigned longflags;struct proto_ops*ops;struct fasync_struct*fasync_list;struct file*file;//通过这个和文件描述符建立联系struct sock*sk;wait_queue_head_twait;shorttype;};下面我们再来看看sock_map_fd函数
int sock_map_fd(struct socket *sock){int fd;struct qstr this;char name[32];/* *Find a file descriptor suitable for return to the user. */fd = get_unused_fd();//分配一个未使用的fdif (fd >= 0) {struct file *file = get_empty_filp();if (!file) {put_unused_fd(fd);fd = -ENFILE;goto out;}this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);this.name = name;this.hash = SOCK_INODE(sock)->i_ino;file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);if (!file->f_dentry) {put_filp(file);put_unused_fd(fd);fd = -ENOMEM;goto out;}file->f_dentry->d_op = &sockfs_dentry_operations;d_add(file->f_dentry, SOCK_INODE(sock));file->f_vfsmnt = mntget(sock_mnt);file->f_mapping = file->f_dentry->d_inode->i_mapping;sock->file = file;//建立联系file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;//socket操作函数,当使用文件系统的IO函数时,其实使用的是socket的IO函数file->f_mode = FMODE_READ | FMODE_WRITE;file->f_flags = O_RDWR;file->f_pos = 0;file->private_data = sock;fd_install(fd, file);}out:return fd;}static struct file_operations socket_file_ops = {.owner =THIS_MODULE,.llseek =no_llseek,.aio_read =sock_aio_read,.aio_write =sock_aio_write,.poll =sock_poll,.unlocked_ioctl = sock_ioctl,.mmap =sock_mmap,.open =sock_no_open,/* special open code to disallow open via /proc */.release =sock_close,.fasync =sock_fasync,.readv =sock_readv,.writev =sock_writev,.sendpage =sock_sendpage};
- linux内核中的文件描述符(二)--socket和文件描述符
- Linux文件描述符和文件指针
- Linux 文件描述符和文件锁
- 【Linux】---文件描述符和文件指针
- Linux文件描述符表和文件的关系
- Linux下的文件流和文件描述符
- 文件描述符和文件指针区别
- 文件指针和文件描述符
- 文件指针和文件描述符
- 文件描述符和文件指针
- Perl文件句柄和文件描述符
- 文件描述符和文件指针
- 文件描述符和文件指针
- 辨析文件描述符和文件指针
- 文件描述符和文件指针
- 文件描述符和文件描述符表
- Linux内核中的文件描述符
- Linux下文件描述符和文件流的转换
- 无路可逃?(图的DFS)
- 有向图边的分类
- 《权力》读书笔记,第9章 挫折也是一种财富
- 找中位数(用堆维持小的一半数,建立大根堆)
- 由jdveloper运行不起的解决办法 <Received exception while creating connection for pool "Connection1": ORA-01033:
- linux内核中的文件描述符(二)--socket和文件描述符
- 《权力》读书笔记,第12章 大胆地去竞逐权力吧
- BBED模拟数据块不一致
- 【转载】《敏捷软件测试:测试人员与敏捷团队的实践指南》一书思维图
- HDU 2795
- 混迹C++ 之构造器和析构器
- JavaScript专题——专题三 JavaScript 面向对象
- codeforces 219A
- 网络抓包工具抓取本地环回接口127.0.0.1的数据包